4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
214 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
218 count = gst_tag_list_get_tag_size(list, tag);
220 LOGD("count = %d", count);
222 for (i = 0; i < count; i++) {
225 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
226 if (!gst_tag_list_get_string_index(list, tag, i, &str))
227 g_assert_not_reached();
229 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
233 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
235 g_print(" : %s", str);
242 /* This function should be called after the pipeline goes PAUSED or higher
245 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
247 static gboolean has_duration = FALSE;
248 static gboolean has_video_attrs = FALSE;
249 static gboolean has_audio_attrs = FALSE;
250 static gboolean has_bitrate = FALSE;
251 gboolean missing_only = FALSE;
252 gboolean all = FALSE;
253 MMHandleType attrs = 0;
257 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
259 /* check player state here */
260 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
261 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
262 /* give warning now only */
263 LOGW("be careful. content attributes may not available in this state ");
266 /* get content attribute first */
267 attrs = MMPLAYER_GET_ATTRS(player);
269 LOGE("cannot get content attribute");
273 /* get update flag */
275 if (flag & ATTR_MISSING_ONLY) {
277 LOGD("updating missed attr only");
280 if (flag & ATTR_ALL) {
282 has_duration = FALSE;
283 has_video_attrs = FALSE;
284 has_audio_attrs = FALSE;
287 LOGD("updating all attrs");
290 if (missing_only && all) {
291 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
292 missing_only = FALSE;
295 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
296 has_duration = __mmplayer_update_duration_value(player);
298 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
299 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
301 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
302 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
304 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
305 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
308 if (mm_attrs_commit_all(attrs)) {
309 LOGE("failed to update attributes");
319 _mmplayer_get_stream_service_type(mmplayer_t *player)
321 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
325 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
327 player->pipeline->mainbin &&
328 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
329 STREAMING_SERVICE_NONE);
331 /* streaming service type if streaming */
332 if (!MMPLAYER_IS_STREAMING(player))
333 return STREAMING_SERVICE_NONE;
335 streaming_type = (player->duration == 0) ?
336 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
338 switch (streaming_type) {
339 case STREAMING_SERVICE_LIVE:
340 LOGD("it's live streaming");
342 case STREAMING_SERVICE_VOD:
343 LOGD("it's vod streaming");
346 LOGE("should not get here");
352 return streaming_type;
355 /* this function sets the player state and also report
356 * it to applicaton by calling callback function
359 _mmplayer_set_state(mmplayer_t *player, int state)
361 MMMessageParamType msg = {0, };
363 MMPLAYER_RETURN_IF_FAIL(player);
365 if (MMPLAYER_CURRENT_STATE(player) == state) {
366 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
367 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
371 /* update player states */
372 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
373 MMPLAYER_CURRENT_STATE(player) = state;
375 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
376 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
379 MMPLAYER_PRINT_STATE(player);
381 switch (MMPLAYER_CURRENT_STATE(player)) {
382 case MM_PLAYER_STATE_NULL:
383 case MM_PLAYER_STATE_READY:
385 case MM_PLAYER_STATE_PAUSED:
386 __mmplayer_set_pause_state(player);
388 case MM_PLAYER_STATE_PLAYING:
389 __mmplayer_set_playing_state(player);
391 case MM_PLAYER_STATE_NONE:
393 LOGW("invalid target state, there is nothing to do.");
398 /* post message to application */
399 if (MMPLAYER_TARGET_STATE(player) == state) {
400 /* fill the message with state of player */
401 msg.union_type = MM_MSG_UNION_STATE;
402 msg.state.previous = MMPLAYER_PREV_STATE(player);
403 msg.state.current = MMPLAYER_CURRENT_STATE(player);
405 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
407 /* state changed by resource callback */
408 if (player->interrupted_by_resource)
409 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
410 else /* state changed by usecase */
411 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
414 LOGD("intermediate state, do nothing.");
415 MMPLAYER_PRINT_STATE(player);
419 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
420 && !player->sent_bos) {
421 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
422 player->sent_bos = TRUE;
429 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
431 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
432 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
434 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
436 //LOGD("incomming command : %d ", command);
438 current_state = MMPLAYER_CURRENT_STATE(player);
439 pending_state = MMPLAYER_PENDING_STATE(player);
441 MMPLAYER_PRINT_STATE(player);
444 case MMPLAYER_COMMAND_CREATE:
446 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
448 if (current_state == MM_PLAYER_STATE_NULL ||
449 current_state == MM_PLAYER_STATE_READY ||
450 current_state == MM_PLAYER_STATE_PAUSED ||
451 current_state == MM_PLAYER_STATE_PLAYING)
456 case MMPLAYER_COMMAND_DESTROY:
458 /* destroy can called anytime */
460 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
464 case MMPLAYER_COMMAND_REALIZE:
466 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
468 if (pending_state != MM_PLAYER_STATE_NONE) {
471 /* need ready state to realize */
472 if (current_state == MM_PLAYER_STATE_READY)
475 if (current_state != MM_PLAYER_STATE_NULL)
481 case MMPLAYER_COMMAND_UNREALIZE:
483 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
485 if (current_state == MM_PLAYER_STATE_NULL)
490 case MMPLAYER_COMMAND_START:
492 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
494 if (pending_state == MM_PLAYER_STATE_NONE) {
495 if (current_state == MM_PLAYER_STATE_PLAYING)
497 else if (current_state != MM_PLAYER_STATE_READY &&
498 current_state != MM_PLAYER_STATE_PAUSED)
500 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
502 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
503 LOGD("player is going to paused state, just change the pending state as playing");
510 case MMPLAYER_COMMAND_STOP:
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
514 if (current_state == MM_PLAYER_STATE_READY)
517 /* need playing/paused state to stop */
518 if (current_state != MM_PLAYER_STATE_PLAYING &&
519 current_state != MM_PLAYER_STATE_PAUSED)
524 case MMPLAYER_COMMAND_PAUSE:
526 if (MMPLAYER_IS_LIVE_STREAMING(player))
529 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
530 goto NOT_COMPLETED_SEEK;
532 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
534 if (pending_state == MM_PLAYER_STATE_NONE) {
535 if (current_state == MM_PLAYER_STATE_PAUSED)
537 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
539 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
541 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
542 if (current_state == MM_PLAYER_STATE_PAUSED)
543 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
550 case MMPLAYER_COMMAND_RESUME:
552 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
553 goto NOT_COMPLETED_SEEK;
555 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
557 if (pending_state == MM_PLAYER_STATE_NONE) {
558 if (current_state == MM_PLAYER_STATE_PLAYING)
560 else if (current_state != MM_PLAYER_STATE_PAUSED)
562 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
564 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
565 LOGD("player is going to paused state, just change the pending state as playing");
575 player->cmd = command;
577 return MM_ERROR_NONE;
580 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
581 MMPLAYER_STATE_GET_NAME(current_state), command);
582 return MM_ERROR_PLAYER_INVALID_STATE;
585 LOGW("not completed seek");
586 return MM_ERROR_PLAYER_DOING_SEEK;
589 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
590 return MM_ERROR_PLAYER_NO_OP;
593 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
594 return MM_ERROR_PLAYER_NO_OP;
597 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
599 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
600 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
603 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
604 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
606 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
607 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
610 LOGE("invalid mmplayer resource type %d", type);
611 return MM_ERROR_PLAYER_INTERNAL;
614 if (player->hw_resource[type] != NULL) {
615 LOGD("[%d type] resource was already acquired", type);
616 return MM_ERROR_NONE;
619 LOGD("mark for acquire [%d type] resource", type);
620 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
621 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
622 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
623 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
624 return MM_ERROR_PLAYER_INTERNAL;
627 rm_ret = mm_resource_manager_commit(player->resource_manager);
628 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
629 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
630 return MM_ERROR_PLAYER_INTERNAL;
634 return MM_ERROR_NONE;
637 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
639 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
643 if (player->hw_resource[type] == NULL) {
644 LOGD("there is no acquired [%d type] resource", type);
645 return MM_ERROR_NONE;
648 LOGD("mark for release [%d type] resource", type);
649 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
650 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
651 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
652 return MM_ERROR_PLAYER_INTERNAL;
655 player->hw_resource[type] = NULL;
657 rm_ret = mm_resource_manager_commit(player->resource_manager);
658 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
659 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
660 return MM_ERROR_PLAYER_INTERNAL;
664 return MM_ERROR_NONE;
668 __mmplayer_initialize_gapless_play(mmplayer_t *player)
674 player->smooth_streaming = FALSE;
675 player->videodec_linked = 0;
676 player->audiodec_linked = 0;
677 player->textsink_linked = 0;
678 player->is_external_subtitle_present = FALSE;
679 player->is_external_subtitle_added_now = FALSE;
680 player->not_supported_codec = MISSING_PLUGIN_NONE;
681 player->can_support_codec = FOUND_PLUGIN_NONE;
682 player->pending_seek.is_pending = false;
683 player->pending_seek.pos = 0;
684 player->msg_posted = FALSE;
685 player->has_many_types = FALSE;
686 player->no_more_pad = FALSE;
687 player->not_found_demuxer = 0;
688 player->seek_state = MMPLAYER_SEEK_NONE;
689 player->is_subtitle_force_drop = FALSE;
690 player->play_subtitle = FALSE;
691 player->adjust_subtitle_pos = 0;
693 player->total_bitrate = 0;
694 player->total_maximum_bitrate = 0;
696 _mmplayer_track_initialize(player);
697 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
699 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
700 player->bitrate[i] = 0;
701 player->maximum_bitrate[i] = 0;
704 if (player->v_stream_caps) {
705 gst_caps_unref(player->v_stream_caps);
706 player->v_stream_caps = NULL;
709 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
711 /* clean found audio decoders */
712 if (player->audio_decoders) {
713 GList *a_dec = player->audio_decoders;
714 for (; a_dec; a_dec = g_list_next(a_dec)) {
715 gchar *name = a_dec->data;
716 MMPLAYER_FREEIF(name);
718 g_list_free(player->audio_decoders);
719 player->audio_decoders = NULL;
722 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
728 __mmplayer_gapless_play_thread(gpointer data)
730 mmplayer_t *player = (mmplayer_t *)data;
731 mmplayer_gst_element_t *mainbin = NULL;
733 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
735 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
736 while (!player->gapless_play_thread_exit) {
737 LOGD("gapless play thread started. waiting for signal.");
738 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
740 LOGD("reconfigure pipeline for gapless play.");
742 if (player->gapless_play_thread_exit) {
743 if (player->gapless.reconfigure) {
744 player->gapless.reconfigure = false;
745 MMPLAYER_PLAYBACK_UNLOCK(player);
747 LOGD("exiting gapless play thread");
751 mainbin = player->pipeline->mainbin;
753 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
754 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
755 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
756 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
757 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
759 /* Initialize Player values */
760 __mmplayer_initialize_gapless_play(player);
762 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
764 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
770 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
772 GSource *source = NULL;
776 source = g_main_context_find_source_by_id(context, source_id);
777 if (source != NULL) {
778 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
779 g_source_destroy(source);
786 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
788 mmplayer_t *player = (mmplayer_t *)hplayer;
789 GstMessage *msg = NULL;
790 GQueue *queue = NULL;
793 MMPLAYER_RETURN_IF_FAIL(player);
795 /* disconnecting bus watch */
796 if (player->bus_watcher)
797 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
798 player->bus_watcher = 0;
800 /* destroy the gst bus msg thread */
801 if (player->bus_msg_thread) {
802 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
803 player->bus_msg_thread_exit = TRUE;
804 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
805 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
807 LOGD("gst bus msg thread exit.");
808 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
809 player->bus_msg_thread = NULL;
811 g_mutex_clear(&player->bus_msg_thread_mutex);
812 g_cond_clear(&player->bus_msg_thread_cond);
815 g_mutex_lock(&player->bus_msg_q_lock);
816 queue = player->bus_msg_q;
817 while (!g_queue_is_empty(queue)) {
818 msg = (GstMessage *)g_queue_pop_head(queue);
823 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
824 gst_message_unref(msg);
826 g_mutex_unlock(&player->bus_msg_q_lock);
832 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
834 GstElement *parent = NULL;
836 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
837 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
840 MMPLAYER_FSINK_LOCK(player);
842 /* get parent of fakesink */
843 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
845 LOGD("fakesink already removed");
849 gst_element_set_locked_state(fakesink->gst, TRUE);
851 /* setting the state to NULL never returns async
852 * so no need to wait for completion of state transiton
854 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
855 LOGE("fakesink state change failure!");
856 /* FIXIT : should I return here? or try to proceed to next? */
859 /* remove fakesink from it's parent */
860 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
861 LOGE("failed to remove fakesink");
863 gst_object_unref(parent);
868 gst_object_unref(parent);
870 LOGD("state-holder removed");
872 gst_element_set_locked_state(fakesink->gst, FALSE);
874 MMPLAYER_FSINK_UNLOCK(player);
879 gst_element_set_locked_state(fakesink->gst, FALSE);
881 MMPLAYER_FSINK_UNLOCK(player);
885 static GstPadProbeReturn
886 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
888 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
889 return GST_PAD_PROBE_OK;
893 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
895 gint64 stop_running_time = 0;
896 gint64 position_running_time = 0;
900 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
901 if ((player->gapless.update_segment[idx] == TRUE) ||
902 !(player->selector[idx].event_probe_id)) {
903 /* LOGW("[%d] skip", idx); */
907 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
909 gst_segment_to_running_time(&player->gapless.segment[idx],
910 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
911 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
913 gst_segment_to_running_time(&player->gapless.segment[idx],
914 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
916 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
918 gst_segment_to_running_time(&player->gapless.segment[idx],
919 GST_FORMAT_TIME, player->duration);
922 position_running_time =
923 gst_segment_to_running_time(&player->gapless.segment[idx],
924 GST_FORMAT_TIME, player->gapless.segment[idx].position);
926 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
927 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
929 GST_TIME_ARGS(stop_running_time),
930 GST_TIME_ARGS(position_running_time),
931 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
932 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
934 position_running_time = MAX(position_running_time, stop_running_time);
935 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
936 GST_FORMAT_TIME, player->gapless.segment[idx].start);
937 position_running_time = MAX(0, position_running_time);
938 position = MAX(position, position_running_time);
942 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
943 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
944 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
946 player->gapless.start_time[stream_type] += position;
952 static GstPadProbeReturn
953 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
955 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
956 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
957 mmplayer_t *player = (mmplayer_t *)data;
958 GstCaps *caps = NULL;
959 GstStructure *str = NULL;
960 const gchar *name = NULL;
961 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
962 gboolean caps_ret = TRUE;
964 if (GST_EVENT_IS_DOWNSTREAM(event) &&
965 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
966 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
967 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
968 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
970 } else if (GST_EVENT_IS_UPSTREAM(event) &&
971 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
975 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
979 if (strstr(name, "audio")) {
980 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
981 } else if (strstr(name, "video")) {
982 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
984 /* text track is not supportable */
985 LOGE("invalid name %s", name);
989 switch (GST_EVENT_TYPE(event)) {
992 /* in case of gapless, drop eos event not to send it to sink */
993 if (player->gapless.reconfigure && !player->msg_posted) {
994 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
995 ret = GST_PAD_PROBE_DROP;
999 case GST_EVENT_STREAM_START:
1001 __mmplayer_gst_selector_update_start_time(player, stream_type);
1004 case GST_EVENT_FLUSH_STOP:
1006 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1007 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1008 player->gapless.start_time[stream_type] = 0;
1011 case GST_EVENT_SEGMENT:
1016 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1017 gst_event_copy_segment(event, &segment);
1019 if (segment.format != GST_FORMAT_TIME)
1022 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1023 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1024 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1025 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1026 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1027 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1029 /* keep the all the segment ev to cover the seeking */
1030 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1031 player->gapless.update_segment[stream_type] = TRUE;
1033 if (!player->gapless.running)
1036 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1038 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1040 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1041 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1042 gst_event_unref(event);
1043 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1049 gdouble proportion = 0.0;
1050 GstClockTimeDiff diff = 0;
1051 GstClockTime timestamp = 0;
1052 gint64 running_time_diff = -1;
1053 GstQOSType type = 0;
1054 GstEvent *tmpev = NULL;
1056 running_time_diff = player->gapless.segment[stream_type].base;
1058 if (running_time_diff <= 0) /* don't need to adjust */
1061 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1062 gst_event_unref(event);
1064 if (timestamp < running_time_diff) {
1065 LOGW("QOS event from previous group");
1066 ret = GST_PAD_PROBE_DROP;
1070 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1071 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1072 stream_type, GST_TIME_ARGS(timestamp),
1073 GST_TIME_ARGS(running_time_diff),
1074 GST_TIME_ARGS(timestamp - running_time_diff));
1076 timestamp -= running_time_diff;
1078 /* That case is invalid for QoS events */
1079 if (diff < 0 && -diff > timestamp) {
1080 LOGW("QOS event from previous group");
1081 ret = GST_PAD_PROBE_DROP;
1085 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1086 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1096 gst_caps_unref(caps);
1100 /* create fakesink for audio or video path witout audiobin or videobin */
1102 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1104 GstElement *pipeline = NULL;
1105 GstElement *fakesink = NULL;
1106 GstPad *sinkpad = NULL;
1109 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1111 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1114 fakesink = gst_element_factory_make("fakesink", NULL);
1115 if (fakesink == NULL) {
1116 LOGE("failed to create fakesink");
1120 /* store it as it's sink element */
1121 __mmplayer_add_sink(player, fakesink);
1123 gst_bin_add(GST_BIN(pipeline), fakesink);
1126 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1128 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1130 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1131 LOGE("failed to link fakesink");
1132 gst_object_unref(GST_OBJECT(fakesink));
1136 if (strstr(name, "video")) {
1137 if (player->v_stream_caps) {
1138 gst_caps_unref(player->v_stream_caps);
1139 player->v_stream_caps = NULL;
1141 if (player->ini.set_dump_element_flag)
1142 __mmplayer_add_dump_buffer_probe(player, fakesink);
1145 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1146 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1150 gst_object_unref(GST_OBJECT(sinkpad));
1157 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1159 GstElement *pipeline = NULL;
1160 GstElement *selector = NULL;
1161 GstPad *srcpad = NULL;
1164 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1166 selector = gst_element_factory_make("input-selector", NULL);
1168 LOGE("failed to create input-selector");
1171 g_object_set(selector, "sync-streams", TRUE, NULL);
1173 player->pipeline->mainbin[elem_idx].id = elem_idx;
1174 player->pipeline->mainbin[elem_idx].gst = selector;
1176 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1178 srcpad = gst_element_get_static_pad(selector, "src");
1180 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1181 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1182 __mmplayer_gst_selector_blocked, NULL, NULL);
1183 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1184 __mmplayer_gst_selector_event_probe, player, NULL);
1186 gst_element_set_state(selector, GST_STATE_PAUSED);
1188 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1189 gst_bin_add(GST_BIN(pipeline), selector);
1191 gst_object_unref(GST_OBJECT(srcpad));
1198 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1200 mmplayer_t *player = (mmplayer_t *)data;
1201 GstElement *selector = NULL;
1202 GstCaps *caps = NULL;
1203 GstStructure *str = NULL;
1204 const gchar *name = NULL;
1205 GstPad *sinkpad = NULL;
1206 gboolean first_track = FALSE;
1207 gboolean caps_ret = TRUE;
1209 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1210 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1213 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1214 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1216 LOGD("pad-added signal handling");
1218 /* get mimetype from caps */
1219 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1223 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1224 /* LOGD("detected mimetype : %s", name); */
1226 if (strstr(name, "video")) {
1228 gchar *caps_str = NULL;
1230 caps_str = gst_caps_to_string(caps);
1231 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1232 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1233 player->set_mode.video_zc = true;
1235 MMPLAYER_FREEIF(caps_str);
1237 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1238 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1240 LOGD("surface type : %d", stype);
1242 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1243 __mmplayer_gst_create_sinkbin(elem, pad, player);
1247 /* in case of exporting video frame, it requires the 360 video filter.
1248 * it will be handled in _no_more_pads(). */
1249 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1250 __mmplayer_gst_make_fakesink(player, pad, name);
1254 LOGD("video selector is required");
1255 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1256 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1257 } else if (strstr(name, "audio")) {
1258 gint samplerate = 0;
1261 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1262 if (player->build_audio_offload)
1263 player->no_more_pad = TRUE; /* remove state holder */
1264 __mmplayer_gst_create_sinkbin(elem, pad, player);
1268 gst_structure_get_int(str, "rate", &samplerate);
1269 gst_structure_get_int(str, "channels", &channels);
1271 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1272 __mmplayer_gst_make_fakesink(player, pad, name);
1276 LOGD("audio selector is required");
1277 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1278 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1280 } else if (strstr(name, "text")) {
1281 LOGD("text selector is required");
1282 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1283 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1285 LOGE("invalid caps info");
1289 /* check selector and create it */
1290 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1291 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1296 LOGD("input-selector is already created.");
1300 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1302 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1304 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1305 LOGE("failed to link selector");
1306 gst_object_unref(GST_OBJECT(selector));
1311 LOGD("this track will be activated");
1312 g_object_set(selector, "active-pad", sinkpad, NULL);
1315 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1321 gst_caps_unref(caps);
1324 gst_object_unref(GST_OBJECT(sinkpad));
1332 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1334 GstPad *srcpad = NULL;
1337 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1339 LOGD("type %d", type);
1342 LOGD("there is no %d track", type);
1346 srcpad = gst_element_get_static_pad(selector, "src");
1348 LOGE("failed to get srcpad from selector");
1352 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1354 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1356 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1357 if (player->selector[type].block_id) {
1358 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1359 player->selector[type].block_id = 0;
1363 gst_object_unref(GST_OBJECT(srcpad));
1372 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1374 MMHandleType attrs = 0;
1375 gint active_index = 0;
1378 MMPLAYER_RETURN_IF_FAIL(player);
1380 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1382 /* change track to active pad */
1383 active_index = player->selector[type].active_pad_index;
1384 if ((active_index != DEFAULT_TRACK) &&
1385 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1386 LOGW("failed to change %d type track to %d", type, active_index);
1387 player->selector[type].active_pad_index = DEFAULT_TRACK;
1391 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1392 attrs = MMPLAYER_GET_ATTRS(player);
1394 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1395 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1397 if (mm_attrs_commit_all(attrs))
1398 LOGW("failed to commit attrs.");
1400 LOGW("cannot get content attribute");
1409 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1412 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1414 if (!audio_selector) {
1415 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1417 /* in case the source is changed, output can be changed. */
1418 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1419 LOGD("remove previous audiobin if it exist");
1421 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1422 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1424 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1425 MMPLAYER_FREEIF(player->pipeline->audiobin);
1428 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1429 __mmplayer_pipeline_complete(NULL, player);
1434 /* apply the audio track information */
1435 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1437 /* create audio sink path */
1438 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1439 LOGE("failed to create audio sink path");
1448 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1451 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1453 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1454 LOGD("text path is not supproted");
1458 /* apply the text track information */
1459 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1461 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1462 player->has_closed_caption = TRUE;
1464 /* create text decode path */
1465 player->no_more_pad = TRUE;
1467 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1468 LOGE("failed to create text sink path");
1477 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1479 gint64 dur_bytes = 0L;
1482 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1483 player->pipeline->mainbin && player->streamer, FALSE);
1485 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1486 LOGE("fail to get duration.");
1488 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1489 * use file information was already set on Q2 when it was created. */
1490 _mm_player_streaming_set_queue2(player->streamer,
1491 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1492 TRUE, /* use_buffering */
1493 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1494 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1501 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1503 mmplayer_t *player = NULL;
1504 GstElement *video_selector = NULL;
1505 GstElement *audio_selector = NULL;
1506 GstElement *text_selector = NULL;
1509 player = (mmplayer_t *)data;
1511 LOGD("no-more-pad signal handling");
1513 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1514 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1515 LOGW("player is shutting down");
1519 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1520 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1521 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1522 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1523 LOGE("failed to set queue2 buffering");
1528 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1529 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1530 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1532 if (!video_selector && !audio_selector && !text_selector) {
1533 LOGW("there is no selector");
1534 player->no_more_pad = TRUE;
1538 /* create video path followed by video-select */
1539 if (video_selector && !audio_selector && !text_selector)
1540 player->no_more_pad = TRUE;
1542 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1545 /* create audio path followed by audio-select */
1546 if (audio_selector && !text_selector)
1547 player->no_more_pad = TRUE;
1549 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1552 /* create text path followed by text-select */
1553 __mmplayer_create_text_sink_path(player, text_selector);
1556 if (player->gapless.reconfigure) {
1557 player->gapless.reconfigure = FALSE;
1558 MMPLAYER_PLAYBACK_UNLOCK(player);
1565 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1567 gboolean ret = FALSE;
1568 GstElement *pipeline = NULL;
1569 GstPad *sinkpad = NULL;
1572 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1573 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1575 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1577 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1579 LOGE("failed to get pad from sinkbin");
1585 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1586 LOGE("failed to link sinkbin for reusing");
1587 goto EXIT; /* exit either pass or fail */
1591 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1592 LOGE("failed to set state(READY) to sinkbin");
1597 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1598 LOGE("failed to add sinkbin to pipeline");
1603 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1604 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1609 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1610 LOGE("failed to set state(PAUSED) to sinkbin");
1619 gst_object_unref(GST_OBJECT(sinkpad));
1627 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1629 mmplayer_t *player = NULL;
1630 GstCaps *caps = NULL;
1631 gchar *caps_str = NULL;
1632 GstStructure *str = NULL;
1633 const gchar *name = NULL;
1634 GstElement *sinkbin = NULL;
1635 gboolean reusing = FALSE;
1636 gboolean caps_ret = TRUE;
1637 gchar *sink_pad_name = "sink";
1640 player = (mmplayer_t *)data;
1643 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1644 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1646 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1650 caps_str = gst_caps_to_string(caps);
1652 /* LOGD("detected mimetype : %s", name); */
1653 if (strstr(name, "audio")) {
1654 if (player->pipeline->audiobin == NULL) {
1655 const gchar *audio_format = gst_structure_get_string(str, "format");
1657 LOGD("original audio format %s", audio_format);
1658 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1661 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1662 LOGE("failed to create audiobin. continuing without audio");
1666 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1667 LOGD("creating audiobin success");
1670 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1671 LOGD("reusing audiobin");
1672 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1674 } else if (strstr(name, "video")) {
1675 /* 1. zero copy is updated at _decode_pad_added()
1676 * 2. NULL surface type is handled in _decode_pad_added() */
1677 LOGD("zero copy %d", player->set_mode.video_zc);
1678 if (player->pipeline->videobin == NULL) {
1679 int surface_type = 0;
1680 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1681 LOGD("display_surface_type (%d)", surface_type);
1683 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1684 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1685 LOGE("failed to acquire video overlay resource");
1689 player->interrupted_by_resource = FALSE;
1691 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1692 LOGE("failed to create videobin. continuing without video");
1696 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1697 LOGD("creating videosink bin success");
1700 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1701 LOGD("re-using videobin");
1702 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1704 } else if (strstr(name, "text")) {
1705 if (player->pipeline->textbin == NULL) {
1706 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1707 LOGE("failed to create text sink bin. continuing without text");
1711 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1712 player->textsink_linked = 1;
1713 LOGD("creating textsink bin success");
1715 if (!player->textsink_linked) {
1716 LOGD("re-using textbin");
1718 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1719 player->textsink_linked = 1;
1721 /* linked textbin exist which means that the external subtitle path exist already */
1722 LOGW("ignoring internal subtutle since external subtitle is available");
1725 sink_pad_name = "text_sink";
1727 LOGW("unknown mime type %s, ignoring it", name);
1731 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1734 LOGD("[handle: %p] success to create and link sink bin", player);
1736 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1737 * streaming task. if the task blocked, then buffer will not flow to the next element
1738 *(autoplugging element). so this is special hack for streaming. please try to remove it
1740 /* dec stream count. we can remove fakesink if it's zero */
1741 if (player->num_dynamic_pad)
1742 player->num_dynamic_pad--;
1744 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1746 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1747 __mmplayer_pipeline_complete(NULL, player);
1751 MMPLAYER_FREEIF(caps_str);
1754 gst_caps_unref(caps);
1760 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1762 int required_angle = 0; /* Angle required for straight view */
1763 int rotation_angle = 0;
1765 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1766 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1768 /* Counter clockwise */
1769 switch (orientation) {
1774 required_angle = 270;
1777 required_angle = 180;
1780 required_angle = 90;
1784 rotation_angle = display_angle + required_angle;
1785 if (rotation_angle >= 360)
1786 rotation_angle -= 360;
1788 /* chech if supported or not */
1789 if (rotation_angle % 90) {
1790 LOGD("not supported rotation angle = %d", rotation_angle);
1794 switch (rotation_angle) {
1796 *value = MM_DISPLAY_ROTATION_NONE;
1799 *value = MM_DISPLAY_ROTATION_90;
1802 *value = MM_DISPLAY_ROTATION_180;
1805 *value = MM_DISPLAY_ROTATION_270;
1809 LOGD("setting rotation property value : %d", *value);
1815 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1817 /* check video sinkbin is created */
1818 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1820 player->pipeline->videobin &&
1821 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1822 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1823 MM_ERROR_PLAYER_NOT_INITIALIZED);
1825 return MM_ERROR_NONE;
1829 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1831 int display_rotation = 0;
1832 gchar *org_orient = NULL;
1833 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1836 LOGE("cannot get content attribute");
1837 return MM_ERROR_PLAYER_INTERNAL;
1840 if (display_angle) {
1841 /* update user roation */
1842 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1844 /* Counter clockwise */
1845 switch (display_rotation) {
1846 case MM_DISPLAY_ROTATION_NONE:
1849 case MM_DISPLAY_ROTATION_90:
1850 *display_angle = 90;
1852 case MM_DISPLAY_ROTATION_180:
1853 *display_angle = 180;
1855 case MM_DISPLAY_ROTATION_270:
1856 *display_angle = 270;
1859 LOGW("wrong angle type : %d", display_rotation);
1862 LOGD("check user angle: %d", *display_angle);
1866 /* Counter clockwise */
1867 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1870 if (!strcmp(org_orient, "rotate-90"))
1872 else if (!strcmp(org_orient, "rotate-180"))
1874 else if (!strcmp(org_orient, "rotate-270"))
1877 LOGD("original rotation is %s", org_orient);
1879 LOGD("content_video_orientation get fail");
1882 LOGD("check orientation: %d", *orientation);
1885 return MM_ERROR_NONE;
1889 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1891 int rotation_value = 0;
1892 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1893 int display_angle = 0;
1896 /* check video sinkbin is created */
1897 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1900 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1902 /* get rotation value to set */
1903 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1904 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1905 LOGD("set video param : rotate %d", rotation_value);
1909 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1911 MMHandleType attrs = 0;
1915 /* check video sinkbin is created */
1916 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1919 attrs = MMPLAYER_GET_ATTRS(player);
1920 MMPLAYER_RETURN_IF_FAIL(attrs);
1922 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1923 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1924 LOGD("set video param : visible %d", visible);
1928 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1930 MMHandleType attrs = 0;
1931 int display_method = 0;
1934 /* check video sinkbin is created */
1935 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1938 attrs = MMPLAYER_GET_ATTRS(player);
1939 MMPLAYER_RETURN_IF_FAIL(attrs);
1941 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1942 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1943 LOGD("set video param : method %d", display_method);
1947 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1949 MMHandleType attrs = 0;
1950 void *handle = NULL;
1953 /* check video sinkbin is created */
1954 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1955 LOGW("There is no video sink");
1959 attrs = MMPLAYER_GET_ATTRS(player);
1960 MMPLAYER_RETURN_IF_FAIL(attrs);
1961 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1963 gst_video_overlay_set_video_roi_area(
1964 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1965 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1966 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1967 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1972 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1974 MMHandleType attrs = 0;
1975 void *handle = NULL;
1979 int win_roi_width = 0;
1980 int win_roi_height = 0;
1983 /* check video sinkbin is created */
1984 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1985 LOGW("There is no video sink");
1989 attrs = MMPLAYER_GET_ATTRS(player);
1990 MMPLAYER_RETURN_IF_FAIL(attrs);
1992 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1995 /* It should be set after setting window */
1996 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1997 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1998 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1999 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2001 /* After setting window handle, set display roi area */
2002 gst_video_overlay_set_display_roi_area(
2003 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2004 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2005 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2006 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2011 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2013 MMHandleType attrs = 0;
2014 void *handle = NULL;
2016 /* check video sinkbin is created */
2017 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2020 attrs = MMPLAYER_GET_ATTRS(player);
2021 MMPLAYER_RETURN_IF_FAIL(attrs);
2023 /* common case if using overlay surface */
2024 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2027 /* default is using wl_surface_id */
2028 unsigned int wl_surface_id = 0;
2029 wl_surface_id = *(int *)handle;
2030 LOGD("set video param : wl_surface_id %d", wl_surface_id);
2031 gst_video_overlay_set_wl_window_wl_surface_id(
2032 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2035 /* FIXIT : is it error case? */
2036 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2041 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2043 gboolean update_all_param = FALSE;
2046 /* check video sinkbin is created */
2047 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2048 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2050 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2051 LOGE("can not find tizenwlsink");
2052 return MM_ERROR_PLAYER_INTERNAL;
2055 LOGD("param_name : %s", param_name);
2056 if (!g_strcmp0(param_name, "update_all_param"))
2057 update_all_param = TRUE;
2059 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2060 __mmplayer_video_param_set_display_overlay(player);
2061 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2062 __mmplayer_video_param_set_display_method(player);
2063 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2064 __mmplayer_video_param_set_display_visible(player);
2065 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2066 __mmplayer_video_param_set_display_rotation(player);
2067 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2068 __mmplayer_video_param_set_roi_area(player);
2069 if (update_all_param)
2070 __mmplayer_video_param_set_video_roi_area(player);
2072 return MM_ERROR_NONE;
2076 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2078 MMHandleType attrs = 0;
2079 int surface_type = 0;
2080 int ret = MM_ERROR_NONE;
2084 /* check video sinkbin is created */
2085 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2086 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2088 attrs = MMPLAYER_GET_ATTRS(player);
2090 LOGE("cannot get content attribute");
2091 return MM_ERROR_PLAYER_INTERNAL;
2093 LOGD("param_name : %s", param_name);
2095 /* update display surface */
2096 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2097 LOGD("check display surface type attribute: %d", surface_type);
2099 /* configuring display */
2100 switch (surface_type) {
2101 case MM_DISPLAY_SURFACE_OVERLAY:
2103 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2104 if (ret != MM_ERROR_NONE)
2112 return MM_ERROR_NONE;
2116 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2118 gboolean disable_overlay = FALSE;
2119 mmplayer_t *player = (mmplayer_t *)hplayer;
2122 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2123 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2124 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2125 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2127 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2128 LOGW("Display control is not supported");
2129 return MM_ERROR_PLAYER_INTERNAL;
2132 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2134 if (audio_only == (bool)disable_overlay) {
2135 LOGE("It's the same with current setting: (%d)", audio_only);
2136 return MM_ERROR_NONE;
2140 LOGE("disable overlay");
2141 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2143 /* release overlay resource */
2144 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2145 LOGE("failed to release overlay resource");
2149 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2150 LOGE("failed to acquire video overlay resource");
2153 player->interrupted_by_resource = FALSE;
2155 LOGD("enable overlay");
2156 __mmplayer_video_param_set_display_overlay(player);
2157 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2162 return MM_ERROR_NONE;
2166 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2168 mmplayer_t *player = (mmplayer_t *)hplayer;
2169 gboolean disable_overlay = FALSE;
2173 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2174 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2175 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2176 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2177 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2179 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2180 LOGW("Display control is not supported");
2181 return MM_ERROR_PLAYER_INTERNAL;
2184 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2186 *paudio_only = (bool)disable_overlay;
2188 LOGD("audio_only : %d", *paudio_only);
2192 return MM_ERROR_NONE;
2196 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2198 GList *bucket = element_bucket;
2199 mmplayer_gst_element_t *element = NULL;
2200 mmplayer_gst_element_t *prv_element = NULL;
2201 GstElement *tee_element = NULL;
2202 gint successful_link_count = 0;
2206 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2208 prv_element = (mmplayer_gst_element_t *)bucket->data;
2209 bucket = bucket->next;
2211 for (; bucket; bucket = bucket->next) {
2212 element = (mmplayer_gst_element_t *)bucket->data;
2214 if (element && element->gst) {
2215 if (prv_element && prv_element->gst) {
2216 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2218 prv_element->gst = tee_element;
2220 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2221 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2222 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2226 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2227 LOGD("linking [%s] to [%s] success",
2228 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2229 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2230 successful_link_count++;
2231 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2232 LOGD("keep audio-tee element for next audio pipeline branch");
2233 tee_element = prv_element->gst;
2236 LOGD("linking [%s] to [%s] failed",
2237 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2238 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2244 prv_element = element;
2249 return successful_link_count;
2253 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2255 GList *bucket = element_bucket;
2256 mmplayer_gst_element_t *element = NULL;
2257 int successful_add_count = 0;
2261 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2262 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2264 for (; bucket; bucket = bucket->next) {
2265 element = (mmplayer_gst_element_t *)bucket->data;
2267 if (element && element->gst) {
2268 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2269 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2270 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2271 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2274 successful_add_count++;
2280 return successful_add_count;
2284 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2286 mmplayer_t *player = (mmplayer_t *)data;
2287 GstCaps *caps = NULL;
2288 GstStructure *str = NULL;
2290 gboolean caps_ret = TRUE;
2294 MMPLAYER_RETURN_IF_FAIL(pad);
2295 MMPLAYER_RETURN_IF_FAIL(unused);
2296 MMPLAYER_RETURN_IF_FAIL(data);
2298 caps = gst_pad_get_current_caps(pad);
2302 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2306 LOGD("name = %s", name);
2308 if (strstr(name, "audio")) {
2309 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2311 if (player->audio_stream_changed_cb) {
2312 LOGE("call the audio stream changed cb");
2313 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2315 } else if (strstr(name, "video")) {
2316 if ((name = gst_structure_get_string(str, "format")))
2317 player->set_mode.video_zc = name[0] == 'S';
2319 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2321 if (player->video_stream_changed_cb) {
2322 LOGE("call the video stream changed cb");
2323 player->video_stream_changed_cb(player->video_stream_changed_cb_user_param);
2326 LOGW("invalid caps info");
2331 gst_caps_unref(caps);
2339 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2344 MMPLAYER_RETURN_IF_FAIL(player);
2346 if (player->audio_stream_buff_list) {
2347 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2348 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2351 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2352 __mmplayer_audio_stream_send_data(player, tmp);
2354 MMPLAYER_FREEIF(tmp->pcm_data);
2355 MMPLAYER_FREEIF(tmp);
2358 g_list_free(player->audio_stream_buff_list);
2359 player->audio_stream_buff_list = NULL;
2366 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2368 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2371 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2373 audio_stream.bitrate = a_buffer->bitrate;
2374 audio_stream.channel = a_buffer->channel;
2375 audio_stream.depth = a_buffer->depth;
2376 audio_stream.is_little_endian = a_buffer->is_little_endian;
2377 audio_stream.channel_mask = a_buffer->channel_mask;
2378 audio_stream.data_size = a_buffer->data_size;
2379 audio_stream.data = a_buffer->pcm_data;
2380 audio_stream.pcm_format = a_buffer->pcm_format;
2382 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2383 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2389 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2391 mmplayer_t *player = (mmplayer_t *)data;
2392 const gchar *pcm_format = NULL;
2396 gint endianness = 0;
2397 guint64 channel_mask = 0;
2398 void *a_data = NULL;
2400 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2401 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2405 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2407 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2408 a_data = mapinfo.data;
2409 a_size = mapinfo.size;
2411 GstCaps *caps = gst_pad_get_current_caps(pad);
2412 GstStructure *structure = gst_caps_get_structure(caps, 0);
2414 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2415 pcm_format = gst_structure_get_string(structure, "format");
2416 gst_structure_get_int(structure, "rate", &rate);
2417 gst_structure_get_int(structure, "channels", &channel);
2418 gst_structure_get_int(structure, "depth", &depth);
2419 gst_structure_get_int(structure, "endianness", &endianness);
2420 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2421 gst_caps_unref(GST_CAPS(caps));
2423 /* In case of the sync is false, use buffer list. *
2424 * The num of buffer list depends on the num of audio channels */
2425 if (player->audio_stream_buff_list) {
2426 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2427 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2429 if (channel_mask == tmp->channel_mask) {
2430 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2431 if (tmp->data_size + a_size < tmp->buff_size) {
2432 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2433 tmp->data_size += a_size;
2435 /* send data to client */
2436 __mmplayer_audio_stream_send_data(player, tmp);
2438 if (a_size > tmp->buff_size) {
2439 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2440 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2441 if (tmp->pcm_data == NULL) {
2442 LOGE("failed to realloc data.");
2445 tmp->buff_size = a_size;
2447 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2448 memcpy(tmp->pcm_data, a_data, a_size);
2449 tmp->data_size = a_size;
2454 LOGE("data is empty in list.");
2460 /* create new audio stream data for newly found audio channel */
2461 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2462 if (a_buffer == NULL) {
2463 LOGE("failed to alloc data.");
2466 a_buffer->bitrate = rate;
2467 a_buffer->channel = channel;
2468 a_buffer->depth = depth;
2469 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2470 a_buffer->channel_mask = channel_mask;
2471 a_buffer->data_size = a_size;
2472 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2474 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2475 /* If sync is FALSE, use buffer list to reduce the IPC. */
2476 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2477 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2478 if (a_buffer->pcm_data == NULL) {
2479 LOGE("failed to alloc data.");
2480 MMPLAYER_FREEIF(a_buffer);
2483 memcpy(a_buffer->pcm_data, a_data, a_size);
2484 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2485 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2487 /* If sync is TRUE, send data directly. */
2488 a_buffer->pcm_data = a_data;
2489 __mmplayer_audio_stream_send_data(player, a_buffer);
2490 MMPLAYER_FREEIF(a_buffer);
2494 gst_buffer_unmap(buffer, &mapinfo);
2499 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2501 mmplayer_t *player = (mmplayer_t *)data;
2502 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2503 GstPad *sinkpad = NULL;
2504 GstElement *queue = NULL, *sink = NULL;
2507 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2509 queue = gst_element_factory_make("queue", NULL);
2510 if (queue == NULL) {
2511 LOGD("fail make queue");
2515 sink = gst_element_factory_make("fakesink", NULL);
2517 LOGD("fail make fakesink");
2521 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2523 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2524 LOGW("failed to link queue & sink");
2528 sinkpad = gst_element_get_static_pad(queue, "sink");
2530 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2531 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2535 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2537 gst_object_unref(sinkpad);
2538 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2539 g_object_set(sink, "sync", TRUE, NULL);
2540 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2542 /* keep the first sink reference only */
2543 if (!audiobin[MMPLAYER_A_SINK].gst) {
2544 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2545 audiobin[MMPLAYER_A_SINK].gst = sink;
2548 gst_element_set_state(sink, GST_STATE_PAUSED);
2549 gst_element_set_state(queue, GST_STATE_PAUSED);
2551 _mmplayer_add_signal_connection(player,
2553 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2555 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2558 __mmplayer_add_sink(player, sink);
2564 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2566 gst_object_unref(GST_OBJECT(queue));
2570 gst_object_unref(GST_OBJECT(sink));
2574 gst_object_unref(GST_OBJECT(sinkpad));
2582 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2584 #define MAX_PROPS_LEN 128
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 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2600 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2603 LOGE("stream_type is null.");
2605 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2606 stream_type, stream_id);
2607 props = gst_structure_from_string(stream_props, NULL);
2608 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2609 LOGI("stream_type[%s], stream_id[%d], result[%s].", stream_type, stream_id, stream_props);
2610 gst_structure_free(props);
2613 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2615 switch (latency_mode) {
2616 case AUDIO_LATENCY_MODE_LOW:
2617 latency = g_strndup("low", 3);
2619 case AUDIO_LATENCY_MODE_MID:
2620 latency = g_strndup("mid", 3);
2622 case AUDIO_LATENCY_MODE_HIGH:
2623 latency = g_strndup("high", 4);
2627 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2631 LOGD("audiosink property - latency=%s", latency);
2633 MMPLAYER_FREEIF(latency);
2639 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2641 mmplayer_gst_element_t *audiobin = NULL;
2644 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2646 audiobin = player->pipeline->audiobin;
2648 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2649 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2650 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2652 if (player->video360_yaw_radians <= M_PI &&
2653 player->video360_yaw_radians >= -M_PI &&
2654 player->video360_pitch_radians <= M_PI_2 &&
2655 player->video360_pitch_radians >= -M_PI_2) {
2656 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2657 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2658 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2659 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2660 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2661 "source-orientation-y", player->video360_metadata.init_view_heading,
2662 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2669 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2671 mmplayer_gst_element_t *audiobin = NULL;
2672 GstPad *sink_pad = NULL;
2673 GstCaps *acaps = NULL;
2675 int pitch_control = 0;
2676 double pitch_value = 1.0;
2679 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2680 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2682 audiobin = player->pipeline->audiobin;
2684 LOGD("make element for normal audio playback");
2686 /* audio bin structure for playback. {} means optional.
2687 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2689 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2690 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2693 /* for pitch control */
2694 mm_attrs_multiple_get(player->attrs, NULL,
2695 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2696 MM_PLAYER_PITCH_VALUE, &pitch_value,
2699 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2700 if (pitch_control && (player->videodec_linked == 0)) {
2701 GstElementFactory *factory;
2703 factory = gst_element_factory_find("pitch");
2705 gst_object_unref(factory);
2708 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2712 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2714 LOGW("there is no pitch element");
2719 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2721 /* replaygain volume */
2722 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2723 if (player->sound.rg_enable)
2724 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2726 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2729 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2731 /* for logical volume control */
2732 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2735 if (player->sound.mute) {
2736 LOGD("mute enabled");
2737 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2740 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2742 /* audio effect element. if audio effect is enabled */
2743 if ((strcmp(player->ini.audioeffect_element, ""))
2745 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2746 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2748 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2750 if ((!player->bypass_audio_effect)
2751 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2752 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2753 if (!_mmplayer_audio_effect_custom_apply(player))
2754 LOGI("apply audio effect(custom) setting success");
2758 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2759 && (player->set_mode.rich_audio)) {
2760 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2764 /* create audio sink */
2765 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2766 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2767 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2769 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2770 if (player->is_360_feature_enabled &&
2771 player->is_content_spherical &&
2773 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2774 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2775 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2777 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2779 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2781 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2782 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2783 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2784 gst_caps_unref(acaps);
2786 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2788 player->is_openal_plugin_used = TRUE;
2790 if (player->is_360_feature_enabled && player->is_content_spherical)
2791 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2792 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2795 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2796 (player->videodec_linked && player->ini.use_system_clock)) {
2797 LOGD("system clock will be used.");
2798 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2801 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2802 __mmplayer_gst_set_pulsesink_property(player);
2803 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2804 __mmplayer_gst_set_openalsink_property(player);
2807 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2808 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2810 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2811 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2812 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2813 gst_object_unref(GST_OBJECT(sink_pad));
2815 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2818 return MM_ERROR_NONE;
2820 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2822 return MM_ERROR_PLAYER_INTERNAL;
2826 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2828 mmplayer_gst_element_t *audiobin = NULL;
2829 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2831 gchar *dst_format = NULL;
2833 int dst_samplerate = 0;
2834 int dst_channels = 0;
2835 GstCaps *caps = NULL;
2836 char *caps_str = NULL;
2839 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2840 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2842 audiobin = player->pipeline->audiobin;
2844 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2846 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2848 [case 1] extract interleave audio pcm without playback
2849 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2850 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2852 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2854 [case 2] deinterleave for each channel without playback
2855 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2856 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2858 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2859 - fakesink (sync or not)
2862 [case 3] [case 1(sync only)] + playback
2863 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2865 * src - ... - tee - queue1 - playback path
2866 - queue2 - [case1 pipeline with sync]
2868 [case 4] [case 2(sync only)] + playback
2869 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2871 * src - ... - tee - queue1 - playback path
2872 - queue2 - [case2 pipeline with sync]
2876 /* 1. create tee and playback path
2877 'tee' should be added at first to copy the decoded stream
2879 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2880 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2881 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2883 /* tee - path 1 : for playback path */
2884 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2885 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2887 /* tee - path 2 : for extract path */
2888 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2889 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2892 /* if there is tee, 'tee - path 2' is linked here */
2894 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2897 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2899 /* 2. decide the extract pcm format */
2900 mm_attrs_multiple_get(player->attrs, NULL,
2901 "pcm_audioformat", &dst_format, &dst_len,
2902 "pcm_extraction_samplerate", &dst_samplerate,
2903 "pcm_extraction_channels", &dst_channels,
2906 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2907 dst_format, dst_len, dst_samplerate, dst_channels);
2909 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2910 mm_attrs_multiple_get(player->attrs, NULL,
2911 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2912 "content_audio_samplerate", &dst_samplerate,
2913 "content_audio_channels", &dst_channels,
2916 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2917 dst_format, dst_len, dst_samplerate, dst_channels);
2919 /* If there is no enough information, set it to platform default value. */
2920 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2921 LOGD("set platform default format");
2922 dst_format = DEFAULT_PCM_OUT_FORMAT;
2924 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2925 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2928 /* 3. create capsfilter */
2929 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2930 caps = gst_caps_new_simple("audio/x-raw",
2931 "format", G_TYPE_STRING, dst_format,
2932 "rate", G_TYPE_INT, dst_samplerate,
2933 "channels", G_TYPE_INT, dst_channels,
2936 caps_str = gst_caps_to_string(caps);
2937 LOGD("new caps : %s", caps_str);
2939 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2942 gst_caps_unref(caps);
2943 MMPLAYER_FREEIF(caps_str);
2945 /* 4-1. create deinterleave to extract pcm for each channel */
2946 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2947 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2948 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2950 /* audiosink will be added after getting signal for each channel */
2951 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2952 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2954 /* 4-2. create fakesink to extract interlevaed pcm */
2955 LOGD("add audio fakesink for interleaved audio");
2956 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2957 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2958 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2959 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2961 _mmplayer_add_signal_connection(player,
2962 G_OBJECT(audiobin[extract_sink_id].gst),
2963 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2965 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2968 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2972 return MM_ERROR_NONE;
2974 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2976 return MM_ERROR_PLAYER_INTERNAL;
2980 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2982 int ret = MM_ERROR_NONE;
2983 mmplayer_gst_element_t *audiobin = NULL;
2984 GList *element_bucket = NULL;
2987 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2988 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2990 audiobin = player->pipeline->audiobin;
2992 if (player->build_audio_offload) { /* skip all the audio filters */
2993 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2995 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2996 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2997 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2999 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3003 /* FIXME: need to mention the supportable condition at API reference */
3004 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3005 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3007 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3009 if (ret != MM_ERROR_NONE)
3012 LOGD("success to make audio bin element");
3013 *bucket = element_bucket;
3016 return MM_ERROR_NONE;
3019 LOGE("failed to make audio bin element");
3020 g_list_free(element_bucket);
3024 return MM_ERROR_PLAYER_INTERNAL;
3028 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3030 mmplayer_gst_element_t *first_element = NULL;
3031 mmplayer_gst_element_t *audiobin = NULL;
3033 GstPad *ghostpad = NULL;
3034 GList *element_bucket = NULL;
3038 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3041 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3043 LOGE("failed to allocate memory for audiobin");
3044 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3048 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3049 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3050 if (!audiobin[MMPLAYER_A_BIN].gst) {
3051 LOGE("failed to create audiobin");
3056 player->pipeline->audiobin = audiobin;
3058 /* create audio filters and audiosink */
3059 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3062 /* adding created elements to bin */
3063 LOGD("adding created elements to bin");
3064 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3067 /* linking elements in the bucket by added order. */
3068 LOGD("Linking elements in the bucket by added order.");
3069 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3072 /* get first element's sinkpad for creating ghostpad */
3073 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3074 if (!first_element) {
3075 LOGE("failed to get first elem");
3079 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3081 LOGE("failed to get pad from first element of audiobin");
3085 ghostpad = gst_ghost_pad_new("sink", pad);
3087 LOGE("failed to create ghostpad");
3091 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3092 LOGE("failed to add ghostpad to audiobin");
3096 gst_object_unref(pad);
3098 g_list_free(element_bucket);
3101 return MM_ERROR_NONE;
3104 LOGD("ERROR : releasing audiobin");
3107 gst_object_unref(GST_OBJECT(pad));
3110 gst_object_unref(GST_OBJECT(ghostpad));
3113 g_list_free(element_bucket);
3115 /* release element which are not added to bin */
3116 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3117 /* NOTE : skip bin */
3118 if (audiobin[i].gst) {
3119 GstObject *parent = NULL;
3120 parent = gst_element_get_parent(audiobin[i].gst);
3123 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3124 audiobin[i].gst = NULL;
3126 gst_object_unref(GST_OBJECT(parent));
3130 /* release audiobin with it's childs */
3131 if (audiobin[MMPLAYER_A_BIN].gst)
3132 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3134 MMPLAYER_FREEIF(audiobin);
3136 player->pipeline->audiobin = NULL;
3138 return MM_ERROR_PLAYER_INTERNAL;
3142 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3144 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3148 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3150 int ret = MM_ERROR_NONE;
3152 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3153 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3155 MMPLAYER_VIDEO_BO_LOCK(player);
3157 if (player->video_bo_list) {
3158 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3159 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3160 if (tmp && tmp->bo == bo) {
3162 LOGD("release bo %p", bo);
3163 tbm_bo_unref(tmp->bo);
3164 MMPLAYER_VIDEO_BO_UNLOCK(player);
3165 MMPLAYER_VIDEO_BO_SIGNAL(player);
3170 /* hw codec is running or the list was reset for DRC. */
3171 LOGW("there is no bo list.");
3173 MMPLAYER_VIDEO_BO_UNLOCK(player);
3175 LOGW("failed to find bo %p", bo);
3180 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3185 MMPLAYER_RETURN_IF_FAIL(player);
3187 MMPLAYER_VIDEO_BO_LOCK(player);
3188 if (player->video_bo_list) {
3189 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3190 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3191 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3194 tbm_bo_unref(tmp->bo);
3198 g_list_free(player->video_bo_list);
3199 player->video_bo_list = NULL;
3201 player->video_bo_size = 0;
3202 MMPLAYER_VIDEO_BO_UNLOCK(player);
3209 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3212 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3213 gboolean ret = TRUE;
3215 /* check DRC, if it is, destroy the prev bo list to create again */
3216 if (player->video_bo_size != size) {
3217 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3218 __mmplayer_video_stream_destroy_bo_list(player);
3219 player->video_bo_size = size;
3222 MMPLAYER_VIDEO_BO_LOCK(player);
3224 if ((!player->video_bo_list) ||
3225 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3227 /* create bo list */
3229 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3231 if (player->video_bo_list) {
3232 /* if bo list did not created all, try it again. */
3233 idx = g_list_length(player->video_bo_list);
3234 LOGD("bo list exist(len: %d)", idx);
3237 for (; idx < player->ini.num_of_video_bo; idx++) {
3238 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3240 LOGE("Fail to alloc bo_info.");
3243 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3245 LOGE("Fail to tbm_bo_alloc.");
3246 MMPLAYER_FREEIF(bo_info);
3249 bo_info->used = FALSE;
3250 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3253 /* update video num buffers */
3254 LOGD("video_num_buffers : %d", idx);
3255 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3256 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3259 MMPLAYER_VIDEO_BO_UNLOCK(player);
3265 /* get bo from list*/
3266 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3267 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3268 if (tmp && (tmp->used == FALSE)) {
3269 LOGD("found bo %p to use", tmp->bo);
3271 MMPLAYER_VIDEO_BO_UNLOCK(player);
3272 return tbm_bo_ref(tmp->bo);
3276 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3277 MMPLAYER_VIDEO_BO_UNLOCK(player);
3281 if (player->ini.video_bo_timeout <= 0) {
3282 MMPLAYER_VIDEO_BO_WAIT(player);
3284 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3285 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3292 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3294 mmplayer_t *player = (mmplayer_t *)data;
3296 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3298 /* send prerolled pkt */
3299 player->video_stream_prerolled = false;
3301 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3303 /* not to send prerolled pkt again */
3304 player->video_stream_prerolled = true;
3308 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3310 mmplayer_t *player = (mmplayer_t *)data;
3311 mmplayer_video_decoded_data_info_t *stream = NULL;
3312 GstMemory *mem = NULL;
3315 MMPLAYER_RETURN_IF_FAIL(player);
3316 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3318 if (player->video_stream_prerolled) {
3319 player->video_stream_prerolled = false;
3320 LOGD("skip the prerolled pkt not to send it again");
3324 /* clear stream data structure */
3325 stream = __mmplayer_create_stream_from_pad(pad);
3327 LOGE("failed to alloc stream");
3331 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3333 /* set size and timestamp */
3334 mem = gst_buffer_peek_memory(buffer, 0);
3335 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3336 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3338 /* check zero-copy */
3339 if (player->set_mode.video_zc &&
3340 player->set_mode.video_export &&
3341 gst_is_tizen_memory(mem)) {
3342 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3343 stream->internal_buffer = gst_buffer_ref(buffer);
3344 } else { /* sw codec */
3345 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3348 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3352 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3353 LOGE("failed to send video decoded data.");
3360 LOGE("release video stream resource.");
3361 if (gst_is_tizen_memory(mem)) {
3363 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3365 tbm_bo_unref(stream->bo[i]);
3368 /* unref gst buffer */
3369 if (stream->internal_buffer)
3370 gst_buffer_unref(stream->internal_buffer);
3373 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3375 MMPLAYER_FREEIF(stream);
3380 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3382 mmplayer_gst_element_t *videobin = NULL;
3385 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3387 videobin = player->pipeline->videobin;
3389 /* Set spatial media metadata and/or user settings to the element.
3391 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3392 "projection-type", player->video360_metadata.projection_type, NULL);
3394 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3395 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3397 if (player->video360_metadata.full_pano_width_pixels &&
3398 player->video360_metadata.full_pano_height_pixels &&
3399 player->video360_metadata.cropped_area_image_width &&
3400 player->video360_metadata.cropped_area_image_height) {
3401 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3402 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3403 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3404 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3405 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3406 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3407 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3411 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3412 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3413 "horizontal-fov", player->video360_horizontal_fov,
3414 "vertical-fov", player->video360_vertical_fov, NULL);
3417 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3418 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3419 "zoom", 1.0f / player->video360_zoom, NULL);
3422 if (player->video360_yaw_radians <= M_PI &&
3423 player->video360_yaw_radians >= -M_PI &&
3424 player->video360_pitch_radians <= M_PI_2 &&
3425 player->video360_pitch_radians >= -M_PI_2) {
3426 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3427 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3428 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3429 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3430 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3431 "pose-yaw", player->video360_metadata.init_view_heading,
3432 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3435 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3436 "passthrough", !player->is_video360_enabled, NULL);
3443 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3445 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3446 GList *element_bucket = NULL;
3449 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3451 /* create video360 filter */
3452 if (player->is_360_feature_enabled && player->is_content_spherical) {
3453 LOGD("create video360 element");
3454 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3455 __mmplayer_gst_set_video360_property(player);
3459 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3460 LOGD("skip creating the videoconv and rotator");
3461 return MM_ERROR_NONE;
3464 /* in case of sw codec & overlay surface type, except 360 playback.
3465 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3466 LOGD("create video converter: %s", video_csc);
3467 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3470 *bucket = element_bucket;
3472 return MM_ERROR_NONE;
3474 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3475 g_list_free(element_bucket);
3479 return MM_ERROR_PLAYER_INTERNAL;
3483 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3485 gchar *factory_name = NULL;
3487 switch (surface_type) {
3488 case MM_DISPLAY_SURFACE_OVERLAY:
3489 if (strlen(player->ini.videosink_element_overlay) > 0)
3490 factory_name = player->ini.videosink_element_overlay;
3492 case MM_DISPLAY_SURFACE_REMOTE:
3493 case MM_DISPLAY_SURFACE_NULL:
3494 if (strlen(player->ini.videosink_element_fake) > 0)
3495 factory_name = player->ini.videosink_element_fake;
3498 LOGE("unidentified surface type");
3502 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3503 return factory_name;
3507 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3509 gchar *factory_name = NULL;
3510 mmplayer_gst_element_t *videobin = NULL;
3515 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3517 videobin = player->pipeline->videobin;
3518 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3520 attrs = MMPLAYER_GET_ATTRS(player);
3522 LOGE("cannot get content attribute");
3523 return MM_ERROR_PLAYER_INTERNAL;
3526 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3527 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3528 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3530 /* support shard memory with S/W codec on HawkP */
3531 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3532 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3533 "use-tbm", use_tbm, NULL);
3537 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3538 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3541 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3543 LOGD("disable last-sample");
3544 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3547 if (player->set_mode.video_export) {
3549 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3550 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3551 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3553 _mmplayer_add_signal_connection(player,
3554 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3555 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3557 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3560 _mmplayer_add_signal_connection(player,
3561 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3562 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3564 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3568 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3569 return MM_ERROR_PLAYER_INTERNAL;
3571 if (videobin[MMPLAYER_V_SINK].gst) {
3572 GstPad *sink_pad = NULL;
3573 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3575 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3576 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3577 gst_object_unref(GST_OBJECT(sink_pad));
3579 LOGE("failed to get sink pad from videosink");
3583 return MM_ERROR_NONE;
3588 * - video overlay surface(arm/x86) : tizenwlsink
3591 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3594 GList *element_bucket = NULL;
3595 mmplayer_gst_element_t *first_element = NULL;
3596 mmplayer_gst_element_t *videobin = NULL;
3597 gchar *videosink_factory_name = NULL;
3600 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3603 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3605 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3607 player->pipeline->videobin = videobin;
3610 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3611 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3612 if (!videobin[MMPLAYER_V_BIN].gst) {
3613 LOGE("failed to create videobin");
3617 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3620 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3621 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3623 /* additional setting for sink plug-in */
3624 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3625 LOGE("failed to set video property");
3629 /* store it as it's sink element */
3630 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3632 /* adding created elements to bin */
3633 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3634 LOGE("failed to add elements");
3638 /* Linking elements in the bucket by added order */
3639 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3640 LOGE("failed to link elements");
3644 /* get first element's sinkpad for creating ghostpad */
3645 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3646 if (!first_element) {
3647 LOGE("failed to get first element from bucket");
3651 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3653 LOGE("failed to get pad from first element");
3657 /* create ghostpad */
3658 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3659 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3660 LOGE("failed to add ghostpad to videobin");
3663 gst_object_unref(pad);
3665 /* done. free allocated variables */
3666 g_list_free(element_bucket);
3670 return MM_ERROR_NONE;
3673 LOGE("ERROR : releasing videobin");
3674 g_list_free(element_bucket);
3677 gst_object_unref(GST_OBJECT(pad));
3679 /* release videobin with it's childs */
3680 if (videobin[MMPLAYER_V_BIN].gst)
3681 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3683 MMPLAYER_FREEIF(videobin);
3684 player->pipeline->videobin = NULL;
3686 return MM_ERROR_PLAYER_INTERNAL;
3690 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3692 GList *element_bucket = NULL;
3693 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3695 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3696 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3697 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3698 "signal-handoffs", FALSE,
3701 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3702 _mmplayer_add_signal_connection(player,
3703 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3704 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3706 G_CALLBACK(__mmplayer_update_subtitle),
3709 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3710 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3712 if (!player->play_subtitle) {
3713 LOGD("add textbin sink as sink element of whole pipeline.");
3714 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3717 /* adding created elements to bin */
3718 LOGD("adding created elements to bin");
3719 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3720 LOGE("failed to add elements");
3724 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3725 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3726 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3728 /* linking elements in the bucket by added order. */
3729 LOGD("Linking elements in the bucket by added order.");
3730 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3731 LOGE("failed to link elements");
3735 /* done. free allocated variables */
3736 g_list_free(element_bucket);
3738 if (textbin[MMPLAYER_T_QUEUE].gst) {
3740 GstPad *ghostpad = NULL;
3742 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3744 LOGE("failed to get sink pad of text queue");
3748 ghostpad = gst_ghost_pad_new("text_sink", pad);
3749 gst_object_unref(pad);
3752 LOGE("failed to create ghostpad of textbin");
3756 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3757 LOGE("failed to add ghostpad to textbin");
3758 gst_object_unref(ghostpad);
3763 return MM_ERROR_NONE;
3766 g_list_free(element_bucket);
3768 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3769 LOGE("remove textbin sink from sink list");
3770 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3773 /* release element at __mmplayer_gst_create_text_sink_bin */
3774 return MM_ERROR_PLAYER_INTERNAL;
3778 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3780 mmplayer_gst_element_t *textbin = NULL;
3781 GList *element_bucket = NULL;
3782 int surface_type = 0;
3787 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3790 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3792 LOGE("failed to allocate memory for textbin");
3793 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3797 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3798 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3799 if (!textbin[MMPLAYER_T_BIN].gst) {
3800 LOGE("failed to create textbin");
3805 player->pipeline->textbin = textbin;
3808 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3809 LOGD("surface type for subtitle : %d", surface_type);
3810 switch (surface_type) {
3811 case MM_DISPLAY_SURFACE_OVERLAY:
3812 case MM_DISPLAY_SURFACE_NULL:
3813 case MM_DISPLAY_SURFACE_REMOTE:
3814 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3815 LOGE("failed to make plain text elements");
3826 return MM_ERROR_NONE;
3830 LOGD("ERROR : releasing textbin");
3832 g_list_free(element_bucket);
3834 /* release signal */
3835 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3837 /* release element which are not added to bin */
3838 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3839 /* NOTE : skip bin */
3840 if (textbin[i].gst) {
3841 GstObject *parent = NULL;
3842 parent = gst_element_get_parent(textbin[i].gst);
3845 gst_object_unref(GST_OBJECT(textbin[i].gst));
3846 textbin[i].gst = NULL;
3848 gst_object_unref(GST_OBJECT(parent));
3853 /* release textbin with it's childs */
3854 if (textbin[MMPLAYER_T_BIN].gst)
3855 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3857 MMPLAYER_FREEIF(player->pipeline->textbin);
3858 player->pipeline->textbin = NULL;
3861 return MM_ERROR_PLAYER_INTERNAL;
3865 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3867 mmplayer_gst_element_t *mainbin = NULL;
3868 mmplayer_gst_element_t *textbin = NULL;
3869 MMHandleType attrs = 0;
3870 GstElement *subsrc = NULL;
3871 GstElement *subparse = NULL;
3872 gchar *subtitle_uri = NULL;
3873 const gchar *charset = NULL;
3879 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3881 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3883 mainbin = player->pipeline->mainbin;
3885 attrs = MMPLAYER_GET_ATTRS(player);
3887 LOGE("cannot get content attribute");
3888 return MM_ERROR_PLAYER_INTERNAL;
3891 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3892 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3893 LOGE("subtitle uri is not proper filepath.");
3894 return MM_ERROR_PLAYER_INVALID_URI;
3897 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3898 LOGE("failed to get storage info of subtitle path");
3899 return MM_ERROR_PLAYER_INVALID_URI;
3902 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3904 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3905 player->subtitle_language_list = NULL;
3906 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3908 /* create the subtitle source */
3909 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3911 LOGE("failed to create filesrc element");
3914 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3916 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3917 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3919 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3920 LOGW("failed to add queue");
3921 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3922 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3923 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3928 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3930 LOGE("failed to create subparse element");
3934 charset = _mmplayer_get_charset(subtitle_uri);
3936 LOGD("detected charset is %s", charset);
3937 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3940 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3941 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3943 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3944 LOGW("failed to add subparse");
3945 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3946 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3947 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3951 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3952 LOGW("failed to link subsrc and subparse");
3956 player->play_subtitle = TRUE;
3957 player->adjust_subtitle_pos = 0;
3959 LOGD("play subtitle using subtitle file");
3961 if (player->pipeline->textbin == NULL) {
3962 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3963 LOGE("failed to create text sink bin. continuing without text");
3967 textbin = player->pipeline->textbin;
3969 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3970 LOGW("failed to add textbin");
3972 /* release signal */
3973 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3975 /* release textbin with it's childs */
3976 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3977 MMPLAYER_FREEIF(player->pipeline->textbin);
3978 player->pipeline->textbin = textbin = NULL;
3982 LOGD("link text input selector and textbin ghost pad");
3984 player->textsink_linked = 1;
3985 player->external_text_idx = 0;
3986 LOGI("textsink is linked");
3988 textbin = player->pipeline->textbin;
3989 LOGD("text bin has been created. reuse it.");
3990 player->external_text_idx = 1;
3993 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3994 LOGW("failed to link subparse and textbin");
3998 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4000 LOGE("failed to get sink pad from textsink to probe data");
4004 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4005 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4007 gst_object_unref(pad);
4010 /* create dot. for debugging */
4011 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4014 return MM_ERROR_NONE;
4017 /* release text pipeline resource */
4018 player->textsink_linked = 0;
4020 /* release signal */
4021 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4023 if (player->pipeline->textbin) {
4024 LOGE("remove textbin");
4026 /* release textbin with it's childs */
4027 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4028 MMPLAYER_FREEIF(player->pipeline->textbin);
4029 player->pipeline->textbin = NULL;
4033 /* release subtitle elem */
4034 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4035 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4037 return MM_ERROR_PLAYER_INTERNAL;
4041 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4043 mmplayer_t *player = (mmplayer_t *)data;
4044 MMMessageParamType msg = {0, };
4045 GstClockTime duration = 0;
4046 gpointer text = NULL;
4047 guint text_size = 0;
4048 gboolean ret = TRUE;
4049 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4053 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4054 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4056 if (player->is_subtitle_force_drop) {
4057 LOGW("subtitle is dropped forcedly.");
4061 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4062 text = mapinfo.data;
4063 text_size = mapinfo.size;
4065 if (player->set_mode.subtitle_off) {
4066 LOGD("subtitle is OFF.");
4070 if (!text || (text_size == 0)) {
4071 LOGD("There is no subtitle to be displayed.");
4075 msg.data = (void *)text;
4077 duration = GST_BUFFER_DURATION(buffer);
4079 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4080 if (player->duration > GST_BUFFER_PTS(buffer))
4081 duration = player->duration - GST_BUFFER_PTS(buffer);
4084 LOGI("subtitle duration is invalid, subtitle duration change "
4085 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4087 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4089 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4091 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4092 gst_buffer_unmap(buffer, &mapinfo);
4099 static GstPadProbeReturn
4100 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4102 mmplayer_t *player = (mmplayer_t *)u_data;
4103 GstClockTime cur_timestamp = 0;
4104 gint64 adjusted_timestamp = 0;
4105 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4107 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4109 if (player->set_mode.subtitle_off) {
4110 LOGD("subtitle is OFF.");
4114 if (player->adjust_subtitle_pos == 0) {
4115 LOGD("nothing to do");
4119 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4120 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4122 if (adjusted_timestamp < 0) {
4123 LOGD("adjusted_timestamp under zero");
4128 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4129 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4130 GST_TIME_ARGS(cur_timestamp),
4131 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4133 return GST_PAD_PROBE_OK;
4137 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4141 /* check player and subtitlebin are created */
4142 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4143 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4145 if (position == 0) {
4146 LOGD("nothing to do");
4148 return MM_ERROR_NONE;
4151 /* check current postion */
4152 player->adjust_subtitle_pos = position;
4154 LOGD("save adjust_subtitle_pos in player");
4158 return MM_ERROR_NONE;
4162 * This function is to create audio or video pipeline for playing.
4164 * @param player [in] handle of player
4166 * @return This function returns zero on success.
4171 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4173 int ret = MM_ERROR_NONE;
4174 mmplayer_gst_element_t *mainbin = NULL;
4175 MMHandleType attrs = 0;
4178 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4180 /* get profile attribute */
4181 attrs = MMPLAYER_GET_ATTRS(player);
4183 LOGE("failed to get content attribute");
4187 /* create pipeline handles */
4188 if (player->pipeline) {
4189 LOGE("pipeline should be released before create new one");
4193 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4194 if (player->pipeline == NULL)
4197 /* create mainbin */
4198 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4199 if (mainbin == NULL)
4202 /* create pipeline */
4203 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4204 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4205 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4206 LOGE("failed to create pipeline");
4211 player->pipeline->mainbin = mainbin;
4213 /* create the source and decoder elements */
4214 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4215 ret = _mmplayer_gst_build_es_pipeline(player);
4217 ret = _mmplayer_gst_build_pipeline(player);
4219 if (ret != MM_ERROR_NONE) {
4220 LOGE("failed to create some elements");
4224 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4225 if (__mmplayer_check_subtitle(player)
4226 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4227 LOGE("failed to create text pipeline");
4230 ret = _mmplayer_gst_add_bus_watch(player);
4231 if (ret != MM_ERROR_NONE) {
4232 LOGE("failed to add bus watch");
4237 return MM_ERROR_NONE;
4240 __mmplayer_gst_destroy_pipeline(player);
4241 return MM_ERROR_PLAYER_INTERNAL;
4245 __mmplayer_reset_gapless_state(mmplayer_t *player)
4248 MMPLAYER_RETURN_IF_FAIL(player
4250 && player->pipeline->audiobin
4251 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4253 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4260 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4263 int ret = MM_ERROR_NONE;
4267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4269 /* cleanup stuffs */
4270 MMPLAYER_FREEIF(player->type);
4271 player->no_more_pad = FALSE;
4272 player->num_dynamic_pad = 0;
4273 player->demux_pad_index = 0;
4275 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4276 player->subtitle_language_list = NULL;
4277 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4279 __mmplayer_reset_gapless_state(player);
4281 if (player->streamer) {
4282 _mm_player_streaming_initialize(player->streamer, FALSE);
4283 _mm_player_streaming_destroy(player->streamer);
4284 player->streamer = NULL;
4287 /* cleanup unlinked mime type */
4288 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4289 MMPLAYER_FREEIF(player->unlinked_video_mime);
4290 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4292 /* cleanup running stuffs */
4293 _mmplayer_cancel_eos_timer(player);
4295 /* cleanup gst stuffs */
4296 if (player->pipeline) {
4297 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4298 GstTagList *tag_list = player->pipeline->tag_list;
4300 /* first we need to disconnect all signal hander */
4301 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4304 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4305 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4306 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4307 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4308 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4309 gst_object_unref(bus);
4311 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4312 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4313 if (ret != MM_ERROR_NONE) {
4314 LOGE("fail to change state to NULL");
4315 return MM_ERROR_PLAYER_INTERNAL;
4318 LOGW("succeeded in changing state to NULL");
4320 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4323 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4324 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4326 /* free avsysaudiosink
4327 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4328 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4330 MMPLAYER_FREEIF(audiobin);
4331 MMPLAYER_FREEIF(videobin);
4332 MMPLAYER_FREEIF(textbin);
4333 MMPLAYER_FREEIF(mainbin);
4337 gst_tag_list_unref(tag_list);
4339 MMPLAYER_FREEIF(player->pipeline);
4341 MMPLAYER_FREEIF(player->album_art);
4343 if (player->v_stream_caps) {
4344 gst_caps_unref(player->v_stream_caps);
4345 player->v_stream_caps = NULL;
4348 if (player->a_stream_caps) {
4349 gst_caps_unref(player->a_stream_caps);
4350 player->a_stream_caps = NULL;
4353 if (player->s_stream_caps) {
4354 gst_caps_unref(player->s_stream_caps);
4355 player->s_stream_caps = NULL;
4357 _mmplayer_track_destroy(player);
4359 if (player->sink_elements)
4360 g_list_free(player->sink_elements);
4361 player->sink_elements = NULL;
4363 if (player->bufmgr) {
4364 tbm_bufmgr_deinit(player->bufmgr);
4365 player->bufmgr = NULL;
4368 LOGW("finished destroy pipeline");
4376 __mmplayer_gst_realize(mmplayer_t *player)
4379 int ret = MM_ERROR_NONE;
4383 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4385 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4387 ret = __mmplayer_gst_create_pipeline(player);
4389 LOGE("failed to create pipeline");
4393 /* set pipeline state to READY */
4394 /* NOTE : state change to READY must be performed sync. */
4395 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4396 ret = _mmplayer_gst_set_state(player,
4397 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4399 if (ret != MM_ERROR_NONE) {
4400 /* return error if failed to set state */
4401 LOGE("failed to set READY state");
4405 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4407 /* create dot before error-return. for debugging */
4408 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4416 __mmplayer_gst_unrealize(mmplayer_t *player)
4418 int ret = MM_ERROR_NONE;
4422 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4424 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4425 MMPLAYER_PRINT_STATE(player);
4427 /* release miscellaneous information */
4428 __mmplayer_release_misc(player);
4430 /* destroy pipeline */
4431 ret = __mmplayer_gst_destroy_pipeline(player);
4432 if (ret != MM_ERROR_NONE) {
4433 LOGE("failed to destory pipeline");
4437 /* release miscellaneous information.
4438 these info needs to be released after pipeline is destroyed. */
4439 __mmplayer_release_misc_post(player);
4441 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4449 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4454 LOGW("set_message_callback is called with invalid player handle");
4455 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4458 player->msg_cb = callback;
4459 player->msg_cb_param = user_param;
4461 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4465 return MM_ERROR_NONE;
4469 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4471 int ret = MM_ERROR_NONE;
4476 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4477 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4478 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4480 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4482 if (strstr(uri, "es_buff://")) {
4483 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4484 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4485 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4486 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4488 tmp = g_ascii_strdown(uri, strlen(uri));
4489 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4490 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4492 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4494 } else if (strstr(uri, "mms://")) {
4495 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4496 } else if ((path = strstr(uri, "mem://"))) {
4497 ret = __mmplayer_set_mem_uri(data, path, param);
4499 ret = __mmplayer_set_file_uri(data, uri);
4502 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4503 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4504 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4505 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4507 /* dump parse result */
4508 SECURE_LOGW("incoming uri : %s", uri);
4509 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4510 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4518 __mmplayer_can_do_interrupt(mmplayer_t *player)
4520 if (!player || !player->pipeline || !player->attrs) {
4521 LOGW("not initialized");
4525 if (player->audio_decoded_cb) {
4526 LOGW("not support in pcm extraction mode");
4530 /* check if seeking */
4531 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4532 MMMessageParamType msg_param;
4533 memset(&msg_param, 0, sizeof(MMMessageParamType));
4534 msg_param.code = MM_ERROR_PLAYER_SEEK;
4535 player->seek_state = MMPLAYER_SEEK_NONE;
4536 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4540 /* check other thread */
4541 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4542 LOGW("locked already, cmd state : %d", player->cmd);
4544 /* check application command */
4545 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4546 LOGW("playing.. should wait cmd lock then, will be interrupted");
4548 /* lock will be released at mrp_resource_release_cb() */
4549 MMPLAYER_CMD_LOCK(player);
4552 LOGW("nothing to do");
4555 LOGW("can interrupt immediately");
4559 FAILED: /* with CMD UNLOCKED */
4562 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4567 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4570 mmplayer_t *player = NULL;
4571 MMMessageParamType msg = {0, };
4573 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4578 LOGE("user_data is null");
4581 player = (mmplayer_t *)user_data;
4583 if (!__mmplayer_can_do_interrupt(player)) {
4584 LOGW("no need to interrupt, so leave");
4585 /* FIXME: there is no way to avoid releasing resource. */
4589 player->interrupted_by_resource = TRUE;
4591 /* get last play position */
4592 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4593 msg.union_type = MM_MSG_UNION_TIME;
4594 msg.time.elapsed = pos;
4595 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4597 LOGW("failed to get play position.");
4600 LOGD("video resource conflict so, resource will be freed by unrealizing");
4601 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4602 LOGE("failed to unrealize");
4604 /* lock is called in __mmplayer_can_do_interrupt() */
4605 MMPLAYER_CMD_UNLOCK(player);
4607 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4608 player->hw_resource[res_idx] = NULL;
4612 return TRUE; /* release all the resources */
4616 __mmplayer_initialize_video_roi(mmplayer_t *player)
4618 player->video_roi.scale_x = 0.0;
4619 player->video_roi.scale_y = 0.0;
4620 player->video_roi.scale_width = 1.0;
4621 player->video_roi.scale_height = 1.0;
4625 _mmplayer_create_player(MMHandleType handle)
4627 int ret = MM_ERROR_PLAYER_INTERNAL;
4628 bool enabled = false;
4630 mmplayer_t *player = MM_PLAYER_CAST(handle);
4634 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4636 /* initialize player state */
4637 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4638 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4639 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4640 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4642 /* check current state */
4643 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4645 /* construct attributes */
4646 player->attrs = _mmplayer_construct_attribute(handle);
4648 if (!player->attrs) {
4649 LOGE("Failed to construct attributes");
4653 /* initialize gstreamer with configured parameter */
4654 if (!__mmplayer_init_gstreamer(player)) {
4655 LOGE("Initializing gstreamer failed");
4656 _mmplayer_deconstruct_attribute(handle);
4660 /* create lock. note that g_tread_init() has already called in gst_init() */
4661 g_mutex_init(&player->fsink_lock);
4663 /* create update tag lock */
4664 g_mutex_init(&player->update_tag_lock);
4666 /* create gapless play mutex */
4667 g_mutex_init(&player->gapless_play_thread_mutex);
4669 /* create gapless play cond */
4670 g_cond_init(&player->gapless_play_thread_cond);
4672 /* create gapless play thread */
4673 player->gapless_play_thread =
4674 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4675 if (!player->gapless_play_thread) {
4676 LOGE("failed to create gapless play thread");
4677 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4678 g_mutex_clear(&player->gapless_play_thread_mutex);
4679 g_cond_clear(&player->gapless_play_thread_cond);
4683 player->bus_msg_q = g_queue_new();
4684 if (!player->bus_msg_q) {
4685 LOGE("failed to create queue for bus_msg");
4686 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4690 ret = _mmplayer_initialize_video_capture(player);
4691 if (ret != MM_ERROR_NONE) {
4692 LOGE("failed to initialize video capture");
4696 /* initialize resource manager */
4697 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4698 __resource_release_cb, player, &player->resource_manager)
4699 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4700 LOGE("failed to initialize resource manager");
4701 ret = MM_ERROR_PLAYER_INTERNAL;
4705 /* create video bo lock and cond */
4706 g_mutex_init(&player->video_bo_mutex);
4707 g_cond_init(&player->video_bo_cond);
4709 /* create media stream callback mutex */
4710 g_mutex_init(&player->media_stream_cb_lock);
4712 /* create subtitle info lock and cond */
4713 g_mutex_init(&player->subtitle_info_mutex);
4714 g_cond_init(&player->subtitle_info_cond);
4716 player->streaming_type = STREAMING_SERVICE_NONE;
4718 /* give default value of audio effect setting */
4719 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4720 player->sound.rg_enable = false;
4721 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4723 player->play_subtitle = FALSE;
4724 player->has_closed_caption = FALSE;
4725 player->pending_resume = FALSE;
4726 if (player->ini.dump_element_keyword[0][0] == '\0')
4727 player->ini.set_dump_element_flag = FALSE;
4729 player->ini.set_dump_element_flag = TRUE;
4731 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4732 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4733 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4735 /* Set video360 settings to their defaults for just-created player.
4738 player->is_360_feature_enabled = FALSE;
4739 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4740 LOGI("spherical feature info: %d", enabled);
4742 player->is_360_feature_enabled = TRUE;
4744 LOGE("failed to get spherical feature info");
4747 player->is_content_spherical = FALSE;
4748 player->is_video360_enabled = TRUE;
4749 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4750 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4751 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4752 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4753 player->video360_zoom = 1.0f;
4754 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4755 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4757 __mmplayer_initialize_video_roi(player);
4759 /* set player state to null */
4760 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4761 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4765 return MM_ERROR_NONE;
4769 g_mutex_clear(&player->fsink_lock);
4770 /* free update tag lock */
4771 g_mutex_clear(&player->update_tag_lock);
4772 g_queue_free(player->bus_msg_q);
4773 player->bus_msg_q = NULL;
4774 /* free gapless play thread */
4775 if (player->gapless_play_thread) {
4776 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4777 player->gapless_play_thread_exit = TRUE;
4778 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4779 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4781 g_thread_join(player->gapless_play_thread);
4782 player->gapless_play_thread = NULL;
4784 g_mutex_clear(&player->gapless_play_thread_mutex);
4785 g_cond_clear(&player->gapless_play_thread_cond);
4788 /* release attributes */
4789 _mmplayer_deconstruct_attribute(handle);
4797 __mmplayer_init_gstreamer(mmplayer_t *player)
4799 static gboolean initialized = FALSE;
4800 static const int max_argc = 50;
4802 gchar **argv = NULL;
4803 gchar **argv2 = NULL;
4809 LOGD("gstreamer already initialized.");
4814 argc = malloc(sizeof(int));
4815 argv = malloc(sizeof(gchar *) * max_argc);
4816 argv2 = malloc(sizeof(gchar *) * max_argc);
4818 if (!argc || !argv || !argv2)
4821 memset(argv, 0, sizeof(gchar *) * max_argc);
4822 memset(argv2, 0, sizeof(gchar *) * max_argc);
4826 argv[0] = g_strdup("mmplayer");
4829 for (i = 0; i < 5; i++) {
4830 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4831 if (strlen(player->ini.gst_param[i]) > 0) {
4832 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4837 /* we would not do fork for scanning plugins */
4838 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4841 /* check disable registry scan */
4842 if (player->ini.skip_rescan) {
4843 argv[*argc] = g_strdup("--gst-disable-registry-update");
4847 /* check disable segtrap */
4848 if (player->ini.disable_segtrap) {
4849 argv[*argc] = g_strdup("--gst-disable-segtrap");
4853 LOGD("initializing gstreamer with following parameter");
4854 LOGD("argc : %d", *argc);
4857 for (i = 0; i < arg_count; i++) {
4859 LOGD("argv[%d] : %s", i, argv2[i]);
4862 /* initializing gstreamer */
4863 if (!gst_init_check(argc, &argv, &err)) {
4864 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4871 for (i = 0; i < arg_count; i++) {
4872 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4873 MMPLAYER_FREEIF(argv2[i]);
4876 MMPLAYER_FREEIF(argv);
4877 MMPLAYER_FREEIF(argv2);
4878 MMPLAYER_FREEIF(argc);
4888 for (i = 0; i < arg_count; i++) {
4889 LOGD("free[%d] : %s", i, argv2[i]);
4890 MMPLAYER_FREEIF(argv2[i]);
4893 MMPLAYER_FREEIF(argv);
4894 MMPLAYER_FREEIF(argv2);
4895 MMPLAYER_FREEIF(argc);
4901 __mmplayer_check_async_state_transition(mmplayer_t *player)
4903 GstState element_state = GST_STATE_VOID_PENDING;
4904 GstState element_pending_state = GST_STATE_VOID_PENDING;
4905 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4906 GstElement *element = NULL;
4907 gboolean async = FALSE;
4909 /* check player handle */
4910 MMPLAYER_RETURN_IF_FAIL(player &&
4912 player->pipeline->mainbin &&
4913 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4916 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4918 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4919 LOGD("don't need to check the pipeline state");
4923 MMPLAYER_PRINT_STATE(player);
4925 /* wait for state transition */
4926 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4927 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4929 if (ret == GST_STATE_CHANGE_FAILURE) {
4930 LOGE(" [%s] state : %s pending : %s",
4931 GST_ELEMENT_NAME(element),
4932 gst_element_state_get_name(element_state),
4933 gst_element_state_get_name(element_pending_state));
4935 /* dump state of all element */
4936 _mmplayer_dump_pipeline_state(player);
4941 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4946 _mmplayer_destroy(MMHandleType handle)
4948 mmplayer_t *player = MM_PLAYER_CAST(handle);
4952 /* check player handle */
4953 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4955 /* destroy can called at anytime */
4956 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4958 /* check async state transition */
4959 __mmplayer_check_async_state_transition(player);
4961 /* release gapless play thread */
4962 if (player->gapless_play_thread) {
4963 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4964 player->gapless_play_thread_exit = TRUE;
4965 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4966 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4968 LOGD("waitting for gapless play thread exit");
4969 g_thread_join(player->gapless_play_thread);
4970 g_mutex_clear(&player->gapless_play_thread_mutex);
4971 g_cond_clear(&player->gapless_play_thread_cond);
4972 LOGD("gapless play thread released");
4975 _mmplayer_release_video_capture(player);
4977 /* de-initialize resource manager */
4978 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4979 player->resource_manager))
4980 LOGE("failed to deinitialize resource manager");
4982 /* release pipeline */
4983 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4984 LOGE("failed to destory pipeline");
4985 return MM_ERROR_PLAYER_INTERNAL;
4988 g_queue_free(player->bus_msg_q);
4990 /* release subtitle info lock and cond */
4991 g_mutex_clear(&player->subtitle_info_mutex);
4992 g_cond_clear(&player->subtitle_info_cond);
4994 __mmplayer_release_dump_list(player->dump_list);
4996 /* release miscellaneous information */
4997 __mmplayer_release_misc(player);
4999 /* release miscellaneous information.
5000 these info needs to be released after pipeline is destroyed. */
5001 __mmplayer_release_misc_post(player);
5003 /* release attributes */
5004 _mmplayer_deconstruct_attribute(handle);
5007 g_mutex_clear(&player->fsink_lock);
5010 g_mutex_clear(&player->update_tag_lock);
5012 /* release video bo lock and cond */
5013 g_mutex_clear(&player->video_bo_mutex);
5014 g_cond_clear(&player->video_bo_cond);
5016 /* release media stream callback lock */
5017 g_mutex_clear(&player->media_stream_cb_lock);
5021 return MM_ERROR_NONE;
5025 _mmplayer_realize(MMHandleType hplayer)
5027 mmplayer_t *player = (mmplayer_t *)hplayer;
5030 MMHandleType attrs = 0;
5031 int ret = MM_ERROR_NONE;
5035 /* check player handle */
5036 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5038 /* check current state */
5039 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5041 attrs = MMPLAYER_GET_ATTRS(player);
5043 LOGE("fail to get attributes.");
5044 return MM_ERROR_PLAYER_INTERNAL;
5046 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5047 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5049 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5050 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5052 if (ret != MM_ERROR_NONE) {
5053 LOGE("failed to parse profile");
5058 if (uri && (strstr(uri, "es_buff://"))) {
5059 if (strstr(uri, "es_buff://push_mode"))
5060 player->es_player_push_mode = TRUE;
5062 player->es_player_push_mode = FALSE;
5065 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5066 LOGW("mms protocol is not supported format.");
5067 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5070 if (MMPLAYER_IS_STREAMING(player))
5071 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5073 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5075 player->smooth_streaming = FALSE;
5076 player->videodec_linked = 0;
5077 player->audiodec_linked = 0;
5078 player->textsink_linked = 0;
5079 player->is_external_subtitle_present = FALSE;
5080 player->is_external_subtitle_added_now = FALSE;
5081 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5082 player->video360_metadata.is_spherical = -1;
5083 player->is_openal_plugin_used = FALSE;
5084 player->demux_pad_index = 0;
5085 player->subtitle_language_list = NULL;
5086 player->is_subtitle_force_drop = FALSE;
5088 _mmplayer_track_initialize(player);
5089 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5091 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5092 gint prebuffer_ms = 0, rebuffer_ms = 0;
5094 player->streamer = _mm_player_streaming_create();
5095 _mm_player_streaming_initialize(player->streamer, TRUE);
5097 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5098 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5100 if (prebuffer_ms > 0) {
5101 prebuffer_ms = MAX(prebuffer_ms, 1000);
5102 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5105 if (rebuffer_ms > 0) {
5106 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5107 rebuffer_ms = MAX(rebuffer_ms, 1000);
5108 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5111 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5112 player->streamer->buffering_req.rebuffer_time);
5115 /* realize pipeline */
5116 ret = __mmplayer_gst_realize(player);
5117 if (ret != MM_ERROR_NONE)
5118 LOGE("fail to realize the player.");
5120 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5128 _mmplayer_unrealize(MMHandleType hplayer)
5130 mmplayer_t *player = (mmplayer_t *)hplayer;
5131 int ret = MM_ERROR_NONE;
5135 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5137 MMPLAYER_CMD_UNLOCK(player);
5138 /* destroy the gst bus msg thread which is created during realize.
5139 this funct have to be called before getting cmd lock. */
5140 _mmplayer_bus_msg_thread_destroy(player);
5141 MMPLAYER_CMD_LOCK(player);
5143 /* check current state */
5144 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5146 /* check async state transition */
5147 __mmplayer_check_async_state_transition(player);
5149 /* unrealize pipeline */
5150 ret = __mmplayer_gst_unrealize(player);
5152 if (!player->interrupted_by_resource) {
5153 if ((__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) ||
5154 (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE))
5155 LOGE("failed to release video resources");
5163 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5165 mmplayer_t *player = (mmplayer_t *)hplayer;
5167 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5169 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5173 _mmplayer_get_state(MMHandleType hplayer, int *state)
5175 mmplayer_t *player = (mmplayer_t *)hplayer;
5177 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5179 *state = MMPLAYER_CURRENT_STATE(player);
5181 return MM_ERROR_NONE;
5185 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5187 GstElement *vol_element = NULL;
5188 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5191 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5192 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5194 /* check pipeline handle */
5195 if (!player->pipeline || !player->pipeline->audiobin) {
5196 LOGD("'%s' will be applied when audiobin is created", prop_name);
5198 /* NOTE : stored value will be used in create_audiobin
5199 * returning MM_ERROR_NONE here makes application to able to
5200 * set audio volume or mute at anytime.
5202 return MM_ERROR_NONE;
5205 if (player->build_audio_offload) {
5206 LOGD("offload pipeline");
5207 volume_elem_id = MMPLAYER_A_SINK;
5210 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5212 LOGE("failed to get vol element %d", volume_elem_id);
5213 return MM_ERROR_PLAYER_INTERNAL;
5216 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5218 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5219 LOGE("there is no '%s' property", prop_name);
5220 return MM_ERROR_PLAYER_INTERNAL;
5223 if (!strcmp(prop_name, "volume")) {
5224 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5225 } else if (!strcmp(prop_name, "mute")) {
5226 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5228 LOGE("invalid property %s", prop_name);
5229 return MM_ERROR_PLAYER_INTERNAL;
5232 return MM_ERROR_NONE;
5236 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5238 int ret = MM_ERROR_NONE;
5239 mmplayer_t *player = (mmplayer_t *)hplayer;
5242 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5244 LOGD("volume = %f", volume);
5246 /* invalid factor range or not */
5247 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5248 LOGE("Invalid volume value");
5249 return MM_ERROR_INVALID_ARGUMENT;
5252 player->sound.volume = volume;
5254 ret = __mmplayer_gst_set_volume_property(player, "volume");
5261 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5263 mmplayer_t *player = (mmplayer_t *)hplayer;
5267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5268 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5270 *volume = player->sound.volume;
5272 LOGD("current vol = %f", *volume);
5275 return MM_ERROR_NONE;
5279 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5281 int ret = MM_ERROR_NONE;
5282 mmplayer_t *player = (mmplayer_t *)hplayer;
5285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5287 LOGD("mute = %d", mute);
5289 player->sound.mute = mute;
5291 ret = __mmplayer_gst_set_volume_property(player, "mute");
5298 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5300 mmplayer_t *player = (mmplayer_t *)hplayer;
5304 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5305 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5307 *mute = player->sound.mute;
5309 LOGD("current mute = %d", *mute);
5313 return MM_ERROR_NONE;
5317 _mmplayer_set_videostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5319 mmplayer_t *player = (mmplayer_t *)hplayer;
5323 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5325 player->video_stream_changed_cb = callback;
5326 player->video_stream_changed_cb_user_param = user_param;
5327 LOGD("Handle value is %p : %p", player, player->video_stream_changed_cb);
5331 return MM_ERROR_NONE;
5335 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5337 mmplayer_t *player = (mmplayer_t *)hplayer;
5341 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5343 player->audio_stream_changed_cb = callback;
5344 player->audio_stream_changed_cb_user_param = user_param;
5345 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5349 return MM_ERROR_NONE;
5353 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5355 mmplayer_t *player = (mmplayer_t *)hplayer;
5359 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5361 player->audio_decoded_cb = callback;
5362 player->audio_decoded_cb_user_param = user_param;
5363 player->audio_extract_opt = opt;
5364 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5368 return MM_ERROR_NONE;
5372 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5374 mmplayer_t *player = (mmplayer_t *)hplayer;
5378 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5380 if (callback && !player->bufmgr)
5381 player->bufmgr = tbm_bufmgr_init(-1);
5383 player->set_mode.video_export = (callback) ? true : false;
5384 player->video_decoded_cb = callback;
5385 player->video_decoded_cb_user_param = user_param;
5387 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5391 return MM_ERROR_NONE;
5395 _mmplayer_start(MMHandleType hplayer)
5397 mmplayer_t *player = (mmplayer_t *)hplayer;
5398 gint ret = MM_ERROR_NONE;
5402 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5404 /* check current state */
5405 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5407 /* start pipeline */
5408 ret = _mmplayer_gst_start(player);
5409 if (ret != MM_ERROR_NONE)
5410 LOGE("failed to start player.");
5412 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5413 LOGD("force playing start even during buffering");
5414 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5422 /* NOTE: post "not supported codec message" to application
5423 * when one codec is not found during AUTOPLUGGING in MSL.
5424 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5425 * And, if any codec is not found, don't send message here.
5426 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5429 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5431 MMMessageParamType msg_param;
5432 memset(&msg_param, 0, sizeof(MMMessageParamType));
5433 gboolean post_msg_direct = FALSE;
5437 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5439 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5440 player->not_supported_codec, player->can_support_codec);
5442 if (player->not_found_demuxer) {
5443 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5444 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5446 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5447 MMPLAYER_FREEIF(msg_param.data);
5449 return MM_ERROR_NONE;
5452 if (player->not_supported_codec) {
5453 if (player->can_support_codec) {
5454 // There is one codec to play
5455 post_msg_direct = TRUE;
5457 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5458 post_msg_direct = TRUE;
5461 if (post_msg_direct) {
5462 MMMessageParamType msg_param;
5463 memset(&msg_param, 0, sizeof(MMMessageParamType));
5465 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5466 LOGW("not found AUDIO codec, posting error code to application.");
5468 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5469 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5470 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5471 LOGW("not found VIDEO codec, posting error code to application.");
5473 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5474 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5477 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5479 MMPLAYER_FREEIF(msg_param.data);
5481 return MM_ERROR_NONE;
5483 // no any supported codec case
5484 LOGW("not found any codec, posting error code to application.");
5486 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5487 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5488 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5490 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5491 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5494 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5496 MMPLAYER_FREEIF(msg_param.data);
5502 return MM_ERROR_NONE;
5506 __mmplayer_check_pipeline(mmplayer_t *player)
5508 GstState element_state = GST_STATE_VOID_PENDING;
5509 GstState element_pending_state = GST_STATE_VOID_PENDING;
5511 int ret = MM_ERROR_NONE;
5513 if (!player->gapless.reconfigure)
5516 LOGW("pipeline is under construction.");
5518 MMPLAYER_PLAYBACK_LOCK(player);
5519 MMPLAYER_PLAYBACK_UNLOCK(player);
5521 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5523 /* wait for state transition */
5524 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5525 if (ret == GST_STATE_CHANGE_FAILURE)
5526 LOGE("failed to change pipeline state within %d sec", timeout);
5529 /* NOTE : it should be able to call 'stop' anytime*/
5531 _mmplayer_stop(MMHandleType hplayer)
5533 mmplayer_t *player = (mmplayer_t *)hplayer;
5534 int ret = MM_ERROR_NONE;
5538 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5540 /* check current state */
5541 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5543 /* check pipline building state */
5544 __mmplayer_check_pipeline(player);
5545 __mmplayer_reset_gapless_state(player);
5547 /* NOTE : application should not wait for EOS after calling STOP */
5548 _mmplayer_cancel_eos_timer(player);
5551 player->seek_state = MMPLAYER_SEEK_NONE;
5554 ret = _mmplayer_gst_stop(player);
5556 if (ret != MM_ERROR_NONE)
5557 LOGE("failed to stop player.");
5565 _mmplayer_pause(MMHandleType hplayer)
5567 mmplayer_t *player = (mmplayer_t *)hplayer;
5568 gint64 pos_nsec = 0;
5569 gboolean async = FALSE;
5570 gint ret = MM_ERROR_NONE;
5574 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5576 /* check current state */
5577 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5579 /* check pipline building state */
5580 __mmplayer_check_pipeline(player);
5582 switch (MMPLAYER_CURRENT_STATE(player)) {
5583 case MM_PLAYER_STATE_READY:
5585 /* check prepare async or not.
5586 * In the case of streaming playback, it's recommned to avoid blocking wait.
5588 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5589 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5591 /* Changing back sync of rtspsrc to async */
5592 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5593 LOGD("async prepare working mode for rtsp");
5599 case MM_PLAYER_STATE_PLAYING:
5601 /* NOTE : store current point to overcome some bad operation
5602 *(returning zero when getting current position in paused state) of some
5605 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5606 LOGW("getting current position failed in paused");
5608 player->last_position = pos_nsec;
5610 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5611 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5612 This causes problem is position calculation during normal pause resume scenarios also.
5613 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5614 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5615 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5616 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5622 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5623 LOGD("doing async pause in case of ms buff src");
5627 /* pause pipeline */
5628 ret = _mmplayer_gst_pause(player, async);
5630 if (ret != MM_ERROR_NONE)
5631 LOGE("failed to pause player. ret : 0x%x", ret);
5633 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5634 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5635 LOGE("failed to update display_rotation");
5643 /* in case of streaming, pause could take long time.*/
5645 _mmplayer_abort_pause(MMHandleType hplayer)
5647 mmplayer_t *player = (mmplayer_t *)hplayer;
5648 int ret = MM_ERROR_NONE;
5652 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5654 player->pipeline->mainbin,
5655 MM_ERROR_PLAYER_NOT_INITIALIZED);
5657 LOGD("set the pipeline state to READY");
5659 /* set state to READY */
5660 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5661 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5662 if (ret != MM_ERROR_NONE) {
5663 LOGE("fail to change state to READY");
5664 return MM_ERROR_PLAYER_INTERNAL;
5667 LOGD("succeeded in changing state to READY");
5672 _mmplayer_resume(MMHandleType hplayer)
5674 mmplayer_t *player = (mmplayer_t *)hplayer;
5675 int ret = MM_ERROR_NONE;
5676 gboolean async = FALSE;
5680 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5682 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5683 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5684 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5688 /* Changing back sync mode rtspsrc to async */
5689 LOGD("async resume for rtsp case");
5693 /* check current state */
5694 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5696 ret = _mmplayer_gst_resume(player, async);
5697 if (ret != MM_ERROR_NONE)
5698 LOGE("failed to resume player.");
5700 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5701 LOGD("force resume even during buffering");
5702 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5711 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5713 mmplayer_t *player = (mmplayer_t *)hplayer;
5714 gint64 pos_nsec = 0;
5715 int ret = MM_ERROR_NONE;
5717 signed long long start = 0, stop = 0;
5718 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5721 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5722 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5724 /* The sound of video is not supported under 0.0 and over 2.0. */
5725 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5726 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5729 _mmplayer_set_mute(hplayer, mute);
5731 if (player->playback_rate == rate)
5732 return MM_ERROR_NONE;
5734 /* If the position is reached at start potion during fast backward, EOS is posted.
5735 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5737 player->playback_rate = rate;
5739 current_state = MMPLAYER_CURRENT_STATE(player);
5741 if (current_state != MM_PLAYER_STATE_PAUSED)
5742 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5744 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5746 if ((current_state == MM_PLAYER_STATE_PAUSED)
5747 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5748 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5749 pos_nsec = player->last_position;
5754 stop = GST_CLOCK_TIME_NONE;
5756 start = GST_CLOCK_TIME_NONE;
5760 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5761 player->playback_rate,
5763 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5764 GST_SEEK_TYPE_SET, start,
5765 GST_SEEK_TYPE_SET, stop)) {
5766 LOGE("failed to set speed playback");
5767 return MM_ERROR_PLAYER_SEEK;
5770 LOGD("succeeded to set speed playback as %0.1f", rate);
5774 return MM_ERROR_NONE;;
5778 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5780 mmplayer_t *player = (mmplayer_t *)hplayer;
5781 int ret = MM_ERROR_NONE;
5785 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5787 /* check pipline building state */
5788 __mmplayer_check_pipeline(player);
5790 ret = _mmplayer_gst_set_position(player, position, FALSE);
5798 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5800 mmplayer_t *player = (mmplayer_t *)hplayer;
5801 int ret = MM_ERROR_NONE;
5803 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5804 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5806 if (g_strrstr(player->type, "video/mpegts"))
5807 __mmplayer_update_duration_value(player);
5809 *duration = player->duration;
5814 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5816 mmplayer_t *player = (mmplayer_t *)hplayer;
5817 int ret = MM_ERROR_NONE;
5819 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5821 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5827 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5829 mmplayer_t *player = (mmplayer_t *)hplayer;
5830 int ret = MM_ERROR_NONE;
5834 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5836 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5844 __mmplayer_is_midi_type(gchar *str_caps)
5846 if ((g_strrstr(str_caps, "audio/midi")) ||
5847 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5848 (g_strrstr(str_caps, "application/x-smaf")) ||
5849 (g_strrstr(str_caps, "audio/x-imelody")) ||
5850 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5851 (g_strrstr(str_caps, "audio/xmf")) ||
5852 (g_strrstr(str_caps, "audio/mxmf"))) {
5861 __mmplayer_is_only_mp3_type(gchar *str_caps)
5863 if (g_strrstr(str_caps, "application/x-id3") ||
5864 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5870 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5872 GstStructure *caps_structure = NULL;
5873 gint samplerate = 0;
5877 MMPLAYER_RETURN_IF_FAIL(player && caps);
5879 caps_structure = gst_caps_get_structure(caps, 0);
5881 /* set stream information */
5882 gst_structure_get_int(caps_structure, "rate", &samplerate);
5883 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5885 gst_structure_get_int(caps_structure, "channels", &channels);
5886 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5888 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5892 __mmplayer_update_content_type_info(mmplayer_t *player)
5895 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5897 if (__mmplayer_is_midi_type(player->type)) {
5898 player->bypass_audio_effect = TRUE;
5902 if (!player->streamer) {
5903 LOGD("no need to check streaming type");
5907 if (g_strrstr(player->type, "application/x-hls")) {
5908 /* If it can't know exact type when it parses uri because of redirection case,
5909 * it will be fixed by typefinder or when doing autoplugging.
5911 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5912 player->streamer->is_adaptive_streaming = TRUE;
5913 } else if (g_strrstr(player->type, "application/dash+xml")) {
5914 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5915 player->streamer->is_adaptive_streaming = TRUE;
5918 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5919 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5920 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5922 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5923 if (player->streamer->is_adaptive_streaming)
5924 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5926 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5930 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5935 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5936 GstCaps *caps, gpointer data)
5938 mmplayer_t *player = (mmplayer_t *)data;
5943 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5945 /* store type string */
5946 MMPLAYER_FREEIF(player->type);
5947 player->type = gst_caps_to_string(caps);
5949 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5950 player, player->type, probability, gst_caps_get_size(caps));
5952 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5953 (g_strrstr(player->type, "audio/x-raw-int"))) {
5954 LOGE("not support media format");
5956 if (player->msg_posted == FALSE) {
5957 MMMessageParamType msg_param;
5958 memset(&msg_param, 0, sizeof(MMMessageParamType));
5960 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5961 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5963 /* don't post more if one was sent already */
5964 player->msg_posted = TRUE;
5969 __mmplayer_update_content_type_info(player);
5971 pad = gst_element_get_static_pad(tf, "src");
5973 LOGE("fail to get typefind src pad.");
5977 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5978 gboolean async = FALSE;
5979 LOGE("failed to autoplug %s", player->type);
5981 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5983 if (async && player->msg_posted == FALSE)
5984 __mmplayer_handle_missed_plugin(player);
5988 gst_object_unref(GST_OBJECT(pad));
5996 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5998 GstElement *decodebin = NULL;
6002 /* create decodebin */
6003 decodebin = gst_element_factory_make("decodebin", NULL);
6006 LOGE("fail to create decodebin");
6010 /* raw pad handling signal */
6011 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6012 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6014 /* no-more-pad pad handling signal */
6015 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6016 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6018 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6019 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6021 /* This signal is emitted when a pad for which there is no further possible
6022 decoding is added to the decodebin.*/
6023 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6024 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6026 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6027 before looking for any elements that can handle that stream.*/
6028 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6029 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6031 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6032 before looking for any elements that can handle that stream.*/
6033 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6034 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6036 /* This signal is emitted once decodebin has finished decoding all the data.*/
6037 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6038 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6040 /* This signal is emitted when a element is added to the bin.*/
6041 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6042 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6049 __mmplayer_gst_make_queue2(mmplayer_t *player)
6051 GstElement *queue2 = NULL;
6052 gint64 dur_bytes = 0L;
6053 mmplayer_gst_element_t *mainbin = NULL;
6054 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6057 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6059 mainbin = player->pipeline->mainbin;
6061 queue2 = gst_element_factory_make("queue2", "queue2");
6063 LOGE("failed to create buffering queue element");
6067 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6068 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6070 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6072 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6073 * skip the pull mode(file or ring buffering) setting. */
6074 if (dur_bytes > 0) {
6075 if (!g_strrstr(player->type, "video/mpegts")) {
6076 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6077 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6083 _mm_player_streaming_set_queue2(player->streamer,
6087 (guint64)dur_bytes); /* no meaning at the moment */
6093 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6095 mmplayer_gst_element_t *mainbin = NULL;
6096 GstElement *decodebin = NULL;
6097 GstElement *queue2 = NULL;
6098 GstPad *sinkpad = NULL;
6099 GstPad *qsrcpad = NULL;
6102 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6104 mainbin = player->pipeline->mainbin;
6106 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6108 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6109 LOGW("need to check: muxed buffer is not null");
6112 queue2 = __mmplayer_gst_make_queue2(player);
6114 LOGE("failed to make queue2");
6118 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6119 LOGE("failed to add buffering queue");
6123 sinkpad = gst_element_get_static_pad(queue2, "sink");
6124 qsrcpad = gst_element_get_static_pad(queue2, "src");
6126 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6127 LOGE("failed to link [%s:%s]-[%s:%s]",
6128 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6132 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6133 LOGE("failed to sync queue2 state with parent");
6137 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6138 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6142 gst_object_unref(GST_OBJECT(sinkpad));
6146 /* create decodebin */
6147 decodebin = _mmplayer_gst_make_decodebin(player);
6149 LOGE("failed to make decodebin");
6153 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6154 LOGE("failed to add decodebin");
6158 /* to force caps on the decodebin element and avoid reparsing stuff by
6159 * typefind. It also avoids a deadlock in the way typefind activates pads in
6160 * the state change */
6161 g_object_set(decodebin, "sink-caps", caps, NULL);
6163 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6165 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6166 LOGE("failed to link [%s:%s]-[%s:%s]",
6167 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6171 gst_object_unref(GST_OBJECT(sinkpad));
6173 gst_object_unref(GST_OBJECT(qsrcpad));
6176 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6177 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6179 /* set decodebin property about buffer in streaming playback. *
6180 * in case of HLS/DASH, it does not need to have big buffer *
6181 * because it is kind of adaptive streaming. */
6182 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6183 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6184 gint high_percent = 0;
6186 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6187 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6189 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6191 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6193 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6194 "high-percent", high_percent,
6195 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6196 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6197 "max-size-buffers", 0, NULL); // disable or automatic
6200 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6201 LOGE("failed to sync decodebin state with parent");
6212 gst_object_unref(GST_OBJECT(sinkpad));
6215 gst_object_unref(GST_OBJECT(qsrcpad));
6218 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6219 * You need to explicitly set elements to the NULL state before
6220 * dropping the final reference, to allow them to clean up.
6222 gst_element_set_state(queue2, GST_STATE_NULL);
6224 /* And, it still has a parent "player".
6225 * You need to let the parent manage the object instead of unreffing the object directly.
6227 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6228 gst_object_unref(queue2);
6233 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6234 * You need to explicitly set elements to the NULL state before
6235 * dropping the final reference, to allow them to clean up.
6237 gst_element_set_state(decodebin, GST_STATE_NULL);
6239 /* And, it still has a parent "player".
6240 * You need to let the parent manage the object instead of unreffing the object directly.
6243 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6244 gst_object_unref(decodebin);
6252 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6256 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6257 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6259 LOGD("class : %s, mime : %s", factory_class, mime);
6261 /* add missing plugin */
6262 /* NOTE : msl should check missing plugin for image mime type.
6263 * Some motion jpeg clips can have playable audio track.
6264 * So, msl have to play audio after displaying popup written video format not supported.
6266 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6267 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6268 LOGD("not found demuxer");
6269 player->not_found_demuxer = TRUE;
6270 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6276 if (!g_strrstr(factory_class, "Demuxer")) {
6277 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6278 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6279 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6281 /* check that clip have multi tracks or not */
6282 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6283 LOGD("video plugin is already linked");
6285 LOGW("add VIDEO to missing plugin");
6286 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6287 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6289 } else if (g_str_has_prefix(mime, "audio")) {
6290 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6291 LOGD("audio plugin is already linked");
6293 LOGW("add AUDIO to missing plugin");
6294 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6295 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6303 return MM_ERROR_NONE;
6307 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6309 mmplayer_t *player = (mmplayer_t *)data;
6313 MMPLAYER_RETURN_IF_FAIL(player);
6315 /* remove fakesink. */
6316 if (!_mmplayer_gst_remove_fakesink(player,
6317 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6318 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6319 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6320 * source element are not same. To overcome this situation, this function will called
6321 * several places and several times. Therefore, this is not an error case.
6326 LOGD("[handle: %p] pipeline has completely constructed", player);
6328 if ((player->ini.async_start) &&
6329 (player->msg_posted == FALSE) &&
6330 (player->cmd >= MMPLAYER_COMMAND_START))
6331 __mmplayer_handle_missed_plugin(player);
6333 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6337 __mmplayer_check_profile(void)
6340 static int profile_tv = -1;
6342 if (__builtin_expect(profile_tv != -1, 1))
6345 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6346 switch (*profileName) {
6361 __mmplayer_get_next_uri(mmplayer_t *player)
6363 mmplayer_parse_profile_t profile;
6365 guint num_of_list = 0;
6368 num_of_list = g_list_length(player->uri_info.uri_list);
6369 uri_idx = player->uri_info.uri_idx;
6371 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6372 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6373 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6375 LOGW("next uri does not exist");
6379 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6380 LOGE("failed to parse profile");
6384 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6385 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6386 LOGW("uri type is not supported(%d)", profile.uri_type);
6390 LOGD("success to find next uri %d", uri_idx);
6394 if (uri_idx == num_of_list) {
6395 LOGE("failed to find next uri");
6399 player->uri_info.uri_idx = uri_idx;
6400 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6402 if (mm_attrs_commit_all(player->attrs)) {
6403 LOGE("failed to commit");
6407 SECURE_LOGD("next playback uri: %s", uri);
6412 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6414 #define REPEAT_COUNT_INFINITE -1
6415 #define REPEAT_COUNT_MIN 2
6416 #define ORIGINAL_URI_ONLY 1
6418 MMHandleType attrs = 0;
6422 guint num_of_uri = 0;
6423 int profile_tv = -1;
6427 LOGD("checking for gapless play option");
6429 if (player->pipeline->textbin) {
6430 LOGE("subtitle path is enabled. gapless play is not supported.");
6434 attrs = MMPLAYER_GET_ATTRS(player);
6436 LOGE("fail to get attributes.");
6440 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6442 /* gapless playback is not supported in case of video at TV profile. */
6443 profile_tv = __mmplayer_check_profile();
6444 if (profile_tv && video) {
6445 LOGW("not support video gapless playback");
6449 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6450 LOGE("failed to get play count");
6452 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6453 LOGE("failed to get gapless mode");
6455 /* check repeat count in case of audio */
6457 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6458 LOGW("gapless is disabled");
6462 num_of_uri = g_list_length(player->uri_info.uri_list);
6464 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6466 if (num_of_uri == ORIGINAL_URI_ONLY) {
6467 /* audio looping path */
6468 if (count >= REPEAT_COUNT_MIN) {
6469 /* decrease play count */
6470 /* we succeeded to rewind. update play count and then wait for next EOS */
6472 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6473 /* commit attribute */
6474 if (mm_attrs_commit_all(attrs))
6475 LOGE("failed to commit attribute");
6477 } else if (count != REPEAT_COUNT_INFINITE) {
6478 LOGD("there is no next uri and no repeat");
6481 LOGD("looping cnt %d", count);
6483 /* gapless playback path */
6484 if (!__mmplayer_get_next_uri(player)) {
6485 LOGE("failed to get next uri");
6492 LOGE("unable to play gapless path. EOS will be posted soon");
6497 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6499 mmplayer_selector_t *selector = &player->selector[type];
6500 mmplayer_gst_element_t *sinkbin = NULL;
6501 main_element_id_e selectorId = MMPLAYER_M_NUM;
6502 main_element_id_e sinkId = MMPLAYER_M_NUM;
6503 GstPad *srcpad = NULL;
6504 GstPad *sinkpad = NULL;
6505 gboolean send_notice = FALSE;
6508 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6510 LOGD("type %d", type);
6513 case MM_PLAYER_TRACK_TYPE_AUDIO:
6514 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6515 sinkId = MMPLAYER_A_BIN;
6516 sinkbin = player->pipeline->audiobin;
6518 case MM_PLAYER_TRACK_TYPE_VIDEO:
6519 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6520 sinkId = MMPLAYER_V_BIN;
6521 sinkbin = player->pipeline->videobin;
6524 case MM_PLAYER_TRACK_TYPE_TEXT:
6525 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6526 sinkId = MMPLAYER_T_BIN;
6527 sinkbin = player->pipeline->textbin;
6530 LOGE("requested type is not supportable");
6535 if (player->pipeline->mainbin[selectorId].gst) {
6538 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6540 if (selector->event_probe_id != 0)
6541 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6542 selector->event_probe_id = 0;
6544 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6545 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6547 if (srcpad && sinkpad) {
6548 /* after getting drained signal there is no data flows, so no need to do pad_block */
6549 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6550 gst_pad_unlink(srcpad, sinkpad);
6552 /* send custom event to sink pad to handle it at video sink */
6554 LOGD("send custom event to sinkpad");
6555 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6556 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6557 gst_pad_send_event(sinkpad, event);
6561 gst_object_unref(sinkpad);
6564 gst_object_unref(srcpad);
6567 LOGD("selector release");
6569 /* release and unref requests pad from the selector */
6570 for (n = 0; n < selector->channels->len; n++) {
6571 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6572 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6574 g_ptr_array_set_size(selector->channels, 0);
6576 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6577 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6579 player->pipeline->mainbin[selectorId].gst = NULL;
6587 __mmplayer_deactivate_old_path(mmplayer_t *player)
6590 MMPLAYER_RETURN_IF_FAIL(player);
6592 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6593 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6594 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6595 LOGE("deactivate selector error");
6599 _mmplayer_track_destroy(player);
6600 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6602 if (player->streamer) {
6603 _mm_player_streaming_initialize(player->streamer, FALSE);
6604 _mm_player_streaming_destroy(player->streamer);
6605 player->streamer = NULL;
6608 MMPLAYER_PLAYBACK_LOCK(player);
6609 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6616 if (!player->msg_posted) {
6617 MMMessageParamType msg = {0,};
6620 msg.code = MM_ERROR_PLAYER_INTERNAL;
6621 LOGE("gapless_uri_play> deactivate error");
6623 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6624 player->msg_posted = TRUE;
6630 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6632 int result = MM_ERROR_NONE;
6633 mmplayer_t *player = (mmplayer_t *)hplayer;
6636 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6638 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6639 if (mm_attrs_commit_all(player->attrs)) {
6640 LOGE("failed to commit the original uri.");
6641 result = MM_ERROR_PLAYER_INTERNAL;
6643 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6644 LOGE("failed to add the original uri in the uri list.");
6652 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6654 mmplayer_t *player = (mmplayer_t *)hplayer;
6655 guint num_of_list = 0;
6659 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6660 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6662 if (player->pipeline && player->pipeline->textbin) {
6663 LOGE("subtitle path is enabled.");
6664 return MM_ERROR_PLAYER_INVALID_STATE;
6667 num_of_list = g_list_length(player->uri_info.uri_list);
6669 if (is_first_path) {
6670 if (num_of_list == 0) {
6671 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6672 SECURE_LOGD("add original path : %s", uri);
6674 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6675 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6677 SECURE_LOGD("change original path : %s", uri);
6680 MMHandleType attrs = 0;
6681 attrs = MMPLAYER_GET_ATTRS(player);
6683 if (num_of_list == 0) {
6684 char *original_uri = NULL;
6687 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6689 if (!original_uri) {
6690 LOGE("there is no original uri.");
6691 return MM_ERROR_PLAYER_INVALID_STATE;
6694 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6695 player->uri_info.uri_idx = 0;
6697 SECURE_LOGD("add original path at first : %s", original_uri);
6701 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6702 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6706 return MM_ERROR_NONE;
6710 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6712 mmplayer_t *player = (mmplayer_t *)hplayer;
6713 char *next_uri = NULL;
6714 guint num_of_list = 0;
6717 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6719 num_of_list = g_list_length(player->uri_info.uri_list);
6721 if (num_of_list > 0) {
6722 gint uri_idx = player->uri_info.uri_idx;
6724 if (uri_idx < num_of_list-1)
6729 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6730 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6732 *uri = g_strdup(next_uri);
6736 return MM_ERROR_NONE;
6740 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6741 GstCaps *caps, gpointer data)
6743 mmplayer_t *player = (mmplayer_t *)data;
6744 const gchar *klass = NULL;
6745 const gchar *mime = NULL;
6746 gchar *caps_str = NULL;
6748 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6749 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6750 caps_str = gst_caps_to_string(caps);
6752 LOGW("unknown type of caps : %s from %s",
6753 caps_str, GST_ELEMENT_NAME(elem));
6755 MMPLAYER_FREEIF(caps_str);
6757 /* There is no available codec. */
6758 __mmplayer_check_not_supported_codec(player, klass, mime);
6762 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6763 GstCaps *caps, gpointer data)
6765 mmplayer_t *player = (mmplayer_t *)data;
6766 const char *mime = NULL;
6767 gboolean ret = TRUE;
6769 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6770 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6772 if (g_str_has_prefix(mime, "audio")) {
6773 GstStructure *caps_structure = NULL;
6774 gint samplerate = 0;
6776 gchar *caps_str = NULL;
6778 caps_structure = gst_caps_get_structure(caps, 0);
6779 gst_structure_get_int(caps_structure, "rate", &samplerate);
6780 gst_structure_get_int(caps_structure, "channels", &channels);
6782 if ((channels > 0 && samplerate == 0)) {
6783 LOGD("exclude audio...");
6787 caps_str = gst_caps_to_string(caps);
6788 /* set it directly because not sent by TAG */
6789 if (g_strrstr(caps_str, "mobile-xmf"))
6790 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6791 MMPLAYER_FREEIF(caps_str);
6792 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6793 MMMessageParamType msg_param;
6794 memset(&msg_param, 0, sizeof(MMMessageParamType));
6795 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6796 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6797 LOGD("video file is not supported on this device");
6799 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6800 LOGD("already video linked");
6803 LOGD("found new stream");
6810 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6812 gboolean ret = TRUE;
6813 GDBusConnection *conn = NULL;
6815 GVariant *result = NULL;
6816 const gchar *dbus_device_type = NULL;
6817 const gchar *dbus_ret = NULL;
6820 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6822 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6828 result = g_dbus_connection_call_sync(conn,
6829 "org.pulseaudio.Server",
6830 "/org/pulseaudio/StreamManager",
6831 "org.pulseaudio.StreamManager",
6832 "GetCurrentMediaRoutingPath",
6833 g_variant_new("(s)", "out"),
6834 G_VARIANT_TYPE("(ss)"),
6835 G_DBUS_CALL_FLAGS_NONE,
6839 if (!result || err) {
6840 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6846 /* device type is listed in stream-map.json at mmfw-sysconf */
6847 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6849 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6850 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6855 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6856 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6857 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6858 LOGD("audio offload is supportable");
6864 LOGD("audio offload is not supportable");
6868 g_variant_unref(result);
6869 g_object_unref(conn);
6874 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6876 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6877 gint64 position = 0;
6879 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6880 player->pipeline && player->pipeline->mainbin);
6882 MMPLAYER_CMD_LOCK(player);
6883 current_state = MMPLAYER_CURRENT_STATE(player);
6885 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6886 LOGW("getting current position failed in paused");
6888 _mmplayer_unrealize((MMHandleType)player);
6889 _mmplayer_realize((MMHandleType)player);
6891 _mmplayer_set_position((MMHandleType)player, position);
6893 /* async not to be blocked in streaming case */
6894 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6895 if (mm_attrs_commit_all(player->attrs))
6896 LOGE("failed to commit");
6898 _mmplayer_pause((MMHandleType)player);
6900 if (current_state == MM_PLAYER_STATE_PLAYING)
6901 _mmplayer_start((MMHandleType)player);
6902 MMPLAYER_CMD_UNLOCK(player);
6904 LOGD("rebuilding audio pipeline is completed.");
6907 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6909 mmplayer_t *player = (mmplayer_t *)user_data;
6910 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6911 gboolean is_supportable = FALSE;
6913 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6914 LOGW("failed to get device type");
6916 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6918 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6919 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6920 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6921 LOGD("ignore this dev connected info");
6925 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6926 if (player->build_audio_offload == is_supportable) {
6927 LOGD("keep current pipeline without re-building");
6931 /* rebuild pipeline */
6932 LOGD("re-build pipeline - offload: %d", is_supportable);
6933 player->build_audio_offload = FALSE;
6934 __mmplayer_rebuild_audio_pipeline(player);
6940 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6942 unsigned int id = 0;
6944 if (player->audio_device_cb_id != 0) {
6945 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6949 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6950 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6951 LOGD("added device connected cb (%u)", id);
6952 player->audio_device_cb_id = id;
6954 LOGW("failed to add device connected cb");
6962 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6964 gboolean ret = FALSE;
6965 GstElementFactory *factory = NULL;
6968 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6970 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6971 if (!__mmplayer_is_only_mp3_type(player->type))
6974 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6975 LOGD("there is no audio offload sink");
6979 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6980 LOGW("there is no audio device type to support offload");
6984 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6986 LOGW("there is no installed audio offload sink element");
6989 gst_object_unref(factory);
6991 if (!__mmplayer_add_audio_device_connected_cb(player))
6994 if (!__mmplayer_is_audio_offload_device_type(player))
6997 LOGD("audio offload can be built");
7005 static GstAutoplugSelectResult
7006 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7008 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7010 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7011 int audio_offload = 0;
7013 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7014 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7016 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7017 LOGD("expose audio path to build offload output path");
7018 player->build_audio_offload = TRUE;
7019 /* update codec info */
7020 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7021 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7022 player->audiodec_linked = 1;
7024 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7028 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7030 LOGD("audio codec type: %d", codec_type);
7031 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7032 /* sw codec will be skipped */
7033 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7034 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7035 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7036 ret = GST_AUTOPLUG_SELECT_SKIP;
7040 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7041 /* hw codec will be skipped */
7042 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7043 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7044 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7045 ret = GST_AUTOPLUG_SELECT_SKIP;
7050 /* set stream information */
7051 if (!player->audiodec_linked)
7052 __mmplayer_set_audio_attrs(player, caps);
7054 /* update codec info */
7055 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7056 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7057 player->audiodec_linked = 1;
7059 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7061 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7063 LOGD("video codec type: %d", codec_type);
7064 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7065 /* sw codec is skipped */
7066 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7067 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7068 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7069 ret = GST_AUTOPLUG_SELECT_SKIP;
7073 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7074 /* hw codec is skipped */
7075 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7076 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7077 ret = GST_AUTOPLUG_SELECT_SKIP;
7082 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7083 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7085 /* mark video decoder for acquire */
7086 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7087 LOGW("video decoder resource is already acquired, skip it.");
7088 ret = GST_AUTOPLUG_SELECT_SKIP;
7092 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7093 LOGE("failed to acquire video decoder resource");
7094 ret = GST_AUTOPLUG_SELECT_SKIP;
7097 player->interrupted_by_resource = FALSE;
7100 /* update codec info */
7101 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7102 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7103 player->videodec_linked = 1;
7111 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7112 GstCaps *caps, GstElementFactory *factory, gpointer data)
7114 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7115 mmplayer_t *player = (mmplayer_t *)data;
7117 gchar *factory_name = NULL;
7118 gchar *caps_str = NULL;
7119 const gchar *klass = NULL;
7122 factory_name = GST_OBJECT_NAME(factory);
7123 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7124 caps_str = gst_caps_to_string(caps);
7126 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7128 /* store type string */
7129 if (player->type == NULL) {
7130 player->type = gst_caps_to_string(caps);
7131 __mmplayer_update_content_type_info(player);
7134 /* filtering exclude keyword */
7135 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7136 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7137 LOGW("skipping [%s] by exculde keyword [%s]",
7138 factory_name, player->ini.exclude_element_keyword[idx]);
7140 result = GST_AUTOPLUG_SELECT_SKIP;
7145 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7146 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7147 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7148 factory_name, player->ini.unsupported_codec_keyword[idx]);
7149 result = GST_AUTOPLUG_SELECT_SKIP;
7154 /* exclude webm format */
7155 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7156 * because webm format is not supportable.
7157 * If webm is disabled in "autoplug-continue", there is no state change
7158 * failure or error because the decodebin will expose the pad directly.
7159 * It make MSL invoke _prepare_async_callback.
7160 * So, we need to disable webm format in "autoplug-select" */
7161 if (caps_str && strstr(caps_str, "webm")) {
7162 LOGW("webm is not supported");
7163 result = GST_AUTOPLUG_SELECT_SKIP;
7167 /* check factory class for filtering */
7168 /* NOTE : msl don't need to use image plugins.
7169 * So, those plugins should be skipped for error handling.
7171 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7172 LOGD("skipping [%s] by not required", factory_name);
7173 result = GST_AUTOPLUG_SELECT_SKIP;
7177 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7178 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7179 // TO CHECK : subtitle if needed, add subparse exception.
7180 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7181 result = GST_AUTOPLUG_SELECT_SKIP;
7185 if (g_strrstr(factory_name, "mpegpsdemux")) {
7186 LOGD("skipping PS container - not support");
7187 result = GST_AUTOPLUG_SELECT_SKIP;
7191 if (g_strrstr(factory_name, "mssdemux"))
7192 player->smooth_streaming = TRUE;
7194 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7195 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7198 GstStructure *str = NULL;
7199 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7201 /* don't make video because of not required */
7202 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7203 (!player->set_mode.video_export)) {
7204 LOGD("no need video decoding, expose pad");
7205 result = GST_AUTOPLUG_SELECT_EXPOSE;
7209 /* get w/h for omx state-tune */
7210 /* FIXME: deprecated? */
7211 str = gst_caps_get_structure(caps, 0);
7212 gst_structure_get_int(str, "width", &width);
7215 if (player->v_stream_caps) {
7216 gst_caps_unref(player->v_stream_caps);
7217 player->v_stream_caps = NULL;
7220 player->v_stream_caps = gst_caps_copy(caps);
7221 LOGD("take caps for video state tune");
7222 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7226 if (g_strrstr(klass, "Codec/Decoder")) {
7227 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7228 if (result != GST_AUTOPLUG_SELECT_TRY) {
7229 LOGW("skip add decoder");
7235 MMPLAYER_FREEIF(caps_str);
7241 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7244 //mmplayer_t *player = (mmplayer_t *)data;
7245 GstCaps *caps = NULL;
7247 LOGD("[Decodebin2] pad-removed signal");
7249 caps = gst_pad_query_caps(new_pad, NULL);
7251 LOGW("query caps is NULL");
7255 gchar *caps_str = NULL;
7256 caps_str = gst_caps_to_string(caps);
7258 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7260 MMPLAYER_FREEIF(caps_str);
7261 gst_caps_unref(caps);
7265 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7267 mmplayer_t *player = (mmplayer_t *)data;
7268 GstIterator *iter = NULL;
7269 GValue item = { 0, };
7271 gboolean done = FALSE;
7272 gboolean is_all_drained = TRUE;
7275 MMPLAYER_RETURN_IF_FAIL(player);
7277 LOGD("__mmplayer_gst_decode_drained");
7279 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7280 LOGW("Fail to get cmd lock");
7284 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7285 !__mmplayer_verify_gapless_play_path(player)) {
7286 LOGD("decoding is finished.");
7287 __mmplayer_reset_gapless_state(player);
7288 MMPLAYER_CMD_UNLOCK(player);
7292 player->gapless.reconfigure = TRUE;
7294 /* check decodebin src pads whether they received EOS or not */
7295 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7298 switch (gst_iterator_next(iter, &item)) {
7299 case GST_ITERATOR_OK:
7300 pad = g_value_get_object(&item);
7301 if (pad && !GST_PAD_IS_EOS(pad)) {
7302 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7303 is_all_drained = FALSE;
7306 g_value_reset(&item);
7308 case GST_ITERATOR_RESYNC:
7309 gst_iterator_resync(iter);
7311 case GST_ITERATOR_ERROR:
7312 case GST_ITERATOR_DONE:
7317 g_value_unset(&item);
7318 gst_iterator_free(iter);
7320 if (!is_all_drained) {
7321 LOGD("Wait util the all pads get EOS.");
7322 MMPLAYER_CMD_UNLOCK(player);
7327 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7328 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7330 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7331 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7332 __mmplayer_deactivate_old_path(player);
7333 MMPLAYER_CMD_UNLOCK(player);
7339 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7341 mmplayer_t *player = (mmplayer_t *)data;
7342 const gchar *klass = NULL;
7343 gchar *factory_name = NULL;
7345 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7346 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7348 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7350 if (__mmplayer_add_dump_buffer_probe(player, element))
7351 LOGD("add buffer probe");
7353 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7354 gchar *selected = NULL;
7355 selected = g_strdup(GST_ELEMENT_NAME(element));
7356 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7359 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7360 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7361 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7363 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7364 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7366 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7367 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7368 "max-video-width", player->adaptive_info.limit.width,
7369 "max-video-height", player->adaptive_info.limit.height, NULL);
7371 } else if (g_strrstr(klass, "Demuxer")) {
7372 //LOGD("plugged element is demuxer. take it");
7373 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7374 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7377 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7378 int surface_type = 0;
7380 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7383 // to support trust-zone only
7384 if (g_strrstr(factory_name, "asfdemux")) {
7385 LOGD("set file-location %s", player->profile.uri);
7386 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7387 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7388 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7389 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7390 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7391 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7392 (__mmplayer_is_only_mp3_type(player->type))) {
7393 LOGD("[mpegaudioparse] set streaming pull mode.");
7394 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7396 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7397 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7400 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7401 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7402 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7404 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7405 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7407 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7408 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7409 (MMPLAYER_IS_DASH_STREAMING(player))) {
7410 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7411 _mm_player_streaming_set_multiqueue(player->streamer, element);
7412 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7421 __mmplayer_release_misc(mmplayer_t *player)
7424 bool cur_mode = player->set_mode.rich_audio;
7427 MMPLAYER_RETURN_IF_FAIL(player);
7429 player->video_decoded_cb = NULL;
7430 player->video_decoded_cb_user_param = NULL;
7431 player->video_stream_prerolled = false;
7433 player->audio_decoded_cb = NULL;
7434 player->audio_decoded_cb_user_param = NULL;
7435 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7437 player->video_stream_changed_cb = NULL;
7438 player->video_stream_changed_cb_user_param = NULL;
7440 player->audio_stream_changed_cb = NULL;
7441 player->audio_stream_changed_cb_user_param = NULL;
7443 player->sent_bos = FALSE;
7444 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7446 player->seek_state = MMPLAYER_SEEK_NONE;
7448 player->total_bitrate = 0;
7449 player->total_maximum_bitrate = 0;
7451 player->not_found_demuxer = 0;
7453 player->last_position = 0;
7454 player->duration = 0;
7455 player->http_content_size = 0;
7456 player->not_supported_codec = MISSING_PLUGIN_NONE;
7457 player->can_support_codec = FOUND_PLUGIN_NONE;
7458 player->pending_seek.is_pending = false;
7459 player->pending_seek.pos = 0;
7460 player->msg_posted = FALSE;
7461 player->has_many_types = FALSE;
7462 player->is_subtitle_force_drop = FALSE;
7463 player->play_subtitle = FALSE;
7464 player->adjust_subtitle_pos = 0;
7465 player->has_closed_caption = FALSE;
7466 player->set_mode.video_export = false;
7467 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7468 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7470 player->set_mode.rich_audio = cur_mode;
7472 if (player->audio_device_cb_id > 0 &&
7473 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7474 LOGW("failed to remove audio device_connected_callback");
7475 player->audio_device_cb_id = 0;
7477 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7478 player->bitrate[i] = 0;
7479 player->maximum_bitrate[i] = 0;
7482 MMPLAYER_MEDIA_STREAM_CALLBACK_LOCK(player);
7484 /* remove media stream cb(appsrc cb) */
7485 for (i = 0; i < MM_PLAYER_STREAM_TYPE_MAX; i++) {
7486 player->media_stream_buffer_status_cb[i] = NULL;
7487 player->media_stream_seek_data_cb[i] = NULL;
7488 player->buffer_cb_user_param[i] = NULL;
7489 player->seek_cb_user_param[i] = NULL;
7491 MMPLAYER_MEDIA_STREAM_CALLBACK_UNLOCK(player);
7493 /* free memory related to audio effect */
7494 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7496 if (player->adaptive_info.var_list) {
7497 g_list_free_full(player->adaptive_info.var_list, g_free);
7498 player->adaptive_info.var_list = NULL;
7501 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7502 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7503 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7505 /* Reset video360 settings to their defaults in case if the pipeline is to be
7508 player->video360_metadata.is_spherical = -1;
7509 player->is_openal_plugin_used = FALSE;
7511 player->is_content_spherical = FALSE;
7512 player->is_video360_enabled = TRUE;
7513 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7514 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7515 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7516 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7517 player->video360_zoom = 1.0f;
7518 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7519 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7521 player->sound.rg_enable = false;
7523 __mmplayer_initialize_video_roi(player);
7528 __mmplayer_release_misc_post(mmplayer_t *player)
7530 char *original_uri = NULL;
7533 /* player->pipeline is already released before. */
7535 MMPLAYER_RETURN_IF_FAIL(player);
7537 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7539 /* clean found audio decoders */
7540 if (player->audio_decoders) {
7541 GList *a_dec = player->audio_decoders;
7542 for (; a_dec; a_dec = g_list_next(a_dec)) {
7543 gchar *name = a_dec->data;
7544 MMPLAYER_FREEIF(name);
7546 g_list_free(player->audio_decoders);
7547 player->audio_decoders = NULL;
7550 /* clean the uri list except original uri */
7551 if (player->uri_info.uri_list) {
7552 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7554 if (player->attrs) {
7555 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7556 LOGD("restore original uri = %s", original_uri);
7558 if (mm_attrs_commit_all(player->attrs))
7559 LOGE("failed to commit the original uri.");
7562 GList *uri_list = player->uri_info.uri_list;
7563 for (; uri_list; uri_list = g_list_next(uri_list)) {
7564 gchar *uri = uri_list->data;
7565 MMPLAYER_FREEIF(uri);
7567 g_list_free(player->uri_info.uri_list);
7568 player->uri_info.uri_list = NULL;
7571 /* clear the audio stream buffer list */
7572 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7574 /* clear the video stream bo list */
7575 __mmplayer_video_stream_destroy_bo_list(player);
7576 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7578 if (player->profile.input_mem.buf) {
7579 free(player->profile.input_mem.buf);
7580 player->profile.input_mem.buf = NULL;
7582 player->profile.input_mem.len = 0;
7583 player->profile.input_mem.offset = 0;
7585 player->uri_info.uri_idx = 0;
7590 __mmplayer_check_subtitle(mmplayer_t *player)
7592 MMHandleType attrs = 0;
7593 char *subtitle_uri = NULL;
7597 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7599 /* get subtitle attribute */
7600 attrs = MMPLAYER_GET_ATTRS(player);
7604 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7605 if (!subtitle_uri || !strlen(subtitle_uri))
7608 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7609 player->is_external_subtitle_present = TRUE;
7617 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7619 MMPLAYER_RETURN_IF_FAIL(player);
7621 if (player->eos_timer) {
7622 LOGD("cancel eos timer");
7623 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7624 player->eos_timer = 0;
7631 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7635 MMPLAYER_RETURN_IF_FAIL(player);
7636 MMPLAYER_RETURN_IF_FAIL(sink);
7638 player->sink_elements = g_list_append(player->sink_elements, sink);
7644 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7648 MMPLAYER_RETURN_IF_FAIL(player);
7649 MMPLAYER_RETURN_IF_FAIL(sink);
7651 player->sink_elements = g_list_remove(player->sink_elements, sink);
7657 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7658 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7660 mmplayer_signal_item_t *item = NULL;
7663 MMPLAYER_RETURN_IF_FAIL(player);
7665 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7666 LOGE("invalid signal type [%d]", type);
7670 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7672 LOGE("cannot connect signal [%s]", signal);
7677 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7678 player->signals[type] = g_list_append(player->signals[type], item);
7684 /* NOTE : be careful with calling this api. please refer to below glib comment
7685 * glib comment : Note that there is a bug in GObject that makes this function much
7686 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7687 * will no longer be called, but, the signal handler is not currently disconnected.
7688 * If the instance is itself being freed at the same time than this doesn't matter,
7689 * since the signal will automatically be removed, but if instance persists,
7690 * then the signal handler will leak. You should not remove the signal yourself
7691 * because in a future versions of GObject, the handler will automatically be
7694 * It's possible to work around this problem in a way that will continue to work
7695 * with future versions of GObject by checking that the signal handler is still
7696 * connected before disconnected it:
7698 * if (g_signal_handler_is_connected(instance, id))
7699 * g_signal_handler_disconnect(instance, id);
7702 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7704 GList *sig_list = NULL;
7705 mmplayer_signal_item_t *item = NULL;
7709 MMPLAYER_RETURN_IF_FAIL(player);
7711 LOGD("release signals type : %d", type);
7713 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7714 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7715 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7716 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7717 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7718 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7722 sig_list = player->signals[type];
7724 for (; sig_list; sig_list = sig_list->next) {
7725 item = sig_list->data;
7727 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7728 if (g_signal_handler_is_connected(item->obj, item->sig))
7729 g_signal_handler_disconnect(item->obj, item->sig);
7732 MMPLAYER_FREEIF(item);
7735 g_list_free(player->signals[type]);
7736 player->signals[type] = NULL;
7744 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7746 mmplayer_t *player = 0;
7747 int prev_display_surface_type = 0;
7748 void *prev_display_overlay = NULL;
7752 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7753 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7755 player = MM_PLAYER_CAST(handle);
7757 /* check video sinkbin is created */
7758 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7759 LOGE("Videosink is already created");
7760 return MM_ERROR_NONE;
7763 LOGD("videosink element is not yet ready");
7765 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7766 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7768 return MM_ERROR_INVALID_ARGUMENT;
7771 /* load previous attributes */
7772 if (player->attrs) {
7773 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7774 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7775 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7776 if (prev_display_surface_type == surface_type) {
7777 LOGD("incoming display surface type is same as previous one, do nothing..");
7779 return MM_ERROR_NONE;
7782 LOGE("failed to load attributes");
7784 return MM_ERROR_PLAYER_INTERNAL;
7787 /* videobin is not created yet, so we just set attributes related to display surface */
7788 LOGD("store display attribute for given surface type(%d)", surface_type);
7789 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7790 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7791 if (mm_attrs_commit_all(player->attrs)) {
7792 LOGE("failed to commit attribute");
7794 return MM_ERROR_PLAYER_INTERNAL;
7798 return MM_ERROR_NONE;
7801 /* Note : if silent is true, then subtitle would not be displayed. :*/
7803 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7805 mmplayer_t *player = (mmplayer_t *)hplayer;
7809 /* check player handle */
7810 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7812 player->set_mode.subtitle_off = silent;
7814 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7818 return MM_ERROR_NONE;
7822 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7824 mmplayer_gst_element_t *mainbin = NULL;
7825 mmplayer_gst_element_t *textbin = NULL;
7826 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7827 GstState current_state = GST_STATE_VOID_PENDING;
7828 GstState element_state = GST_STATE_VOID_PENDING;
7829 GstState element_pending_state = GST_STATE_VOID_PENDING;
7831 GstEvent *event = NULL;
7832 int result = MM_ERROR_NONE;
7834 GstClock *curr_clock = NULL;
7835 GstClockTime base_time, start_time, curr_time;
7840 /* check player handle */
7841 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7843 player->pipeline->mainbin &&
7844 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7846 mainbin = player->pipeline->mainbin;
7847 textbin = player->pipeline->textbin;
7849 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7851 // sync clock with current pipeline
7852 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7853 curr_time = gst_clock_get_time(curr_clock);
7855 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7856 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7858 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7859 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7861 if (current_state > GST_STATE_READY) {
7862 // sync state with current pipeline
7863 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7864 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7865 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7867 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7868 if (GST_STATE_CHANGE_FAILURE == ret) {
7869 LOGE("fail to state change.");
7870 result = MM_ERROR_PLAYER_INTERNAL;
7874 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7875 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7878 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7879 gst_object_unref(curr_clock);
7882 // seek to current position
7883 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7884 result = MM_ERROR_PLAYER_INVALID_STATE;
7885 LOGE("gst_element_query_position failed, invalid state");
7889 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7890 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);
7892 _mmplayer_gst_send_event_to_sink(player, event);
7894 result = MM_ERROR_PLAYER_INTERNAL;
7895 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7899 /* sync state with current pipeline */
7900 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7901 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7902 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7904 return MM_ERROR_NONE;
7907 /* release text pipeline resource */
7908 player->textsink_linked = 0;
7910 /* release signal */
7911 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7913 /* release textbin with it's childs */
7914 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7915 MMPLAYER_FREEIF(player->pipeline->textbin);
7916 player->pipeline->textbin = NULL;
7918 /* release subtitle elem */
7919 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7920 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7926 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7928 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7929 GstState current_state = GST_STATE_VOID_PENDING;
7931 MMHandleType attrs = 0;
7932 mmplayer_gst_element_t *mainbin = NULL;
7933 mmplayer_gst_element_t *textbin = NULL;
7935 gchar *subtitle_uri = NULL;
7936 int result = MM_ERROR_NONE;
7937 const gchar *charset = NULL;
7941 /* check player handle */
7942 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7944 player->pipeline->mainbin &&
7945 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7946 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7948 mainbin = player->pipeline->mainbin;
7949 textbin = player->pipeline->textbin;
7951 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7952 if (current_state < GST_STATE_READY) {
7953 result = MM_ERROR_PLAYER_INVALID_STATE;
7954 LOGE("Pipeline is not in proper state");
7958 attrs = MMPLAYER_GET_ATTRS(player);
7960 LOGE("cannot get content attribute");
7961 result = MM_ERROR_PLAYER_INTERNAL;
7965 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7966 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7967 LOGE("subtitle uri is not proper filepath");
7968 result = MM_ERROR_PLAYER_INVALID_URI;
7972 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7973 LOGE("failed to get storage info of subtitle path");
7974 result = MM_ERROR_PLAYER_INVALID_URI;
7978 LOGD("old subtitle file path is [%s]", subtitle_uri);
7979 LOGD("new subtitle file path is [%s]", filepath);
7981 if (!strcmp(filepath, subtitle_uri)) {
7982 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7985 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7986 if (mm_attrs_commit_all(player->attrs)) {
7987 LOGE("failed to commit.");
7992 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7993 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7994 player->subtitle_language_list = NULL;
7995 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7997 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7998 if (ret != GST_STATE_CHANGE_SUCCESS) {
7999 LOGE("failed to change state of textbin to READY");
8000 result = MM_ERROR_PLAYER_INTERNAL;
8004 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8005 if (ret != GST_STATE_CHANGE_SUCCESS) {
8006 LOGE("failed to change state of subparse to READY");
8007 result = MM_ERROR_PLAYER_INTERNAL;
8011 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8012 if (ret != GST_STATE_CHANGE_SUCCESS) {
8013 LOGE("failed to change state of filesrc to READY");
8014 result = MM_ERROR_PLAYER_INTERNAL;
8018 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8020 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8022 charset = _mmplayer_get_charset(filepath);
8024 LOGD("detected charset is %s", charset);
8025 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8028 result = _mmplayer_sync_subtitle_pipeline(player);
8035 /* API to switch between external subtitles */
8037 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8039 int result = MM_ERROR_NONE;
8040 mmplayer_t *player = (mmplayer_t *)hplayer;
8045 /* check player handle */
8046 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8048 /* filepath can be null in idle state */
8050 /* check file path */
8051 if ((path = strstr(filepath, "file://")))
8052 result = _mmplayer_exist_file_path(path + 7);
8054 result = _mmplayer_exist_file_path(filepath);
8056 if (result != MM_ERROR_NONE) {
8057 LOGE("invalid subtitle path 0x%X", result);
8058 return result; /* file not found or permission denied */
8062 if (!player->pipeline) {
8064 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8065 if (mm_attrs_commit_all(player->attrs)) {
8066 LOGE("failed to commit"); /* subtitle path will not be created */
8067 return MM_ERROR_PLAYER_INTERNAL;
8070 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8071 /* check filepath */
8072 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8074 if (!__mmplayer_check_subtitle(player)) {
8075 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8076 if (mm_attrs_commit_all(player->attrs)) {
8077 LOGE("failed to commit");
8078 return MM_ERROR_PLAYER_INTERNAL;
8081 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8082 LOGE("fail to create text pipeline");
8083 return MM_ERROR_PLAYER_INTERNAL;
8086 result = _mmplayer_sync_subtitle_pipeline(player);
8088 result = __mmplayer_change_external_subtitle_language(player, filepath);
8091 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8092 player->is_external_subtitle_added_now = TRUE;
8094 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8095 if (!player->subtitle_language_list) {
8096 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8097 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8098 LOGW("subtitle language list is not updated yet");
8100 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8108 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8110 int result = MM_ERROR_NONE;
8111 gchar *change_pad_name = NULL;
8112 GstPad *sinkpad = NULL;
8113 mmplayer_gst_element_t *mainbin = NULL;
8114 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8115 GstCaps *caps = NULL;
8116 gint total_track_num = 0;
8120 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8121 MM_ERROR_PLAYER_NOT_INITIALIZED);
8123 LOGD("Change Track(%d) to %d", type, index);
8125 mainbin = player->pipeline->mainbin;
8127 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8128 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8129 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8130 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8132 /* Changing Video Track is not supported. */
8133 LOGE("Track Type Error");
8137 if (mainbin[elem_idx].gst == NULL) {
8138 result = MM_ERROR_PLAYER_NO_OP;
8139 LOGD("Req track doesn't exist");
8143 total_track_num = player->selector[type].total_track_num;
8144 if (total_track_num <= 0) {
8145 result = MM_ERROR_PLAYER_NO_OP;
8146 LOGD("Language list is not available");
8150 if ((index < 0) || (index >= total_track_num)) {
8151 result = MM_ERROR_INVALID_ARGUMENT;
8152 LOGD("Not a proper index : %d", index);
8156 /*To get the new pad from the selector*/
8157 change_pad_name = g_strdup_printf("sink_%u", index);
8158 if (change_pad_name == NULL) {
8159 result = MM_ERROR_PLAYER_INTERNAL;
8160 LOGD("Pad does not exists");
8164 LOGD("new active pad name: %s", change_pad_name);
8166 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8167 if (sinkpad == NULL) {
8168 LOGD("sinkpad is NULL");
8169 result = MM_ERROR_PLAYER_INTERNAL;
8173 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8174 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8176 caps = gst_pad_get_current_caps(sinkpad);
8177 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8180 gst_object_unref(sinkpad);
8182 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8183 __mmplayer_set_audio_attrs(player, caps);
8186 MMPLAYER_FREEIF(change_pad_name);
8191 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8193 int result = MM_ERROR_NONE;
8194 mmplayer_t *player = NULL;
8195 mmplayer_gst_element_t *mainbin = NULL;
8197 gint current_active_index = 0;
8199 GstState current_state = GST_STATE_VOID_PENDING;
8200 GstEvent *event = NULL;
8205 player = (mmplayer_t *)hplayer;
8206 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8208 if (!player->pipeline) {
8209 LOGE("Track %d pre setting -> %d", type, index);
8211 player->selector[type].active_pad_index = index;
8215 mainbin = player->pipeline->mainbin;
8217 current_active_index = player->selector[type].active_pad_index;
8219 /*If index is same as running index no need to change the pad*/
8220 if (current_active_index == index)
8223 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8224 result = MM_ERROR_PLAYER_INVALID_STATE;
8228 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8229 if (current_state < GST_STATE_PAUSED) {
8230 result = MM_ERROR_PLAYER_INVALID_STATE;
8231 LOGW("Pipeline not in porper state");
8235 result = __mmplayer_change_selector_pad(player, type, index);
8236 if (result != MM_ERROR_NONE) {
8237 LOGE("change selector pad error");
8241 player->selector[type].active_pad_index = index;
8243 if (current_state == GST_STATE_PLAYING) {
8244 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8245 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8246 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8248 _mmplayer_gst_send_event_to_sink(player, event);
8250 result = MM_ERROR_PLAYER_INTERNAL;
8260 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8262 mmplayer_t *player = (mmplayer_t *)hplayer;
8266 /* check player handle */
8267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8269 *silent = player->set_mode.subtitle_off;
8271 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8275 return MM_ERROR_NONE;
8279 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8281 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8282 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8284 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8285 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8289 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8290 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8291 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8292 mmplayer_dump_t *dump_s;
8293 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8294 if (dump_s == NULL) {
8295 LOGE("malloc fail");
8299 dump_s->dump_element_file = NULL;
8300 dump_s->dump_pad = NULL;
8301 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8303 if (dump_s->dump_pad) {
8304 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8305 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]);
8306 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8307 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);
8308 /* add list for removed buffer probe and close FILE */
8309 player->dump_list = g_list_append(player->dump_list, dump_s);
8310 LOGD("%s sink pad added buffer probe for dump", factory_name);
8313 MMPLAYER_FREEIF(dump_s);
8314 LOGE("failed to get %s sink pad added", factory_name);
8321 static GstPadProbeReturn
8322 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8324 FILE *dump_data = (FILE *)u_data;
8326 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8327 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8329 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8331 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8333 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8335 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8337 gst_buffer_unmap(buffer, &probe_info);
8339 return GST_PAD_PROBE_OK;
8343 __mmplayer_release_dump_list(GList *dump_list)
8345 GList *d_list = dump_list;
8350 for (; d_list; d_list = g_list_next(d_list)) {
8351 mmplayer_dump_t *dump_s = d_list->data;
8352 if (dump_s->dump_pad) {
8353 if (dump_s->probe_handle_id)
8354 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8355 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8357 if (dump_s->dump_element_file) {
8358 fclose(dump_s->dump_element_file);
8359 dump_s->dump_element_file = NULL;
8361 MMPLAYER_FREEIF(dump_s);
8363 g_list_free(dump_list);
8368 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8370 mmplayer_t *player = (mmplayer_t *)hplayer;
8374 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8375 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8377 *exist = (bool)player->has_closed_caption;
8381 return MM_ERROR_NONE;
8385 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8389 // LOGD("unref internal gst buffer %p", buffer);
8390 gst_buffer_unref((GstBuffer *)buffer);
8397 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8399 mmplayer_t *player = (mmplayer_t *)hplayer;
8403 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8404 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8406 if (MMPLAYER_IS_STREAMING(player))
8407 *timeout = (int)player->ini.live_state_change_timeout;
8409 *timeout = (int)player->ini.localplayback_state_change_timeout;
8411 LOGD("timeout = %d", *timeout);
8414 return MM_ERROR_NONE;
8418 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8422 MMPLAYER_RETURN_IF_FAIL(player);
8424 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8426 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8427 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8428 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8429 player->storage_info[i].id = -1;
8430 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8432 if (path_type != MMPLAYER_PATH_MAX)
8441 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8443 int ret = MM_ERROR_NONE;
8444 mmplayer_t *player = (mmplayer_t *)hplayer;
8445 MMMessageParamType msg_param = {0, };
8448 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8450 LOGW("state changed storage %d:%d", id, state);
8452 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8453 return MM_ERROR_NONE;
8455 /* FIXME: text path should be handled seperately. */
8456 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8457 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8458 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8459 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8460 LOGW("external storage is removed");
8462 if (player->msg_posted == FALSE) {
8463 memset(&msg_param, 0, sizeof(MMMessageParamType));
8464 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8465 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8466 player->msg_posted = TRUE;
8469 /* unrealize the player */
8470 ret = _mmplayer_unrealize(hplayer);
8471 if (ret != MM_ERROR_NONE)
8472 LOGE("failed to unrealize");
8480 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8482 int ret = MM_ERROR_NONE;
8483 mmplayer_t *player = (mmplayer_t *)hplayer;
8484 int idx = 0, total = 0;
8485 gchar *result = NULL, *tmp = NULL;
8488 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8489 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8491 total = *num = g_list_length(player->adaptive_info.var_list);
8493 LOGW("There is no stream variant info.");
8497 result = g_strdup("");
8498 for (idx = 0 ; idx < total ; idx++) {
8499 stream_variant_t *v_data = NULL;
8500 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8503 gchar data[64] = {0};
8504 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8506 tmp = g_strconcat(result, data, NULL);
8510 LOGW("There is no variant data in %d", idx);
8515 *var_info = (char *)result;
8517 LOGD("variant info %d:%s", *num, *var_info);
8523 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8525 int ret = MM_ERROR_NONE;
8526 mmplayer_t *player = (mmplayer_t *)hplayer;
8529 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8531 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8533 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8534 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8535 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8537 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8538 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8539 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8540 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8542 /* FIXME: seek to current position for applying new variant limitation */
8551 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8553 int ret = MM_ERROR_NONE;
8554 mmplayer_t *player = (mmplayer_t *)hplayer;
8557 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8558 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8560 *bandwidth = player->adaptive_info.limit.bandwidth;
8561 *width = player->adaptive_info.limit.width;
8562 *height = player->adaptive_info.limit.height;
8564 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8571 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8573 int ret = MM_ERROR_NONE;
8574 mmplayer_t *player = (mmplayer_t *)hplayer;
8577 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8578 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8579 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8581 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8583 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8584 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8585 else /* live case */
8586 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8588 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8595 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8597 #define IDX_FIRST_SW_CODEC 0
8598 mmplayer_t *player = (mmplayer_t *)hplayer;
8599 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8600 MMHandleType attrs = 0;
8603 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8605 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8606 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8607 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8609 switch (stream_type) {
8610 case MM_PLAYER_STREAM_TYPE_AUDIO:
8611 /* to support audio codec selection, codec info have to be added in ini file as below.
8612 audio codec element hw = xxxx
8613 audio codec element sw = avdec */
8614 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8615 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8616 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8617 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8618 LOGE("There is no audio codec info for codec_type %d", codec_type);
8619 return MM_ERROR_PLAYER_NO_OP;
8622 case MM_PLAYER_STREAM_TYPE_VIDEO:
8623 /* to support video codec selection, codec info have to be added in ini file as below.
8624 video codec element hw = omx
8625 video codec element sw = avdec */
8626 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8627 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8628 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8629 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8630 LOGE("There is no video codec info for codec_type %d", codec_type);
8631 return MM_ERROR_PLAYER_NO_OP;
8635 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8636 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8640 LOGD("update %s codec_type to %d", attr_name, codec_type);
8642 attrs = MMPLAYER_GET_ATTRS(player);
8643 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8645 if (mm_attrs_commit_all(player->attrs)) {
8646 LOGE("failed to commit codec_type attributes");
8647 return MM_ERROR_PLAYER_INTERNAL;
8651 return MM_ERROR_NONE;
8655 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8657 mmplayer_t *player = (mmplayer_t *)hplayer;
8658 GstElement *rg_vol_element = NULL;
8662 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8664 player->sound.rg_enable = enabled;
8666 /* just hold rgvolume enable value if pipeline is not ready */
8667 if (!player->pipeline || !player->pipeline->audiobin) {
8668 LOGD("pipeline is not ready. holding rgvolume enable value");
8669 return MM_ERROR_NONE;
8672 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8674 if (!rg_vol_element) {
8675 LOGD("rgvolume element is not created");
8676 return MM_ERROR_PLAYER_INTERNAL;
8680 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8682 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8686 return MM_ERROR_NONE;
8690 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8692 mmplayer_t *player = (mmplayer_t *)hplayer;
8693 GstElement *rg_vol_element = NULL;
8694 gboolean enable = FALSE;
8698 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8699 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8701 /* just hold enable_rg value if pipeline is not ready */
8702 if (!player->pipeline || !player->pipeline->audiobin) {
8703 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8704 *enabled = player->sound.rg_enable;
8705 return MM_ERROR_NONE;
8708 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8710 if (!rg_vol_element) {
8711 LOGD("rgvolume element is not created");
8712 return MM_ERROR_PLAYER_INTERNAL;
8715 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8716 *enabled = (bool)enable;
8720 return MM_ERROR_NONE;
8724 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8726 mmplayer_t *player = (mmplayer_t *)hplayer;
8727 MMHandleType attrs = 0;
8728 void *handle = NULL;
8729 int ret = MM_ERROR_NONE;
8733 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8735 attrs = MMPLAYER_GET_ATTRS(player);
8736 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8738 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8740 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8741 return MM_ERROR_PLAYER_INTERNAL;
8744 player->video_roi.scale_x = scale_x;
8745 player->video_roi.scale_y = scale_y;
8746 player->video_roi.scale_width = scale_width;
8747 player->video_roi.scale_height = scale_height;
8749 /* check video sinkbin is created */
8750 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8751 return MM_ERROR_NONE;
8753 if (!gst_video_overlay_set_video_roi_area(
8754 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8755 scale_x, scale_y, scale_width, scale_height))
8756 ret = MM_ERROR_PLAYER_INTERNAL;
8758 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8759 scale_x, scale_y, scale_width, scale_height);
8767 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8769 mmplayer_t *player = (mmplayer_t *)hplayer;
8770 int ret = MM_ERROR_NONE;
8774 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8775 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8777 *scale_x = player->video_roi.scale_x;
8778 *scale_y = player->video_roi.scale_y;
8779 *scale_width = player->video_roi.scale_width;
8780 *scale_height = player->video_roi.scale_height;
8782 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8783 *scale_x, *scale_y, *scale_width, *scale_height);
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, "content_video_width", width);
8912 gst_structure_get_int(p, "height", &height);
8913 mm_attrs_set_int_by_name(attrs, "content_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, "content_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, "content_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, "content_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");