4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
214 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
218 count = gst_tag_list_get_tag_size(list, tag);
220 LOGD("count = %d", count);
222 for (i = 0; i < count; i++) {
225 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
226 if (!gst_tag_list_get_string_index(list, tag, i, &str))
227 g_assert_not_reached();
229 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
233 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
235 g_print(" : %s", str);
242 /* This function should be called after the pipeline goes PAUSED or higher
245 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
247 static gboolean has_duration = FALSE;
248 static gboolean has_video_attrs = FALSE;
249 static gboolean has_audio_attrs = FALSE;
250 static gboolean has_bitrate = FALSE;
251 gboolean missing_only = FALSE;
252 gboolean all = FALSE;
253 MMHandleType attrs = 0;
257 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
259 /* check player state here */
260 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
261 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
262 /* give warning now only */
263 LOGW("be careful. content attributes may not available in this state ");
266 /* get content attribute first */
267 attrs = MMPLAYER_GET_ATTRS(player);
269 LOGE("cannot get content attribute");
273 /* get update flag */
275 if (flag & ATTR_MISSING_ONLY) {
277 LOGD("updating missed attr only");
280 if (flag & ATTR_ALL) {
282 has_duration = FALSE;
283 has_video_attrs = FALSE;
284 has_audio_attrs = FALSE;
287 LOGD("updating all attrs");
290 if (missing_only && all) {
291 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
292 missing_only = FALSE;
295 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
296 has_duration = __mmplayer_update_duration_value(player);
298 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
299 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
301 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
302 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
304 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
305 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
308 if (mm_attrs_commit_all(attrs)) {
309 LOGE("failed to update attributes");
319 _mmplayer_get_stream_service_type(mmplayer_t *player)
321 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
325 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
327 player->pipeline->mainbin &&
328 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
329 STREAMING_SERVICE_NONE);
331 /* streaming service type if streaming */
332 if (!MMPLAYER_IS_STREAMING(player))
333 return STREAMING_SERVICE_NONE;
335 streaming_type = (player->duration == 0) ?
336 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
338 switch (streaming_type) {
339 case STREAMING_SERVICE_LIVE:
340 LOGD("it's live streaming");
342 case STREAMING_SERVICE_VOD:
343 LOGD("it's vod streaming");
346 LOGE("should not get here");
352 return streaming_type;
355 /* this function sets the player state and also report
356 * it to applicaton by calling callback function
359 _mmplayer_set_state(mmplayer_t *player, int state)
361 MMMessageParamType msg = {0, };
363 MMPLAYER_RETURN_IF_FAIL(player);
365 if (MMPLAYER_CURRENT_STATE(player) == state) {
366 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
367 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
371 /* update player states */
372 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
373 MMPLAYER_CURRENT_STATE(player) = state;
375 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
376 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
379 MMPLAYER_PRINT_STATE(player);
381 switch (MMPLAYER_CURRENT_STATE(player)) {
382 case MM_PLAYER_STATE_NULL:
383 case MM_PLAYER_STATE_READY:
385 case MM_PLAYER_STATE_PAUSED:
386 __mmplayer_set_pause_state(player);
388 case MM_PLAYER_STATE_PLAYING:
389 __mmplayer_set_playing_state(player);
391 case MM_PLAYER_STATE_NONE:
393 LOGW("invalid target state, there is nothing to do.");
398 /* post message to application */
399 if (MMPLAYER_TARGET_STATE(player) == state) {
400 /* fill the message with state of player */
401 msg.union_type = MM_MSG_UNION_STATE;
402 msg.state.previous = MMPLAYER_PREV_STATE(player);
403 msg.state.current = MMPLAYER_CURRENT_STATE(player);
405 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
407 /* state changed by resource callback */
408 if (player->interrupted_by_resource)
409 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
410 else /* state changed by usecase */
411 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
414 LOGD("intermediate state, do nothing.");
415 MMPLAYER_PRINT_STATE(player);
419 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
420 && !player->sent_bos) {
421 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
422 player->sent_bos = TRUE;
429 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
431 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
432 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
434 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
436 //LOGD("incomming command : %d ", command);
438 current_state = MMPLAYER_CURRENT_STATE(player);
439 pending_state = MMPLAYER_PENDING_STATE(player);
441 MMPLAYER_PRINT_STATE(player);
444 case MMPLAYER_COMMAND_CREATE:
446 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
448 if (current_state == MM_PLAYER_STATE_NULL ||
449 current_state == MM_PLAYER_STATE_READY ||
450 current_state == MM_PLAYER_STATE_PAUSED ||
451 current_state == MM_PLAYER_STATE_PLAYING)
456 case MMPLAYER_COMMAND_DESTROY:
458 /* destroy can called anytime */
460 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
464 case MMPLAYER_COMMAND_REALIZE:
466 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
468 if (pending_state != MM_PLAYER_STATE_NONE) {
471 /* need ready state to realize */
472 if (current_state == MM_PLAYER_STATE_READY)
475 if (current_state != MM_PLAYER_STATE_NULL)
481 case MMPLAYER_COMMAND_UNREALIZE:
483 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
485 if (current_state == MM_PLAYER_STATE_NULL)
490 case MMPLAYER_COMMAND_START:
492 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
494 if (pending_state == MM_PLAYER_STATE_NONE) {
495 if (current_state == MM_PLAYER_STATE_PLAYING)
497 else if (current_state != MM_PLAYER_STATE_READY &&
498 current_state != MM_PLAYER_STATE_PAUSED)
500 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
502 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
503 LOGD("player is going to paused state, just change the pending state as playing");
510 case MMPLAYER_COMMAND_STOP:
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
514 if (current_state == MM_PLAYER_STATE_READY)
517 /* need playing/paused state to stop */
518 if (current_state != MM_PLAYER_STATE_PLAYING &&
519 current_state != MM_PLAYER_STATE_PAUSED)
524 case MMPLAYER_COMMAND_PAUSE:
526 if (MMPLAYER_IS_LIVE_STREAMING(player))
529 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
530 goto NOT_COMPLETED_SEEK;
532 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
534 if (pending_state == MM_PLAYER_STATE_NONE) {
535 if (current_state == MM_PLAYER_STATE_PAUSED)
537 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
539 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
541 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
542 if (current_state == MM_PLAYER_STATE_PAUSED)
543 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
550 case MMPLAYER_COMMAND_RESUME:
552 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
553 goto NOT_COMPLETED_SEEK;
555 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
557 if (pending_state == MM_PLAYER_STATE_NONE) {
558 if (current_state == MM_PLAYER_STATE_PLAYING)
560 else if (current_state != MM_PLAYER_STATE_PAUSED)
562 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
564 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
565 LOGD("player is going to paused state, just change the pending state as playing");
575 player->cmd = command;
577 return MM_ERROR_NONE;
580 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
581 MMPLAYER_STATE_GET_NAME(current_state), command);
582 return MM_ERROR_PLAYER_INVALID_STATE;
585 LOGW("not completed seek");
586 return MM_ERROR_PLAYER_DOING_SEEK;
589 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
590 return MM_ERROR_PLAYER_NO_OP;
593 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
594 return MM_ERROR_PLAYER_NO_OP;
597 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
599 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
600 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
603 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
604 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
606 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
607 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
610 LOGE("invalid mmplayer resource type %d", type);
611 return MM_ERROR_PLAYER_INTERNAL;
614 if (player->hw_resource[type] != NULL) {
615 LOGD("[%d type] resource was already acquired", type);
616 return MM_ERROR_NONE;
619 LOGD("mark for acquire [%d type] resource", type);
620 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
621 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
622 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
623 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
624 return MM_ERROR_PLAYER_INTERNAL;
627 rm_ret = mm_resource_manager_commit(player->resource_manager);
628 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
629 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
630 return MM_ERROR_PLAYER_INTERNAL;
634 return MM_ERROR_NONE;
637 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
639 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
643 if (player->hw_resource[type] == NULL) {
644 LOGD("there is no acquired [%d type] resource", type);
645 return MM_ERROR_NONE;
648 LOGD("mark for release [%d type] resource", type);
649 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
650 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
651 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
652 return MM_ERROR_PLAYER_INTERNAL;
655 player->hw_resource[type] = NULL;
657 rm_ret = mm_resource_manager_commit(player->resource_manager);
658 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
659 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
660 return MM_ERROR_PLAYER_INTERNAL;
664 return MM_ERROR_NONE;
668 __mmplayer_initialize_gapless_play(mmplayer_t *player)
674 player->smooth_streaming = FALSE;
675 player->videodec_linked = 0;
676 player->audiodec_linked = 0;
677 player->textsink_linked = 0;
678 player->is_external_subtitle_present = FALSE;
679 player->is_external_subtitle_added_now = FALSE;
680 player->not_supported_codec = MISSING_PLUGIN_NONE;
681 player->can_support_codec = FOUND_PLUGIN_NONE;
682 player->pending_seek.is_pending = false;
683 player->pending_seek.pos = 0;
684 player->msg_posted = FALSE;
685 player->has_many_types = FALSE;
686 player->no_more_pad = FALSE;
687 player->not_found_demuxer = 0;
688 player->seek_state = MMPLAYER_SEEK_NONE;
689 player->is_subtitle_force_drop = FALSE;
690 player->play_subtitle = FALSE;
691 player->adjust_subtitle_pos = 0;
693 player->total_bitrate = 0;
694 player->total_maximum_bitrate = 0;
696 _mmplayer_track_initialize(player);
697 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
699 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
700 player->bitrate[i] = 0;
701 player->maximum_bitrate[i] = 0;
704 if (player->v_stream_caps) {
705 gst_caps_unref(player->v_stream_caps);
706 player->v_stream_caps = NULL;
709 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
711 /* clean found audio decoders */
712 if (player->audio_decoders) {
713 GList *a_dec = player->audio_decoders;
714 for (; a_dec; a_dec = g_list_next(a_dec)) {
715 gchar *name = a_dec->data;
716 MMPLAYER_FREEIF(name);
718 g_list_free(player->audio_decoders);
719 player->audio_decoders = NULL;
722 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
728 __mmplayer_gapless_play_thread(gpointer data)
730 mmplayer_t *player = (mmplayer_t *)data;
731 mmplayer_gst_element_t *mainbin = NULL;
733 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
735 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
736 while (!player->gapless_play_thread_exit) {
737 LOGD("gapless play thread started. waiting for signal.");
738 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
740 LOGD("reconfigure pipeline for gapless play.");
742 if (player->gapless_play_thread_exit) {
743 if (player->gapless.reconfigure) {
744 player->gapless.reconfigure = false;
745 MMPLAYER_PLAYBACK_UNLOCK(player);
747 LOGD("exiting gapless play thread");
751 mainbin = player->pipeline->mainbin;
753 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
754 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
755 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
756 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
757 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
759 /* Initialize Player values */
760 __mmplayer_initialize_gapless_play(player);
762 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
764 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
770 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
772 GSource *source = NULL;
776 source = g_main_context_find_source_by_id(context, source_id);
777 if (source != NULL) {
778 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
779 g_source_destroy(source);
786 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
788 mmplayer_t *player = (mmplayer_t *)hplayer;
789 GstMessage *msg = NULL;
790 GQueue *queue = NULL;
793 MMPLAYER_RETURN_IF_FAIL(player);
795 /* disconnecting bus watch */
796 if (player->bus_watcher)
797 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
798 player->bus_watcher = 0;
800 /* destroy the gst bus msg thread */
801 if (player->bus_msg_thread) {
802 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
803 player->bus_msg_thread_exit = TRUE;
804 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
805 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
807 LOGD("gst bus msg thread exit.");
808 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
809 player->bus_msg_thread = NULL;
811 g_mutex_clear(&player->bus_msg_thread_mutex);
812 g_cond_clear(&player->bus_msg_thread_cond);
815 g_mutex_lock(&player->bus_msg_q_lock);
816 queue = player->bus_msg_q;
817 while (!g_queue_is_empty(queue)) {
818 msg = (GstMessage *)g_queue_pop_head(queue);
823 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
824 gst_message_unref(msg);
826 g_mutex_unlock(&player->bus_msg_q_lock);
832 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
834 GstElement *parent = NULL;
836 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
837 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
840 MMPLAYER_FSINK_LOCK(player);
842 /* get parent of fakesink */
843 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
845 LOGD("fakesink already removed");
849 gst_element_set_locked_state(fakesink->gst, TRUE);
851 /* setting the state to NULL never returns async
852 * so no need to wait for completion of state transiton
854 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
855 LOGE("fakesink state change failure!");
856 /* FIXIT : should I return here? or try to proceed to next? */
859 /* remove fakesink from it's parent */
860 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
861 LOGE("failed to remove fakesink");
863 gst_object_unref(parent);
868 gst_object_unref(parent);
870 LOGD("state-holder removed");
872 gst_element_set_locked_state(fakesink->gst, FALSE);
874 MMPLAYER_FSINK_UNLOCK(player);
879 gst_element_set_locked_state(fakesink->gst, FALSE);
881 MMPLAYER_FSINK_UNLOCK(player);
885 static GstPadProbeReturn
886 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
888 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
889 return GST_PAD_PROBE_OK;
893 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
895 gint64 stop_running_time = 0;
896 gint64 position_running_time = 0;
900 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
901 if ((player->gapless.update_segment[idx] == TRUE) ||
902 !(player->selector[idx].event_probe_id)) {
903 /* LOGW("[%d] skip", idx); */
907 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
909 gst_segment_to_running_time(&player->gapless.segment[idx],
910 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
911 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
913 gst_segment_to_running_time(&player->gapless.segment[idx],
914 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
916 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
918 gst_segment_to_running_time(&player->gapless.segment[idx],
919 GST_FORMAT_TIME, player->duration);
922 position_running_time =
923 gst_segment_to_running_time(&player->gapless.segment[idx],
924 GST_FORMAT_TIME, player->gapless.segment[idx].position);
926 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
927 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
929 GST_TIME_ARGS(stop_running_time),
930 GST_TIME_ARGS(position_running_time),
931 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
932 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
934 position_running_time = MAX(position_running_time, stop_running_time);
935 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
936 GST_FORMAT_TIME, player->gapless.segment[idx].start);
937 position_running_time = MAX(0, position_running_time);
938 position = MAX(position, position_running_time);
942 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
943 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
944 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
946 player->gapless.start_time[stream_type] += position;
952 static GstPadProbeReturn
953 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
955 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
956 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
957 mmplayer_t *player = (mmplayer_t *)data;
958 GstCaps *caps = NULL;
959 GstStructure *str = NULL;
960 const gchar *name = NULL;
961 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
962 gboolean caps_ret = TRUE;
964 if (GST_EVENT_IS_DOWNSTREAM(event) &&
965 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
966 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
967 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
968 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
970 } else if (GST_EVENT_IS_UPSTREAM(event) &&
971 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
975 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
979 if (strstr(name, "audio")) {
980 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
981 } else if (strstr(name, "video")) {
982 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
984 /* text track is not supportable */
985 LOGE("invalid name %s", name);
989 switch (GST_EVENT_TYPE(event)) {
992 /* in case of gapless, drop eos event not to send it to sink */
993 if (player->gapless.reconfigure && !player->msg_posted) {
994 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
995 ret = GST_PAD_PROBE_DROP;
999 case GST_EVENT_STREAM_START:
1001 __mmplayer_gst_selector_update_start_time(player, stream_type);
1004 case GST_EVENT_FLUSH_STOP:
1006 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1007 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1008 player->gapless.start_time[stream_type] = 0;
1011 case GST_EVENT_SEGMENT:
1016 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1017 gst_event_copy_segment(event, &segment);
1019 if (segment.format != GST_FORMAT_TIME)
1022 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1023 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1024 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1025 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1026 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1027 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1029 /* keep the all the segment ev to cover the seeking */
1030 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1031 player->gapless.update_segment[stream_type] = TRUE;
1033 if (!player->gapless.running)
1036 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1038 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1040 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1041 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1042 gst_event_unref(event);
1043 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1049 gdouble proportion = 0.0;
1050 GstClockTimeDiff diff = 0;
1051 GstClockTime timestamp = 0;
1052 gint64 running_time_diff = -1;
1053 GstQOSType type = 0;
1054 GstEvent *tmpev = NULL;
1056 running_time_diff = player->gapless.segment[stream_type].base;
1058 if (running_time_diff <= 0) /* don't need to adjust */
1061 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1062 gst_event_unref(event);
1064 if (timestamp < running_time_diff) {
1065 LOGW("QOS event from previous group");
1066 ret = GST_PAD_PROBE_DROP;
1070 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1071 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1072 stream_type, GST_TIME_ARGS(timestamp),
1073 GST_TIME_ARGS(running_time_diff),
1074 GST_TIME_ARGS(timestamp - running_time_diff));
1076 timestamp -= running_time_diff;
1078 /* That case is invalid for QoS events */
1079 if (diff < 0 && -diff > timestamp) {
1080 LOGW("QOS event from previous group");
1081 ret = GST_PAD_PROBE_DROP;
1085 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1086 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1096 gst_caps_unref(caps);
1100 /* create fakesink for audio or video path witout audiobin or videobin */
1102 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1104 GstElement *pipeline = NULL;
1105 GstElement *fakesink = NULL;
1106 GstPad *sinkpad = NULL;
1109 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1111 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1114 fakesink = gst_element_factory_make("fakesink", NULL);
1115 if (fakesink == NULL) {
1116 LOGE("failed to create fakesink");
1120 /* store it as it's sink element */
1121 __mmplayer_add_sink(player, fakesink);
1123 gst_bin_add(GST_BIN(pipeline), fakesink);
1126 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1128 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1130 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1131 LOGE("failed to link fakesink");
1132 gst_object_unref(GST_OBJECT(fakesink));
1136 if (strstr(name, "video")) {
1137 if (player->v_stream_caps) {
1138 gst_caps_unref(player->v_stream_caps);
1139 player->v_stream_caps = NULL;
1141 if (player->ini.set_dump_element_flag)
1142 __mmplayer_add_dump_buffer_probe(player, fakesink);
1145 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1146 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1150 gst_object_unref(GST_OBJECT(sinkpad));
1157 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1159 GstElement *pipeline = NULL;
1160 GstElement *selector = NULL;
1161 GstPad *srcpad = NULL;
1164 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1166 selector = gst_element_factory_make("input-selector", NULL);
1168 LOGE("failed to create input-selector");
1171 g_object_set(selector, "sync-streams", TRUE, NULL);
1173 player->pipeline->mainbin[elem_idx].id = elem_idx;
1174 player->pipeline->mainbin[elem_idx].gst = selector;
1176 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1178 srcpad = gst_element_get_static_pad(selector, "src");
1180 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1181 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1182 __mmplayer_gst_selector_blocked, NULL, NULL);
1183 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1184 __mmplayer_gst_selector_event_probe, player, NULL);
1186 gst_element_set_state(selector, GST_STATE_PAUSED);
1188 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1189 gst_bin_add(GST_BIN(pipeline), selector);
1191 gst_object_unref(GST_OBJECT(srcpad));
1198 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1200 mmplayer_t *player = (mmplayer_t *)data;
1201 GstElement *selector = NULL;
1202 GstCaps *caps = NULL;
1203 GstStructure *str = NULL;
1204 const gchar *name = NULL;
1205 GstPad *sinkpad = NULL;
1206 gboolean first_track = FALSE;
1207 gboolean caps_ret = TRUE;
1209 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1210 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1213 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1214 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1216 LOGD("pad-added signal handling");
1218 /* get mimetype from caps */
1219 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1223 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1224 /* LOGD("detected mimetype : %s", name); */
1226 if (strstr(name, "video")) {
1228 gchar *caps_str = NULL;
1230 caps_str = gst_caps_to_string(caps);
1231 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1232 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1233 player->set_mode.video_zc = true;
1235 MMPLAYER_FREEIF(caps_str);
1237 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1238 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1240 LOGD("surface type : %d", stype);
1242 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1243 __mmplayer_gst_create_sinkbin(elem, pad, player);
1247 /* in case of exporting video frame, it requires the 360 video filter.
1248 * it will be handled in _no_more_pads(). */
1249 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1250 __mmplayer_gst_make_fakesink(player, pad, name);
1254 LOGD("video selector is required");
1255 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1256 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1257 } else if (strstr(name, "audio")) {
1258 gint samplerate = 0;
1261 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1262 if (player->build_audio_offload)
1263 player->no_more_pad = TRUE; /* remove state holder */
1264 __mmplayer_gst_create_sinkbin(elem, pad, player);
1268 gst_structure_get_int(str, "rate", &samplerate);
1269 gst_structure_get_int(str, "channels", &channels);
1271 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1272 __mmplayer_gst_make_fakesink(player, pad, name);
1276 LOGD("audio selector is required");
1277 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1278 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1280 } else if (strstr(name, "text")) {
1281 LOGD("text selector is required");
1282 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1283 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1285 LOGE("invalid caps info");
1289 /* check selector and create it */
1290 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1291 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1296 LOGD("input-selector is already created.");
1300 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1302 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1304 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1305 LOGE("failed to link selector");
1306 gst_object_unref(GST_OBJECT(selector));
1311 LOGD("this track will be activated");
1312 g_object_set(selector, "active-pad", sinkpad, NULL);
1315 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1321 gst_caps_unref(caps);
1324 gst_object_unref(GST_OBJECT(sinkpad));
1332 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1334 GstPad *srcpad = NULL;
1337 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1339 LOGD("type %d", type);
1342 LOGD("there is no %d track", type);
1346 srcpad = gst_element_get_static_pad(selector, "src");
1348 LOGE("failed to get srcpad from selector");
1352 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1354 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1356 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1357 if (player->selector[type].block_id) {
1358 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1359 player->selector[type].block_id = 0;
1363 gst_object_unref(GST_OBJECT(srcpad));
1372 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1374 MMHandleType attrs = 0;
1375 gint active_index = 0;
1378 MMPLAYER_RETURN_IF_FAIL(player);
1380 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1382 /* change track to active pad */
1383 active_index = player->selector[type].active_pad_index;
1384 if ((active_index != DEFAULT_TRACK) &&
1385 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1386 LOGW("failed to change %d type track to %d", type, active_index);
1387 player->selector[type].active_pad_index = DEFAULT_TRACK;
1391 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1392 attrs = MMPLAYER_GET_ATTRS(player);
1394 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1395 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1397 if (mm_attrs_commit_all(attrs))
1398 LOGW("failed to commit attrs.");
1400 LOGW("cannot get content attribute");
1409 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1412 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1414 if (!audio_selector) {
1415 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1417 /* in case the source is changed, output can be changed. */
1418 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1419 LOGD("remove previous audiobin if it exist");
1421 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1422 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1424 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1425 MMPLAYER_FREEIF(player->pipeline->audiobin);
1428 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1429 __mmplayer_pipeline_complete(NULL, player);
1434 /* apply the audio track information */
1435 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1437 /* create audio sink path */
1438 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1439 LOGE("failed to create audio sink path");
1448 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1451 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1453 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1454 LOGD("text path is not supproted");
1458 /* apply the text track information */
1459 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1461 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1462 player->has_closed_caption = TRUE;
1464 /* create text decode path */
1465 player->no_more_pad = TRUE;
1467 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1468 LOGE("failed to create text sink path");
1477 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1479 gint64 dur_bytes = 0L;
1482 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1483 player->pipeline->mainbin && player->streamer, FALSE);
1485 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1486 LOGE("fail to get duration.");
1488 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1489 * use file information was already set on Q2 when it was created. */
1490 _mm_player_streaming_set_queue2(player->streamer,
1491 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1492 TRUE, /* use_buffering */
1493 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1494 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1501 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1503 mmplayer_t *player = NULL;
1504 GstElement *video_selector = NULL;
1505 GstElement *audio_selector = NULL;
1506 GstElement *text_selector = NULL;
1509 player = (mmplayer_t *)data;
1511 LOGD("no-more-pad signal handling");
1513 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1514 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1515 LOGW("player is shutting down");
1519 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1520 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1521 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1522 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1523 LOGE("failed to set queue2 buffering");
1528 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1529 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1530 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1532 if (!video_selector && !audio_selector && !text_selector) {
1533 LOGW("there is no selector");
1534 player->no_more_pad = TRUE;
1538 /* create video path followed by video-select */
1539 if (video_selector && !audio_selector && !text_selector)
1540 player->no_more_pad = TRUE;
1542 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1545 /* create audio path followed by audio-select */
1546 if (audio_selector && !text_selector)
1547 player->no_more_pad = TRUE;
1549 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1552 /* create text path followed by text-select */
1553 __mmplayer_create_text_sink_path(player, text_selector);
1556 if (player->gapless.reconfigure) {
1557 player->gapless.reconfigure = FALSE;
1558 MMPLAYER_PLAYBACK_UNLOCK(player);
1565 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1567 gboolean ret = FALSE;
1568 GstElement *pipeline = NULL;
1569 GstPad *sinkpad = NULL;
1572 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1573 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1575 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1577 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1579 LOGE("failed to get pad from sinkbin");
1585 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1586 LOGE("failed to link sinkbin for reusing");
1587 goto EXIT; /* exit either pass or fail */
1591 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1592 LOGE("failed to set state(READY) to sinkbin");
1597 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1598 LOGE("failed to add sinkbin to pipeline");
1603 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1604 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1609 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1610 LOGE("failed to set state(PAUSED) to sinkbin");
1619 gst_object_unref(GST_OBJECT(sinkpad));
1627 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1629 mmplayer_t *player = NULL;
1630 GstCaps *caps = NULL;
1631 gchar *caps_str = NULL;
1632 GstStructure *str = NULL;
1633 const gchar *name = NULL;
1634 GstElement *sinkbin = NULL;
1635 gboolean reusing = FALSE;
1636 gboolean caps_ret = TRUE;
1637 gchar *sink_pad_name = "sink";
1640 player = (mmplayer_t *)data;
1643 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1644 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1646 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1650 caps_str = gst_caps_to_string(caps);
1652 /* LOGD("detected mimetype : %s", name); */
1653 if (strstr(name, "audio")) {
1654 if (player->pipeline->audiobin == NULL) {
1655 const gchar *audio_format = gst_structure_get_string(str, "format");
1657 LOGD("original audio format %s", audio_format);
1658 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1661 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1662 LOGE("failed to create audiobin. continuing without audio");
1666 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1667 LOGD("creating audiobin success");
1670 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1671 LOGD("reusing audiobin");
1672 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1674 } else if (strstr(name, "video")) {
1675 /* 1. zero copy is updated at _decode_pad_added()
1676 * 2. NULL surface type is handled in _decode_pad_added() */
1677 LOGD("zero copy %d", player->set_mode.video_zc);
1678 if (player->pipeline->videobin == NULL) {
1679 int surface_type = 0;
1680 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1681 LOGD("display_surface_type (%d)", surface_type);
1683 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1684 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1685 LOGE("failed to acquire video overlay resource");
1689 player->interrupted_by_resource = FALSE;
1691 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1692 LOGE("failed to create videobin. continuing without video");
1696 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1697 LOGD("creating videosink bin success");
1700 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1701 LOGD("re-using videobin");
1702 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1704 } else if (strstr(name, "text")) {
1705 if (player->pipeline->textbin == NULL) {
1706 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1707 LOGE("failed to create text sink bin. continuing without text");
1711 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1712 player->textsink_linked = 1;
1713 LOGD("creating textsink bin success");
1715 if (!player->textsink_linked) {
1716 LOGD("re-using textbin");
1718 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1719 player->textsink_linked = 1;
1721 /* linked textbin exist which means that the external subtitle path exist already */
1722 LOGW("ignoring internal subtutle since external subtitle is available");
1725 sink_pad_name = "text_sink";
1727 LOGW("unknown mime type %s, ignoring it", name);
1731 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1734 LOGD("[handle: %p] success to create and link sink bin", player);
1736 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1737 * streaming task. if the task blocked, then buffer will not flow to the next element
1738 *(autoplugging element). so this is special hack for streaming. please try to remove it
1740 /* dec stream count. we can remove fakesink if it's zero */
1741 if (player->num_dynamic_pad)
1742 player->num_dynamic_pad--;
1744 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1746 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1747 __mmplayer_pipeline_complete(NULL, player);
1751 MMPLAYER_FREEIF(caps_str);
1754 gst_caps_unref(caps);
1760 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1762 int required_angle = 0; /* Angle required for straight view */
1763 int rotation_angle = 0;
1765 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1766 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1768 /* Counter clockwise */
1769 switch (orientation) {
1774 required_angle = 270;
1777 required_angle = 180;
1780 required_angle = 90;
1784 rotation_angle = display_angle + required_angle;
1785 if (rotation_angle >= 360)
1786 rotation_angle -= 360;
1788 /* chech if supported or not */
1789 if (rotation_angle % 90) {
1790 LOGD("not supported rotation angle = %d", rotation_angle);
1794 switch (rotation_angle) {
1796 *value = MM_DISPLAY_ROTATION_NONE;
1799 *value = MM_DISPLAY_ROTATION_90;
1802 *value = MM_DISPLAY_ROTATION_180;
1805 *value = MM_DISPLAY_ROTATION_270;
1809 LOGD("setting rotation property value : %d", *value);
1815 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1817 /* check video sinkbin is created */
1818 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1820 player->pipeline->videobin &&
1821 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1822 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1823 MM_ERROR_PLAYER_NOT_INITIALIZED);
1825 return MM_ERROR_NONE;
1829 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1831 int display_rotation = 0;
1832 gchar *org_orient = NULL;
1833 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1836 LOGE("cannot get content attribute");
1837 return MM_ERROR_PLAYER_INTERNAL;
1840 if (display_angle) {
1841 /* update user roation */
1842 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1844 /* Counter clockwise */
1845 switch (display_rotation) {
1846 case MM_DISPLAY_ROTATION_NONE:
1849 case MM_DISPLAY_ROTATION_90:
1850 *display_angle = 90;
1852 case MM_DISPLAY_ROTATION_180:
1853 *display_angle = 180;
1855 case MM_DISPLAY_ROTATION_270:
1856 *display_angle = 270;
1859 LOGW("wrong angle type : %d", display_rotation);
1862 LOGD("check user angle: %d", *display_angle);
1866 /* Counter clockwise */
1867 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1870 if (!strcmp(org_orient, "rotate-90"))
1872 else if (!strcmp(org_orient, "rotate-180"))
1874 else if (!strcmp(org_orient, "rotate-270"))
1877 LOGD("original rotation is %s", org_orient);
1879 LOGD("content_video_orientation get fail");
1882 LOGD("check orientation: %d", *orientation);
1885 return MM_ERROR_NONE;
1889 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1891 int rotation_value = 0;
1892 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1893 int display_angle = 0;
1896 /* check video sinkbin is created */
1897 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1900 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1902 /* get rotation value to set */
1903 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1904 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1905 LOGD("set video param : rotate %d", rotation_value);
1909 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1911 MMHandleType attrs = 0;
1915 /* check video sinkbin is created */
1916 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1919 attrs = MMPLAYER_GET_ATTRS(player);
1920 MMPLAYER_RETURN_IF_FAIL(attrs);
1922 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1923 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1924 LOGD("set video param : visible %d", visible);
1928 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1930 MMHandleType attrs = 0;
1931 int display_method = 0;
1934 /* check video sinkbin is created */
1935 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1938 attrs = MMPLAYER_GET_ATTRS(player);
1939 MMPLAYER_RETURN_IF_FAIL(attrs);
1941 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1942 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1943 LOGD("set video param : method %d", display_method);
1947 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1949 MMHandleType attrs = 0;
1950 void *handle = NULL;
1953 /* check video sinkbin is created */
1954 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1955 LOGW("There is no video sink");
1959 attrs = MMPLAYER_GET_ATTRS(player);
1960 MMPLAYER_RETURN_IF_FAIL(attrs);
1961 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1963 gst_video_overlay_set_video_roi_area(
1964 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1965 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1966 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1967 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1972 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1974 MMHandleType attrs = 0;
1975 void *handle = NULL;
1979 int win_roi_width = 0;
1980 int win_roi_height = 0;
1983 /* check video sinkbin is created */
1984 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1985 LOGW("There is no video sink");
1989 attrs = MMPLAYER_GET_ATTRS(player);
1990 MMPLAYER_RETURN_IF_FAIL(attrs);
1992 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1995 /* It should be set after setting window */
1996 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1997 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1998 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1999 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2001 /* After setting window handle, set display roi area */
2002 gst_video_overlay_set_display_roi_area(
2003 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2004 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2005 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2006 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2011 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2013 MMHandleType attrs = 0;
2014 void *handle = NULL;
2016 /* check video sinkbin is created */
2017 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2020 attrs = MMPLAYER_GET_ATTRS(player);
2021 MMPLAYER_RETURN_IF_FAIL(attrs);
2023 /* common case if using overlay surface */
2024 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2027 /* default is using wl_surface_id */
2028 unsigned int wl_surface_id = 0;
2029 wl_surface_id = *(int *)handle;
2030 LOGD("set video param : wl_surface_id %d", wl_surface_id);
2031 gst_video_overlay_set_wl_window_wl_surface_id(
2032 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2035 /* FIXIT : is it error case? */
2036 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2041 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2043 gboolean update_all_param = FALSE;
2046 /* check video sinkbin is created */
2047 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2048 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2050 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2051 LOGE("can not find tizenwlsink");
2052 return MM_ERROR_PLAYER_INTERNAL;
2055 LOGD("param_name : %s", param_name);
2056 if (!g_strcmp0(param_name, "update_all_param"))
2057 update_all_param = TRUE;
2059 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2060 __mmplayer_video_param_set_display_overlay(player);
2061 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2062 __mmplayer_video_param_set_display_method(player);
2063 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2064 __mmplayer_video_param_set_display_visible(player);
2065 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2066 __mmplayer_video_param_set_display_rotation(player);
2067 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2068 __mmplayer_video_param_set_roi_area(player);
2069 if (update_all_param)
2070 __mmplayer_video_param_set_video_roi_area(player);
2072 return MM_ERROR_NONE;
2076 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2078 MMHandleType attrs = 0;
2079 int surface_type = 0;
2080 int ret = MM_ERROR_NONE;
2084 /* check video sinkbin is created */
2085 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2086 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2088 attrs = MMPLAYER_GET_ATTRS(player);
2090 LOGE("cannot get content attribute");
2091 return MM_ERROR_PLAYER_INTERNAL;
2093 LOGD("param_name : %s", param_name);
2095 /* update display surface */
2096 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2097 LOGD("check display surface type attribute: %d", surface_type);
2099 /* configuring display */
2100 switch (surface_type) {
2101 case MM_DISPLAY_SURFACE_OVERLAY:
2103 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2104 if (ret != MM_ERROR_NONE)
2112 return MM_ERROR_NONE;
2116 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2118 gboolean disable_overlay = FALSE;
2119 mmplayer_t *player = (mmplayer_t *)hplayer;
2122 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2123 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2124 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2125 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2127 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2128 LOGW("Display control is not supported");
2129 return MM_ERROR_PLAYER_INTERNAL;
2132 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2134 if (audio_only == (bool)disable_overlay) {
2135 LOGE("It's the same with current setting: (%d)", audio_only);
2136 return MM_ERROR_NONE;
2140 LOGE("disable overlay");
2141 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2143 /* release overlay resource */
2144 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2145 LOGE("failed to release overlay resource");
2149 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2150 LOGE("failed to acquire video overlay resource");
2153 player->interrupted_by_resource = FALSE;
2155 LOGD("enable overlay");
2156 __mmplayer_video_param_set_display_overlay(player);
2157 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2162 return MM_ERROR_NONE;
2166 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2168 mmplayer_t *player = (mmplayer_t *)hplayer;
2169 gboolean disable_overlay = FALSE;
2173 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2174 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2175 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2176 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2177 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2179 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2180 LOGW("Display control is not supported");
2181 return MM_ERROR_PLAYER_INTERNAL;
2184 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2186 *paudio_only = (bool)disable_overlay;
2188 LOGD("audio_only : %d", *paudio_only);
2192 return MM_ERROR_NONE;
2196 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2198 GList *bucket = element_bucket;
2199 mmplayer_gst_element_t *element = NULL;
2200 mmplayer_gst_element_t *prv_element = NULL;
2201 GstElement *tee_element = NULL;
2202 gint successful_link_count = 0;
2206 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2208 prv_element = (mmplayer_gst_element_t *)bucket->data;
2209 bucket = bucket->next;
2211 for (; bucket; bucket = bucket->next) {
2212 element = (mmplayer_gst_element_t *)bucket->data;
2214 if (element && element->gst) {
2215 if (prv_element && prv_element->gst) {
2216 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2218 prv_element->gst = tee_element;
2220 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2221 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2222 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2226 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2227 LOGD("linking [%s] to [%s] success",
2228 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2229 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2230 successful_link_count++;
2231 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2232 LOGD("keep audio-tee element for next audio pipeline branch");
2233 tee_element = prv_element->gst;
2236 LOGD("linking [%s] to [%s] failed",
2237 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2238 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2244 prv_element = element;
2249 return successful_link_count;
2253 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2255 GList *bucket = element_bucket;
2256 mmplayer_gst_element_t *element = NULL;
2257 int successful_add_count = 0;
2261 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2262 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2264 for (; bucket; bucket = bucket->next) {
2265 element = (mmplayer_gst_element_t *)bucket->data;
2267 if (element && element->gst) {
2268 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2269 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2270 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2271 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2274 successful_add_count++;
2280 return successful_add_count;
2284 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2286 mmplayer_t *player = (mmplayer_t *)data;
2287 GstCaps *caps = NULL;
2288 GstStructure *str = NULL;
2290 gboolean caps_ret = TRUE;
2294 MMPLAYER_RETURN_IF_FAIL(pad);
2295 MMPLAYER_RETURN_IF_FAIL(unused);
2296 MMPLAYER_RETURN_IF_FAIL(data);
2298 caps = gst_pad_get_current_caps(pad);
2302 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2306 LOGD("name = %s", name);
2308 if (strstr(name, "audio")) {
2309 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2311 if (player->audio_stream_changed_cb) {
2312 LOGE("call the audio stream changed cb");
2313 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2315 } else if (strstr(name, "video")) {
2316 if ((name = gst_structure_get_string(str, "format")))
2317 player->set_mode.video_zc = name[0] == 'S';
2319 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2320 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2322 LOGW("invalid caps info");
2327 gst_caps_unref(caps);
2335 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2340 MMPLAYER_RETURN_IF_FAIL(player);
2342 if (player->audio_stream_buff_list) {
2343 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2344 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2347 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2348 __mmplayer_audio_stream_send_data(player, tmp);
2350 MMPLAYER_FREEIF(tmp->pcm_data);
2351 MMPLAYER_FREEIF(tmp);
2354 g_list_free(player->audio_stream_buff_list);
2355 player->audio_stream_buff_list = NULL;
2362 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2364 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2367 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2369 audio_stream.bitrate = a_buffer->bitrate;
2370 audio_stream.channel = a_buffer->channel;
2371 audio_stream.depth = a_buffer->depth;
2372 audio_stream.is_little_endian = a_buffer->is_little_endian;
2373 audio_stream.channel_mask = a_buffer->channel_mask;
2374 audio_stream.data_size = a_buffer->data_size;
2375 audio_stream.data = a_buffer->pcm_data;
2376 audio_stream.pcm_format = a_buffer->pcm_format;
2378 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2379 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2385 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2387 mmplayer_t *player = (mmplayer_t *)data;
2388 const gchar *pcm_format = NULL;
2392 gint endianness = 0;
2393 guint64 channel_mask = 0;
2394 void *a_data = NULL;
2396 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2397 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2401 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2403 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2404 a_data = mapinfo.data;
2405 a_size = mapinfo.size;
2407 GstCaps *caps = gst_pad_get_current_caps(pad);
2408 GstStructure *structure = gst_caps_get_structure(caps, 0);
2410 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2411 pcm_format = gst_structure_get_string(structure, "format");
2412 gst_structure_get_int(structure, "rate", &rate);
2413 gst_structure_get_int(structure, "channels", &channel);
2414 gst_structure_get_int(structure, "depth", &depth);
2415 gst_structure_get_int(structure, "endianness", &endianness);
2416 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2417 gst_caps_unref(GST_CAPS(caps));
2419 /* In case of the sync is false, use buffer list. *
2420 * The num of buffer list depends on the num of audio channels */
2421 if (player->audio_stream_buff_list) {
2422 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2423 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2425 if (channel_mask == tmp->channel_mask) {
2426 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2427 if (tmp->data_size + a_size < tmp->buff_size) {
2428 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2429 tmp->data_size += a_size;
2431 /* send data to client */
2432 __mmplayer_audio_stream_send_data(player, tmp);
2434 if (a_size > tmp->buff_size) {
2435 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2436 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2437 if (tmp->pcm_data == NULL) {
2438 LOGE("failed to realloc data.");
2441 tmp->buff_size = a_size;
2443 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2444 memcpy(tmp->pcm_data, a_data, a_size);
2445 tmp->data_size = a_size;
2450 LOGE("data is empty in list.");
2456 /* create new audio stream data for newly found audio channel */
2457 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2458 if (a_buffer == NULL) {
2459 LOGE("failed to alloc data.");
2462 a_buffer->bitrate = rate;
2463 a_buffer->channel = channel;
2464 a_buffer->depth = depth;
2465 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2466 a_buffer->channel_mask = channel_mask;
2467 a_buffer->data_size = a_size;
2468 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2470 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2471 /* If sync is FALSE, use buffer list to reduce the IPC. */
2472 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2473 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2474 if (a_buffer->pcm_data == NULL) {
2475 LOGE("failed to alloc data.");
2476 MMPLAYER_FREEIF(a_buffer);
2479 memcpy(a_buffer->pcm_data, a_data, a_size);
2480 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2481 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2483 /* If sync is TRUE, send data directly. */
2484 a_buffer->pcm_data = a_data;
2485 __mmplayer_audio_stream_send_data(player, a_buffer);
2486 MMPLAYER_FREEIF(a_buffer);
2490 gst_buffer_unmap(buffer, &mapinfo);
2495 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2497 mmplayer_t *player = (mmplayer_t *)data;
2498 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2499 GstPad *sinkpad = NULL;
2500 GstElement *queue = NULL, *sink = NULL;
2503 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2505 queue = gst_element_factory_make("queue", NULL);
2506 if (queue == NULL) {
2507 LOGD("fail make queue");
2511 sink = gst_element_factory_make("fakesink", NULL);
2513 LOGD("fail make fakesink");
2517 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2519 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2520 LOGW("failed to link queue & sink");
2524 sinkpad = gst_element_get_static_pad(queue, "sink");
2526 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2527 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2531 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2533 gst_object_unref(sinkpad);
2534 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2535 g_object_set(sink, "sync", TRUE, NULL);
2536 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2538 /* keep the first sink reference only */
2539 if (!audiobin[MMPLAYER_A_SINK].gst) {
2540 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2541 audiobin[MMPLAYER_A_SINK].gst = sink;
2544 gst_element_set_state(sink, GST_STATE_PAUSED);
2545 gst_element_set_state(queue, GST_STATE_PAUSED);
2547 _mmplayer_add_signal_connection(player,
2549 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2551 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2554 __mmplayer_add_sink(player, sink);
2560 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2562 gst_object_unref(GST_OBJECT(queue));
2566 gst_object_unref(GST_OBJECT(sink));
2570 gst_object_unref(GST_OBJECT(sinkpad));
2578 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2580 #define MAX_PROPS_LEN 128
2581 gint latency_mode = 0;
2582 gchar *stream_type = NULL;
2583 gchar *latency = NULL;
2585 gchar stream_props[MAX_PROPS_LEN] = {0,};
2586 GstStructure *props = NULL;
2589 * It should be set after player creation through attribute.
2590 * But, it can not be changed during playing.
2593 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2595 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2596 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2599 LOGE("stream_type is null.");
2601 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d",
2602 stream_type, stream_id);
2603 props = gst_structure_from_string(stream_props, NULL);
2604 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2605 LOGI("stream_type[%s], stream_id[%d], result[%s].", stream_type, stream_id, stream_props);
2606 gst_structure_free(props);
2609 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2611 switch (latency_mode) {
2612 case AUDIO_LATENCY_MODE_LOW:
2613 latency = g_strndup("low", 3);
2615 case AUDIO_LATENCY_MODE_MID:
2616 latency = g_strndup("mid", 3);
2618 case AUDIO_LATENCY_MODE_HIGH:
2619 latency = g_strndup("high", 4);
2623 g_object_set(player->pipeline->audiobin[MMPLAYER_A_SINK].gst,
2627 LOGD("audiosink property - latency=%s", latency);
2629 MMPLAYER_FREEIF(latency);
2635 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2637 mmplayer_gst_element_t *audiobin = NULL;
2640 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2642 audiobin = player->pipeline->audiobin;
2644 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2645 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2646 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2648 if (player->video360_yaw_radians <= M_PI &&
2649 player->video360_yaw_radians >= -M_PI &&
2650 player->video360_pitch_radians <= M_PI_2 &&
2651 player->video360_pitch_radians >= -M_PI_2) {
2652 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2653 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2654 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2655 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2656 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2657 "source-orientation-y", player->video360_metadata.init_view_heading,
2658 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2665 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2667 mmplayer_gst_element_t *audiobin = NULL;
2668 GstPad *sink_pad = NULL;
2669 GstCaps *acaps = NULL;
2671 int pitch_control = 0;
2672 double pitch_value = 1.0;
2675 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2676 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2678 audiobin = player->pipeline->audiobin;
2680 LOGD("make element for normal audio playback");
2682 /* audio bin structure for playback. {} means optional.
2683 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2685 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2686 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2689 /* for pitch control */
2690 mm_attrs_multiple_get(player->attrs, NULL,
2691 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2692 MM_PLAYER_PITCH_VALUE, &pitch_value,
2695 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2696 if (pitch_control && (player->videodec_linked == 0)) {
2697 GstElementFactory *factory;
2699 factory = gst_element_factory_find("pitch");
2701 gst_object_unref(factory);
2704 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2707 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2708 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2710 LOGW("there is no pitch element");
2715 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2717 /* replaygain volume */
2718 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2719 if (player->sound.rg_enable)
2720 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2722 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2725 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2727 /* for logical volume control */
2728 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2729 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2731 if (player->sound.mute) {
2732 LOGD("mute enabled");
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2736 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2738 /* audio effect element. if audio effect is enabled */
2739 if ((strcmp(player->ini.audioeffect_element, ""))
2741 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2742 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2744 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2746 if ((!player->bypass_audio_effect)
2747 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2748 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2749 if (!_mmplayer_audio_effect_custom_apply(player))
2750 LOGI("apply audio effect(custom) setting success");
2754 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2755 && (player->set_mode.rich_audio)) {
2756 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2760 /* create audio sink */
2761 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2762 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2763 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2765 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2766 if (player->is_360_feature_enabled &&
2767 player->is_content_spherical &&
2769 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2770 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2771 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2773 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2775 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2777 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2778 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2779 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2780 gst_caps_unref(acaps);
2782 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2784 player->is_openal_plugin_used = TRUE;
2786 if (player->is_360_feature_enabled && player->is_content_spherical)
2787 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2788 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2791 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2792 (player->videodec_linked && player->ini.use_system_clock)) {
2793 LOGD("system clock will be used.");
2794 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2797 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2798 __mmplayer_gst_set_pulsesink_property(player);
2799 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2800 __mmplayer_gst_set_openalsink_property(player);
2803 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2804 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2806 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2807 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2808 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2809 gst_object_unref(GST_OBJECT(sink_pad));
2811 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2814 return MM_ERROR_NONE;
2816 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2818 return MM_ERROR_PLAYER_INTERNAL;
2822 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2824 mmplayer_gst_element_t *audiobin = NULL;
2825 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2827 gchar *dst_format = NULL;
2829 int dst_samplerate = 0;
2830 int dst_channels = 0;
2831 GstCaps *caps = NULL;
2832 char *caps_str = NULL;
2835 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2836 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2838 audiobin = player->pipeline->audiobin;
2840 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2842 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2844 [case 1] extract interleave audio pcm without playback
2845 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2846 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2848 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2850 [case 2] deinterleave for each channel without playback
2851 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2852 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2854 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2855 - fakesink (sync or not)
2858 [case 3] [case 1(sync only)] + playback
2859 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2861 * src - ... - tee - queue1 - playback path
2862 - queue2 - [case1 pipeline with sync]
2864 [case 4] [case 2(sync only)] + playback
2865 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2867 * src - ... - tee - queue1 - playback path
2868 - queue2 - [case2 pipeline with sync]
2872 /* 1. create tee and playback path
2873 'tee' should be added at first to copy the decoded stream
2875 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2876 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2877 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2879 /* tee - path 1 : for playback path */
2880 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2881 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2883 /* tee - path 2 : for extract path */
2884 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2885 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2888 /* if there is tee, 'tee - path 2' is linked here */
2890 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2893 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2895 /* 2. decide the extract pcm format */
2896 mm_attrs_multiple_get(player->attrs, NULL,
2897 "pcm_audioformat", &dst_format, &dst_len,
2898 "pcm_extraction_samplerate", &dst_samplerate,
2899 "pcm_extraction_channels", &dst_channels,
2902 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2903 dst_format, dst_len, dst_samplerate, dst_channels);
2905 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2906 mm_attrs_multiple_get(player->attrs, NULL,
2907 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2908 "content_audio_samplerate", &dst_samplerate,
2909 "content_audio_channels", &dst_channels,
2912 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2913 dst_format, dst_len, dst_samplerate, dst_channels);
2915 /* If there is no enough information, set it to platform default value. */
2916 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2917 LOGD("set platform default format");
2918 dst_format = DEFAULT_PCM_OUT_FORMAT;
2920 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2921 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2924 /* 3. create capsfilter */
2925 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2926 caps = gst_caps_new_simple("audio/x-raw",
2927 "format", G_TYPE_STRING, dst_format,
2928 "rate", G_TYPE_INT, dst_samplerate,
2929 "channels", G_TYPE_INT, dst_channels,
2932 caps_str = gst_caps_to_string(caps);
2933 LOGD("new caps : %s", caps_str);
2935 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2938 gst_caps_unref(caps);
2939 MMPLAYER_FREEIF(caps_str);
2941 /* 4-1. create deinterleave to extract pcm for each channel */
2942 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2943 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2944 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2946 /* audiosink will be added after getting signal for each channel */
2947 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2948 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2950 /* 4-2. create fakesink to extract interlevaed pcm */
2951 LOGD("add audio fakesink for interleaved audio");
2952 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2953 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2954 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2955 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2957 _mmplayer_add_signal_connection(player,
2958 G_OBJECT(audiobin[extract_sink_id].gst),
2959 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2961 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2964 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2968 return MM_ERROR_NONE;
2970 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2972 return MM_ERROR_PLAYER_INTERNAL;
2976 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2978 int ret = MM_ERROR_NONE;
2979 mmplayer_gst_element_t *audiobin = NULL;
2980 GList *element_bucket = NULL;
2983 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2984 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2986 audiobin = player->pipeline->audiobin;
2988 if (player->build_audio_offload) { /* skip all the audio filters */
2989 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2991 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2992 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2993 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2995 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2999 /* FIXME: need to mention the supportable condition at API reference */
3000 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3001 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3003 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3005 if (ret != MM_ERROR_NONE)
3008 LOGD("success to make audio bin element");
3009 *bucket = element_bucket;
3012 return MM_ERROR_NONE;
3015 LOGE("failed to make audio bin element");
3016 g_list_free(element_bucket);
3020 return MM_ERROR_PLAYER_INTERNAL;
3024 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3026 mmplayer_gst_element_t *first_element = NULL;
3027 mmplayer_gst_element_t *audiobin = NULL;
3029 GstPad *ghostpad = NULL;
3030 GList *element_bucket = NULL;
3034 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3037 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3039 LOGE("failed to allocate memory for audiobin");
3040 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3044 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3045 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3046 if (!audiobin[MMPLAYER_A_BIN].gst) {
3047 LOGE("failed to create audiobin");
3052 player->pipeline->audiobin = audiobin;
3054 /* create audio filters and audiosink */
3055 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3058 /* adding created elements to bin */
3059 LOGD("adding created elements to bin");
3060 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3063 /* linking elements in the bucket by added order. */
3064 LOGD("Linking elements in the bucket by added order.");
3065 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3068 /* get first element's sinkpad for creating ghostpad */
3069 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3070 if (!first_element) {
3071 LOGE("failed to get first elem");
3075 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3077 LOGE("failed to get pad from first element of audiobin");
3081 ghostpad = gst_ghost_pad_new("sink", pad);
3083 LOGE("failed to create ghostpad");
3087 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3088 LOGE("failed to add ghostpad to audiobin");
3092 gst_object_unref(pad);
3094 g_list_free(element_bucket);
3097 return MM_ERROR_NONE;
3100 LOGD("ERROR : releasing audiobin");
3103 gst_object_unref(GST_OBJECT(pad));
3106 gst_object_unref(GST_OBJECT(ghostpad));
3109 g_list_free(element_bucket);
3111 /* release element which are not added to bin */
3112 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3113 /* NOTE : skip bin */
3114 if (audiobin[i].gst) {
3115 GstObject *parent = NULL;
3116 parent = gst_element_get_parent(audiobin[i].gst);
3119 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3120 audiobin[i].gst = NULL;
3122 gst_object_unref(GST_OBJECT(parent));
3126 /* release audiobin with it's childs */
3127 if (audiobin[MMPLAYER_A_BIN].gst)
3128 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3130 MMPLAYER_FREEIF(audiobin);
3132 player->pipeline->audiobin = NULL;
3134 return MM_ERROR_PLAYER_INTERNAL;
3138 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3140 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3144 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3146 int ret = MM_ERROR_NONE;
3148 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3149 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3151 MMPLAYER_VIDEO_BO_LOCK(player);
3153 if (player->video_bo_list) {
3154 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3155 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3156 if (tmp && tmp->bo == bo) {
3158 LOGD("release bo %p", bo);
3159 tbm_bo_unref(tmp->bo);
3160 MMPLAYER_VIDEO_BO_UNLOCK(player);
3161 MMPLAYER_VIDEO_BO_SIGNAL(player);
3166 /* hw codec is running or the list was reset for DRC. */
3167 LOGW("there is no bo list.");
3169 MMPLAYER_VIDEO_BO_UNLOCK(player);
3171 LOGW("failed to find bo %p", bo);
3176 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3181 MMPLAYER_RETURN_IF_FAIL(player);
3183 MMPLAYER_VIDEO_BO_LOCK(player);
3184 if (player->video_bo_list) {
3185 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3186 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3187 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3190 tbm_bo_unref(tmp->bo);
3194 g_list_free(player->video_bo_list);
3195 player->video_bo_list = NULL;
3197 player->video_bo_size = 0;
3198 MMPLAYER_VIDEO_BO_UNLOCK(player);
3205 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3208 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3209 gboolean ret = TRUE;
3211 /* check DRC, if it is, destroy the prev bo list to create again */
3212 if (player->video_bo_size != size) {
3213 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3214 __mmplayer_video_stream_destroy_bo_list(player);
3215 player->video_bo_size = size;
3218 MMPLAYER_VIDEO_BO_LOCK(player);
3220 if ((!player->video_bo_list) ||
3221 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3223 /* create bo list */
3225 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3227 if (player->video_bo_list) {
3228 /* if bo list did not created all, try it again. */
3229 idx = g_list_length(player->video_bo_list);
3230 LOGD("bo list exist(len: %d)", idx);
3233 for (; idx < player->ini.num_of_video_bo; idx++) {
3234 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3236 LOGE("Fail to alloc bo_info.");
3239 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3241 LOGE("Fail to tbm_bo_alloc.");
3242 MMPLAYER_FREEIF(bo_info);
3245 bo_info->used = FALSE;
3246 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3249 /* update video num buffers */
3250 LOGD("video_num_buffers : %d", idx);
3251 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3252 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3255 MMPLAYER_VIDEO_BO_UNLOCK(player);
3261 /* get bo from list*/
3262 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3263 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3264 if (tmp && (tmp->used == FALSE)) {
3265 LOGD("found bo %p to use", tmp->bo);
3267 MMPLAYER_VIDEO_BO_UNLOCK(player);
3268 return tbm_bo_ref(tmp->bo);
3272 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3273 MMPLAYER_VIDEO_BO_UNLOCK(player);
3277 if (player->ini.video_bo_timeout <= 0) {
3278 MMPLAYER_VIDEO_BO_WAIT(player);
3280 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3281 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3288 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3290 mmplayer_t *player = (mmplayer_t *)data;
3292 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3294 /* send prerolled pkt */
3295 player->video_stream_prerolled = false;
3297 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3299 /* not to send prerolled pkt again */
3300 player->video_stream_prerolled = true;
3304 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3306 mmplayer_t *player = (mmplayer_t *)data;
3307 mmplayer_video_decoded_data_info_t *stream = NULL;
3308 GstMemory *mem = NULL;
3311 MMPLAYER_RETURN_IF_FAIL(player);
3312 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3314 if (player->video_stream_prerolled) {
3315 player->video_stream_prerolled = false;
3316 LOGD("skip the prerolled pkt not to send it again");
3320 /* clear stream data structure */
3321 stream = __mmplayer_create_stream_from_pad(pad);
3323 LOGE("failed to alloc stream");
3327 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3329 /* set size and timestamp */
3330 mem = gst_buffer_peek_memory(buffer, 0);
3331 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3332 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3334 /* check zero-copy */
3335 if (player->set_mode.video_zc &&
3336 player->set_mode.video_export &&
3337 gst_is_tizen_memory(mem)) {
3338 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3339 stream->internal_buffer = gst_buffer_ref(buffer);
3340 } else { /* sw codec */
3341 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3344 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3348 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3349 LOGE("failed to send video decoded data.");
3356 LOGE("release video stream resource.");
3357 if (gst_is_tizen_memory(mem)) {
3359 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3361 tbm_bo_unref(stream->bo[i]);
3364 /* unref gst buffer */
3365 if (stream->internal_buffer)
3366 gst_buffer_unref(stream->internal_buffer);
3369 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3371 MMPLAYER_FREEIF(stream);
3376 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3378 mmplayer_gst_element_t *videobin = NULL;
3381 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3383 videobin = player->pipeline->videobin;
3385 /* Set spatial media metadata and/or user settings to the element.
3387 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3388 "projection-type", player->video360_metadata.projection_type, NULL);
3390 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3391 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3393 if (player->video360_metadata.full_pano_width_pixels &&
3394 player->video360_metadata.full_pano_height_pixels &&
3395 player->video360_metadata.cropped_area_image_width &&
3396 player->video360_metadata.cropped_area_image_height) {
3397 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3398 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3399 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3400 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3401 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3402 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3403 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3407 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3408 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3409 "horizontal-fov", player->video360_horizontal_fov,
3410 "vertical-fov", player->video360_vertical_fov, NULL);
3413 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3414 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3415 "zoom", 1.0f / player->video360_zoom, NULL);
3418 if (player->video360_yaw_radians <= M_PI &&
3419 player->video360_yaw_radians >= -M_PI &&
3420 player->video360_pitch_radians <= M_PI_2 &&
3421 player->video360_pitch_radians >= -M_PI_2) {
3422 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3423 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3424 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3425 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3426 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3427 "pose-yaw", player->video360_metadata.init_view_heading,
3428 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3431 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3432 "passthrough", !player->is_video360_enabled, NULL);
3439 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3441 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3442 GList *element_bucket = NULL;
3445 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3447 /* create video360 filter */
3448 if (player->is_360_feature_enabled && player->is_content_spherical) {
3449 LOGD("create video360 element");
3450 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3451 __mmplayer_gst_set_video360_property(player);
3455 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3456 LOGD("skip creating the videoconv and rotator");
3457 return MM_ERROR_NONE;
3460 /* in case of sw codec & overlay surface type, except 360 playback.
3461 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3462 LOGD("create video converter: %s", video_csc);
3463 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3466 *bucket = element_bucket;
3468 return MM_ERROR_NONE;
3470 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3471 g_list_free(element_bucket);
3475 return MM_ERROR_PLAYER_INTERNAL;
3479 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3481 gchar *factory_name = NULL;
3483 switch (surface_type) {
3484 case MM_DISPLAY_SURFACE_OVERLAY:
3485 if (strlen(player->ini.videosink_element_overlay) > 0)
3486 factory_name = player->ini.videosink_element_overlay;
3488 case MM_DISPLAY_SURFACE_REMOTE:
3489 case MM_DISPLAY_SURFACE_NULL:
3490 if (strlen(player->ini.videosink_element_fake) > 0)
3491 factory_name = player->ini.videosink_element_fake;
3494 LOGE("unidentified surface type");
3498 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3499 return factory_name;
3503 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3505 gchar *factory_name = NULL;
3506 mmplayer_gst_element_t *videobin = NULL;
3511 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3513 videobin = player->pipeline->videobin;
3514 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3516 attrs = MMPLAYER_GET_ATTRS(player);
3518 LOGE("cannot get content attribute");
3519 return MM_ERROR_PLAYER_INTERNAL;
3522 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3523 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3524 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3526 /* support shard memory with S/W codec on HawkP */
3527 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3528 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3529 "use-tbm", use_tbm, NULL);
3533 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3534 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3537 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3539 LOGD("disable last-sample");
3540 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3543 if (player->set_mode.video_export) {
3545 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3546 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3547 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3549 _mmplayer_add_signal_connection(player,
3550 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3551 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3553 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3556 _mmplayer_add_signal_connection(player,
3557 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3558 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3560 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3564 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3565 return MM_ERROR_PLAYER_INTERNAL;
3567 if (videobin[MMPLAYER_V_SINK].gst) {
3568 GstPad *sink_pad = NULL;
3569 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3571 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3572 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3573 gst_object_unref(GST_OBJECT(sink_pad));
3575 LOGE("failed to get sink pad from videosink");
3579 return MM_ERROR_NONE;
3584 * - video overlay surface(arm/x86) : tizenwlsink
3587 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3590 GList *element_bucket = NULL;
3591 mmplayer_gst_element_t *first_element = NULL;
3592 mmplayer_gst_element_t *videobin = NULL;
3593 gchar *videosink_factory_name = NULL;
3596 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3599 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3601 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3603 player->pipeline->videobin = videobin;
3606 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3607 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3608 if (!videobin[MMPLAYER_V_BIN].gst) {
3609 LOGE("failed to create videobin");
3613 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3616 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3617 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3619 /* additional setting for sink plug-in */
3620 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3621 LOGE("failed to set video property");
3625 /* store it as it's sink element */
3626 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3628 /* adding created elements to bin */
3629 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3630 LOGE("failed to add elements");
3634 /* Linking elements in the bucket by added order */
3635 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3636 LOGE("failed to link elements");
3640 /* get first element's sinkpad for creating ghostpad */
3641 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3642 if (!first_element) {
3643 LOGE("failed to get first element from bucket");
3647 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3649 LOGE("failed to get pad from first element");
3653 /* create ghostpad */
3654 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3655 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3656 LOGE("failed to add ghostpad to videobin");
3659 gst_object_unref(pad);
3661 /* done. free allocated variables */
3662 g_list_free(element_bucket);
3666 return MM_ERROR_NONE;
3669 LOGE("ERROR : releasing videobin");
3670 g_list_free(element_bucket);
3673 gst_object_unref(GST_OBJECT(pad));
3675 /* release videobin with it's childs */
3676 if (videobin[MMPLAYER_V_BIN].gst)
3677 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3679 MMPLAYER_FREEIF(videobin);
3680 player->pipeline->videobin = NULL;
3682 return MM_ERROR_PLAYER_INTERNAL;
3686 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3688 GList *element_bucket = NULL;
3689 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3691 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3692 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3693 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3694 "signal-handoffs", FALSE,
3697 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3698 _mmplayer_add_signal_connection(player,
3699 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3700 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3702 G_CALLBACK(__mmplayer_update_subtitle),
3705 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3706 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3708 if (!player->play_subtitle) {
3709 LOGD("add textbin sink as sink element of whole pipeline.");
3710 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3713 /* adding created elements to bin */
3714 LOGD("adding created elements to bin");
3715 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3716 LOGE("failed to add elements");
3720 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3721 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3722 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3724 /* linking elements in the bucket by added order. */
3725 LOGD("Linking elements in the bucket by added order.");
3726 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3727 LOGE("failed to link elements");
3731 /* done. free allocated variables */
3732 g_list_free(element_bucket);
3734 if (textbin[MMPLAYER_T_QUEUE].gst) {
3736 GstPad *ghostpad = NULL;
3738 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3740 LOGE("failed to get sink pad of text queue");
3744 ghostpad = gst_ghost_pad_new("text_sink", pad);
3745 gst_object_unref(pad);
3748 LOGE("failed to create ghostpad of textbin");
3752 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3753 LOGE("failed to add ghostpad to textbin");
3754 gst_object_unref(ghostpad);
3759 return MM_ERROR_NONE;
3762 g_list_free(element_bucket);
3764 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3765 LOGE("remove textbin sink from sink list");
3766 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3769 /* release element at __mmplayer_gst_create_text_sink_bin */
3770 return MM_ERROR_PLAYER_INTERNAL;
3774 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3776 mmplayer_gst_element_t *textbin = NULL;
3777 GList *element_bucket = NULL;
3778 int surface_type = 0;
3783 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3786 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3788 LOGE("failed to allocate memory for textbin");
3789 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3793 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3794 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3795 if (!textbin[MMPLAYER_T_BIN].gst) {
3796 LOGE("failed to create textbin");
3801 player->pipeline->textbin = textbin;
3804 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3805 LOGD("surface type for subtitle : %d", surface_type);
3806 switch (surface_type) {
3807 case MM_DISPLAY_SURFACE_OVERLAY:
3808 case MM_DISPLAY_SURFACE_NULL:
3809 case MM_DISPLAY_SURFACE_REMOTE:
3810 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3811 LOGE("failed to make plain text elements");
3822 return MM_ERROR_NONE;
3826 LOGD("ERROR : releasing textbin");
3828 g_list_free(element_bucket);
3830 /* release signal */
3831 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3833 /* release element which are not added to bin */
3834 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3835 /* NOTE : skip bin */
3836 if (textbin[i].gst) {
3837 GstObject *parent = NULL;
3838 parent = gst_element_get_parent(textbin[i].gst);
3841 gst_object_unref(GST_OBJECT(textbin[i].gst));
3842 textbin[i].gst = NULL;
3844 gst_object_unref(GST_OBJECT(parent));
3849 /* release textbin with it's childs */
3850 if (textbin[MMPLAYER_T_BIN].gst)
3851 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3853 MMPLAYER_FREEIF(player->pipeline->textbin);
3854 player->pipeline->textbin = NULL;
3857 return MM_ERROR_PLAYER_INTERNAL;
3861 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3863 mmplayer_gst_element_t *mainbin = NULL;
3864 mmplayer_gst_element_t *textbin = NULL;
3865 MMHandleType attrs = 0;
3866 GstElement *subsrc = NULL;
3867 GstElement *subparse = NULL;
3868 gchar *subtitle_uri = NULL;
3869 const gchar *charset = NULL;
3875 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3877 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3879 mainbin = player->pipeline->mainbin;
3881 attrs = MMPLAYER_GET_ATTRS(player);
3883 LOGE("cannot get content attribute");
3884 return MM_ERROR_PLAYER_INTERNAL;
3887 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3888 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3889 LOGE("subtitle uri is not proper filepath.");
3890 return MM_ERROR_PLAYER_INVALID_URI;
3893 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3894 LOGE("failed to get storage info of subtitle path");
3895 return MM_ERROR_PLAYER_INVALID_URI;
3898 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3900 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3901 player->subtitle_language_list = NULL;
3902 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3904 /* create the subtitle source */
3905 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3907 LOGE("failed to create filesrc element");
3910 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3912 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3913 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3915 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3916 LOGW("failed to add queue");
3917 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3918 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3919 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3924 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3926 LOGE("failed to create subparse element");
3930 charset = _mmplayer_get_charset(subtitle_uri);
3932 LOGD("detected charset is %s", charset);
3933 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3936 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3937 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3939 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3940 LOGW("failed to add subparse");
3941 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3942 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3943 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3947 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3948 LOGW("failed to link subsrc and subparse");
3952 player->play_subtitle = TRUE;
3953 player->adjust_subtitle_pos = 0;
3955 LOGD("play subtitle using subtitle file");
3957 if (player->pipeline->textbin == NULL) {
3958 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3959 LOGE("failed to create text sink bin. continuing without text");
3963 textbin = player->pipeline->textbin;
3965 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3966 LOGW("failed to add textbin");
3968 /* release signal */
3969 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3971 /* release textbin with it's childs */
3972 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3973 MMPLAYER_FREEIF(player->pipeline->textbin);
3974 player->pipeline->textbin = textbin = NULL;
3978 LOGD("link text input selector and textbin ghost pad");
3980 player->textsink_linked = 1;
3981 player->external_text_idx = 0;
3982 LOGI("textsink is linked");
3984 textbin = player->pipeline->textbin;
3985 LOGD("text bin has been created. reuse it.");
3986 player->external_text_idx = 1;
3989 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3990 LOGW("failed to link subparse and textbin");
3994 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3996 LOGE("failed to get sink pad from textsink to probe data");
4000 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4001 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4003 gst_object_unref(pad);
4006 /* create dot. for debugging */
4007 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4010 return MM_ERROR_NONE;
4013 /* release text pipeline resource */
4014 player->textsink_linked = 0;
4016 /* release signal */
4017 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4019 if (player->pipeline->textbin) {
4020 LOGE("remove textbin");
4022 /* release textbin with it's childs */
4023 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4024 MMPLAYER_FREEIF(player->pipeline->textbin);
4025 player->pipeline->textbin = NULL;
4029 /* release subtitle elem */
4030 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4031 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4033 return MM_ERROR_PLAYER_INTERNAL;
4037 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4039 mmplayer_t *player = (mmplayer_t *)data;
4040 MMMessageParamType msg = {0, };
4041 GstClockTime duration = 0;
4042 gpointer text = NULL;
4043 guint text_size = 0;
4044 gboolean ret = TRUE;
4045 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4049 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4050 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4052 if (player->is_subtitle_force_drop) {
4053 LOGW("subtitle is dropped forcedly.");
4057 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4058 text = mapinfo.data;
4059 text_size = mapinfo.size;
4061 if (player->set_mode.subtitle_off) {
4062 LOGD("subtitle is OFF.");
4066 if (!text || (text_size == 0)) {
4067 LOGD("There is no subtitle to be displayed.");
4071 msg.data = (void *)text;
4073 duration = GST_BUFFER_DURATION(buffer);
4075 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4076 if (player->duration > GST_BUFFER_PTS(buffer))
4077 duration = player->duration - GST_BUFFER_PTS(buffer);
4080 LOGI("subtitle duration is invalid, subtitle duration change "
4081 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4083 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4085 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4087 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4088 gst_buffer_unmap(buffer, &mapinfo);
4095 static GstPadProbeReturn
4096 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4098 mmplayer_t *player = (mmplayer_t *)u_data;
4099 GstClockTime cur_timestamp = 0;
4100 gint64 adjusted_timestamp = 0;
4101 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4103 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4105 if (player->set_mode.subtitle_off) {
4106 LOGD("subtitle is OFF.");
4110 if (player->adjust_subtitle_pos == 0) {
4111 LOGD("nothing to do");
4115 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4116 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4118 if (adjusted_timestamp < 0) {
4119 LOGD("adjusted_timestamp under zero");
4124 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4125 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4126 GST_TIME_ARGS(cur_timestamp),
4127 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4129 return GST_PAD_PROBE_OK;
4133 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4137 /* check player and subtitlebin are created */
4138 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4139 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4141 if (position == 0) {
4142 LOGD("nothing to do");
4144 return MM_ERROR_NONE;
4147 /* check current postion */
4148 player->adjust_subtitle_pos = position;
4150 LOGD("save adjust_subtitle_pos in player");
4154 return MM_ERROR_NONE;
4158 * This function is to create audio or video pipeline for playing.
4160 * @param player [in] handle of player
4162 * @return This function returns zero on success.
4167 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4169 int ret = MM_ERROR_NONE;
4170 mmplayer_gst_element_t *mainbin = NULL;
4171 MMHandleType attrs = 0;
4174 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4176 /* get profile attribute */
4177 attrs = MMPLAYER_GET_ATTRS(player);
4179 LOGE("failed to get content attribute");
4183 /* create pipeline handles */
4184 if (player->pipeline) {
4185 LOGE("pipeline should be released before create new one");
4189 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4190 if (player->pipeline == NULL)
4193 /* create mainbin */
4194 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4195 if (mainbin == NULL)
4198 /* create pipeline */
4199 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4200 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4201 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4202 LOGE("failed to create pipeline");
4207 player->pipeline->mainbin = mainbin;
4209 /* create the source and decoder elements */
4210 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4211 ret = _mmplayer_gst_build_es_pipeline(player);
4213 ret = _mmplayer_gst_build_pipeline(player);
4215 if (ret != MM_ERROR_NONE) {
4216 LOGE("failed to create some elements");
4220 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4221 if (__mmplayer_check_subtitle(player)
4222 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4223 LOGE("failed to create text pipeline");
4226 ret = _mmplayer_gst_add_bus_watch(player);
4227 if (ret != MM_ERROR_NONE) {
4228 LOGE("failed to add bus watch");
4233 return MM_ERROR_NONE;
4236 __mmplayer_gst_destroy_pipeline(player);
4237 return MM_ERROR_PLAYER_INTERNAL;
4241 __mmplayer_reset_gapless_state(mmplayer_t *player)
4244 MMPLAYER_RETURN_IF_FAIL(player
4246 && player->pipeline->audiobin
4247 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4249 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4256 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4259 int ret = MM_ERROR_NONE;
4263 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4265 /* cleanup stuffs */
4266 MMPLAYER_FREEIF(player->type);
4267 player->no_more_pad = FALSE;
4268 player->num_dynamic_pad = 0;
4269 player->demux_pad_index = 0;
4271 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4272 player->subtitle_language_list = NULL;
4273 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4275 __mmplayer_reset_gapless_state(player);
4277 if (player->streamer) {
4278 _mm_player_streaming_initialize(player->streamer, FALSE);
4279 _mm_player_streaming_destroy(player->streamer);
4280 player->streamer = NULL;
4283 /* cleanup unlinked mime type */
4284 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4285 MMPLAYER_FREEIF(player->unlinked_video_mime);
4286 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4288 /* cleanup running stuffs */
4289 _mmplayer_cancel_eos_timer(player);
4291 /* cleanup gst stuffs */
4292 if (player->pipeline) {
4293 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4294 GstTagList *tag_list = player->pipeline->tag_list;
4296 /* first we need to disconnect all signal hander */
4297 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4300 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4301 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4302 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4303 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4304 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4305 gst_object_unref(bus);
4307 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4308 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4309 if (ret != MM_ERROR_NONE) {
4310 LOGE("fail to change state to NULL");
4311 return MM_ERROR_PLAYER_INTERNAL;
4314 LOGW("succeeded in changing state to NULL");
4316 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4319 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4320 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4322 /* free avsysaudiosink
4323 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4324 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4326 MMPLAYER_FREEIF(audiobin);
4327 MMPLAYER_FREEIF(videobin);
4328 MMPLAYER_FREEIF(textbin);
4329 MMPLAYER_FREEIF(mainbin);
4333 gst_tag_list_unref(tag_list);
4335 MMPLAYER_FREEIF(player->pipeline);
4337 MMPLAYER_FREEIF(player->album_art);
4339 if (player->v_stream_caps) {
4340 gst_caps_unref(player->v_stream_caps);
4341 player->v_stream_caps = NULL;
4344 if (player->a_stream_caps) {
4345 gst_caps_unref(player->a_stream_caps);
4346 player->a_stream_caps = NULL;
4349 if (player->s_stream_caps) {
4350 gst_caps_unref(player->s_stream_caps);
4351 player->s_stream_caps = NULL;
4353 _mmplayer_track_destroy(player);
4355 if (player->sink_elements)
4356 g_list_free(player->sink_elements);
4357 player->sink_elements = NULL;
4359 if (player->bufmgr) {
4360 tbm_bufmgr_deinit(player->bufmgr);
4361 player->bufmgr = NULL;
4364 LOGW("finished destroy pipeline");
4372 __mmplayer_gst_realize(mmplayer_t *player)
4375 int ret = MM_ERROR_NONE;
4379 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4381 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4383 ret = __mmplayer_gst_create_pipeline(player);
4385 LOGE("failed to create pipeline");
4389 /* set pipeline state to READY */
4390 /* NOTE : state change to READY must be performed sync. */
4391 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4392 ret = _mmplayer_gst_set_state(player,
4393 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4395 if (ret != MM_ERROR_NONE) {
4396 /* return error if failed to set state */
4397 LOGE("failed to set READY state");
4401 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4403 /* create dot before error-return. for debugging */
4404 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4412 __mmplayer_gst_unrealize(mmplayer_t *player)
4414 int ret = MM_ERROR_NONE;
4418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4420 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4421 MMPLAYER_PRINT_STATE(player);
4423 /* release miscellaneous information */
4424 __mmplayer_release_misc(player);
4426 /* destroy pipeline */
4427 ret = __mmplayer_gst_destroy_pipeline(player);
4428 if (ret != MM_ERROR_NONE) {
4429 LOGE("failed to destory pipeline");
4433 /* release miscellaneous information.
4434 these info needs to be released after pipeline is destroyed. */
4435 __mmplayer_release_misc_post(player);
4437 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4445 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4450 LOGW("set_message_callback is called with invalid player handle");
4451 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4454 player->msg_cb = callback;
4455 player->msg_cb_param = user_param;
4457 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4461 return MM_ERROR_NONE;
4465 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4467 int ret = MM_ERROR_NONE;
4472 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4473 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4474 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4476 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4478 if (strstr(uri, "es_buff://")) {
4479 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4480 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4481 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4482 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4484 tmp = g_ascii_strdown(uri, strlen(uri));
4485 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4486 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4488 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4490 } else if (strstr(uri, "mms://")) {
4491 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4492 } else if ((path = strstr(uri, "mem://"))) {
4493 ret = __mmplayer_set_mem_uri(data, path, param);
4495 ret = __mmplayer_set_file_uri(data, uri);
4498 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4499 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4500 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4501 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4503 /* dump parse result */
4504 SECURE_LOGW("incoming uri : %s", uri);
4505 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4506 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4514 __mmplayer_can_do_interrupt(mmplayer_t *player)
4516 if (!player || !player->pipeline || !player->attrs) {
4517 LOGW("not initialized");
4521 if (player->audio_decoded_cb) {
4522 LOGW("not support in pcm extraction mode");
4526 /* check if seeking */
4527 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4528 MMMessageParamType msg_param;
4529 memset(&msg_param, 0, sizeof(MMMessageParamType));
4530 msg_param.code = MM_ERROR_PLAYER_SEEK;
4531 player->seek_state = MMPLAYER_SEEK_NONE;
4532 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4536 /* check other thread */
4537 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4538 LOGW("locked already, cmd state : %d", player->cmd);
4540 /* check application command */
4541 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4542 LOGW("playing.. should wait cmd lock then, will be interrupted");
4544 /* lock will be released at mrp_resource_release_cb() */
4545 MMPLAYER_CMD_LOCK(player);
4548 LOGW("nothing to do");
4551 LOGW("can interrupt immediately");
4555 FAILED: /* with CMD UNLOCKED */
4558 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4563 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4566 mmplayer_t *player = NULL;
4567 MMMessageParamType msg = {0, };
4569 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4574 LOGE("user_data is null");
4577 player = (mmplayer_t *)user_data;
4579 if (!__mmplayer_can_do_interrupt(player)) {
4580 LOGW("no need to interrupt, so leave");
4581 /* FIXME: there is no way to avoid releasing resource. */
4585 player->interrupted_by_resource = TRUE;
4587 /* get last play position */
4588 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4589 msg.union_type = MM_MSG_UNION_TIME;
4590 msg.time.elapsed = pos;
4591 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4593 LOGW("failed to get play position.");
4596 LOGD("video resource conflict so, resource will be freed by unrealizing");
4597 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4598 LOGE("failed to unrealize");
4600 /* lock is called in __mmplayer_can_do_interrupt() */
4601 MMPLAYER_CMD_UNLOCK(player);
4603 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4604 player->hw_resource[res_idx] = NULL;
4608 return TRUE; /* release all the resources */
4612 __mmplayer_initialize_video_roi(mmplayer_t *player)
4614 player->video_roi.scale_x = 0.0;
4615 player->video_roi.scale_y = 0.0;
4616 player->video_roi.scale_width = 1.0;
4617 player->video_roi.scale_height = 1.0;
4621 _mmplayer_create_player(MMHandleType handle)
4623 int ret = MM_ERROR_PLAYER_INTERNAL;
4624 bool enabled = false;
4626 mmplayer_t *player = MM_PLAYER_CAST(handle);
4630 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4632 /* initialize player state */
4633 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4634 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4635 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4636 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4638 /* check current state */
4639 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4641 /* construct attributes */
4642 player->attrs = _mmplayer_construct_attribute(handle);
4644 if (!player->attrs) {
4645 LOGE("Failed to construct attributes");
4649 /* initialize gstreamer with configured parameter */
4650 if (!__mmplayer_init_gstreamer(player)) {
4651 LOGE("Initializing gstreamer failed");
4652 _mmplayer_deconstruct_attribute(handle);
4656 /* create lock. note that g_tread_init() has already called in gst_init() */
4657 g_mutex_init(&player->fsink_lock);
4659 /* create update tag lock */
4660 g_mutex_init(&player->update_tag_lock);
4662 /* create gapless play mutex */
4663 g_mutex_init(&player->gapless_play_thread_mutex);
4665 /* create gapless play cond */
4666 g_cond_init(&player->gapless_play_thread_cond);
4668 /* create gapless play thread */
4669 player->gapless_play_thread =
4670 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4671 if (!player->gapless_play_thread) {
4672 LOGE("failed to create gapless play thread");
4673 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4674 g_mutex_clear(&player->gapless_play_thread_mutex);
4675 g_cond_clear(&player->gapless_play_thread_cond);
4679 player->bus_msg_q = g_queue_new();
4680 if (!player->bus_msg_q) {
4681 LOGE("failed to create queue for bus_msg");
4682 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4686 ret = _mmplayer_initialize_video_capture(player);
4687 if (ret != MM_ERROR_NONE) {
4688 LOGE("failed to initialize video capture");
4692 /* initialize resource manager */
4693 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4694 __resource_release_cb, player, &player->resource_manager)
4695 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4696 LOGE("failed to initialize resource manager");
4697 ret = MM_ERROR_PLAYER_INTERNAL;
4701 /* create video bo lock and cond */
4702 g_mutex_init(&player->video_bo_mutex);
4703 g_cond_init(&player->video_bo_cond);
4705 /* create subtitle info lock and cond */
4706 g_mutex_init(&player->subtitle_info_mutex);
4707 g_cond_init(&player->subtitle_info_cond);
4709 player->streaming_type = STREAMING_SERVICE_NONE;
4711 /* give default value of audio effect setting */
4712 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4713 player->sound.rg_enable = false;
4714 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4716 player->play_subtitle = FALSE;
4717 player->has_closed_caption = FALSE;
4718 player->pending_resume = FALSE;
4719 if (player->ini.dump_element_keyword[0][0] == '\0')
4720 player->ini.set_dump_element_flag = FALSE;
4722 player->ini.set_dump_element_flag = TRUE;
4724 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4725 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4726 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4728 /* Set video360 settings to their defaults for just-created player.
4731 player->is_360_feature_enabled = FALSE;
4732 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4733 LOGI("spherical feature info: %d", enabled);
4735 player->is_360_feature_enabled = TRUE;
4737 LOGE("failed to get spherical feature info");
4740 player->is_content_spherical = FALSE;
4741 player->is_video360_enabled = TRUE;
4742 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4743 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4744 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4745 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4746 player->video360_zoom = 1.0f;
4747 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4748 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4750 __mmplayer_initialize_video_roi(player);
4752 /* set player state to null */
4753 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4754 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4758 return MM_ERROR_NONE;
4762 g_mutex_clear(&player->fsink_lock);
4763 /* free update tag lock */
4764 g_mutex_clear(&player->update_tag_lock);
4765 g_queue_free(player->bus_msg_q);
4766 player->bus_msg_q = NULL;
4767 /* free gapless play thread */
4768 if (player->gapless_play_thread) {
4769 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4770 player->gapless_play_thread_exit = TRUE;
4771 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4772 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4774 g_thread_join(player->gapless_play_thread);
4775 player->gapless_play_thread = NULL;
4777 g_mutex_clear(&player->gapless_play_thread_mutex);
4778 g_cond_clear(&player->gapless_play_thread_cond);
4781 /* release attributes */
4782 _mmplayer_deconstruct_attribute(handle);
4790 __mmplayer_init_gstreamer(mmplayer_t *player)
4792 static gboolean initialized = FALSE;
4793 static const int max_argc = 50;
4795 gchar **argv = NULL;
4796 gchar **argv2 = NULL;
4802 LOGD("gstreamer already initialized.");
4807 argc = malloc(sizeof(int));
4808 argv = malloc(sizeof(gchar *) * max_argc);
4809 argv2 = malloc(sizeof(gchar *) * max_argc);
4811 if (!argc || !argv || !argv2)
4814 memset(argv, 0, sizeof(gchar *) * max_argc);
4815 memset(argv2, 0, sizeof(gchar *) * max_argc);
4819 argv[0] = g_strdup("mmplayer");
4822 for (i = 0; i < 5; i++) {
4823 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4824 if (strlen(player->ini.gst_param[i]) > 0) {
4825 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4830 /* we would not do fork for scanning plugins */
4831 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4834 /* check disable registry scan */
4835 if (player->ini.skip_rescan) {
4836 argv[*argc] = g_strdup("--gst-disable-registry-update");
4840 /* check disable segtrap */
4841 if (player->ini.disable_segtrap) {
4842 argv[*argc] = g_strdup("--gst-disable-segtrap");
4846 LOGD("initializing gstreamer with following parameter");
4847 LOGD("argc : %d", *argc);
4850 for (i = 0; i < arg_count; i++) {
4852 LOGD("argv[%d] : %s", i, argv2[i]);
4855 /* initializing gstreamer */
4856 if (!gst_init_check(argc, &argv, &err)) {
4857 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4864 for (i = 0; i < arg_count; i++) {
4865 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4866 MMPLAYER_FREEIF(argv2[i]);
4869 MMPLAYER_FREEIF(argv);
4870 MMPLAYER_FREEIF(argv2);
4871 MMPLAYER_FREEIF(argc);
4881 for (i = 0; i < arg_count; i++) {
4882 LOGD("free[%d] : %s", i, argv2[i]);
4883 MMPLAYER_FREEIF(argv2[i]);
4886 MMPLAYER_FREEIF(argv);
4887 MMPLAYER_FREEIF(argv2);
4888 MMPLAYER_FREEIF(argc);
4894 __mmplayer_check_async_state_transition(mmplayer_t *player)
4896 GstState element_state = GST_STATE_VOID_PENDING;
4897 GstState element_pending_state = GST_STATE_VOID_PENDING;
4898 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4899 GstElement *element = NULL;
4900 gboolean async = FALSE;
4902 /* check player handle */
4903 MMPLAYER_RETURN_IF_FAIL(player &&
4905 player->pipeline->mainbin &&
4906 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4909 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4911 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4912 LOGD("don't need to check the pipeline state");
4916 MMPLAYER_PRINT_STATE(player);
4918 /* wait for state transition */
4919 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4920 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4922 if (ret == GST_STATE_CHANGE_FAILURE) {
4923 LOGE(" [%s] state : %s pending : %s",
4924 GST_ELEMENT_NAME(element),
4925 gst_element_state_get_name(element_state),
4926 gst_element_state_get_name(element_pending_state));
4928 /* dump state of all element */
4929 _mmplayer_dump_pipeline_state(player);
4934 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4939 _mmplayer_destroy(MMHandleType handle)
4941 mmplayer_t *player = MM_PLAYER_CAST(handle);
4945 /* check player handle */
4946 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4948 /* destroy can called at anytime */
4949 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4951 /* check async state transition */
4952 __mmplayer_check_async_state_transition(player);
4954 /* release gapless play thread */
4955 if (player->gapless_play_thread) {
4956 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4957 player->gapless_play_thread_exit = TRUE;
4958 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4959 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4961 LOGD("waitting for gapless play thread exit");
4962 g_thread_join(player->gapless_play_thread);
4963 g_mutex_clear(&player->gapless_play_thread_mutex);
4964 g_cond_clear(&player->gapless_play_thread_cond);
4965 LOGD("gapless play thread released");
4968 _mmplayer_release_video_capture(player);
4970 /* de-initialize resource manager */
4971 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4972 player->resource_manager))
4973 LOGE("failed to deinitialize resource manager");
4975 /* release pipeline */
4976 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4977 LOGE("failed to destory pipeline");
4978 return MM_ERROR_PLAYER_INTERNAL;
4981 g_queue_free(player->bus_msg_q);
4983 /* release subtitle info lock and cond */
4984 g_mutex_clear(&player->subtitle_info_mutex);
4985 g_cond_clear(&player->subtitle_info_cond);
4987 __mmplayer_release_dump_list(player->dump_list);
4989 /* release miscellaneous information */
4990 __mmplayer_release_misc(player);
4992 /* release miscellaneous information.
4993 these info needs to be released after pipeline is destroyed. */
4994 __mmplayer_release_misc_post(player);
4996 /* release attributes */
4997 _mmplayer_deconstruct_attribute(handle);
5000 g_mutex_clear(&player->fsink_lock);
5003 g_mutex_clear(&player->update_tag_lock);
5005 /* release video bo lock and cond */
5006 g_mutex_clear(&player->video_bo_mutex);
5007 g_cond_clear(&player->video_bo_cond);
5011 return MM_ERROR_NONE;
5015 _mmplayer_realize(MMHandleType hplayer)
5017 mmplayer_t *player = (mmplayer_t *)hplayer;
5020 MMHandleType attrs = 0;
5021 int ret = MM_ERROR_NONE;
5025 /* check player handle */
5026 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5028 /* check current state */
5029 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5031 attrs = MMPLAYER_GET_ATTRS(player);
5033 LOGE("fail to get attributes.");
5034 return MM_ERROR_PLAYER_INTERNAL;
5036 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5037 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5039 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5040 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5042 if (ret != MM_ERROR_NONE) {
5043 LOGE("failed to parse profile");
5048 if (uri && (strstr(uri, "es_buff://"))) {
5049 if (strstr(uri, "es_buff://push_mode"))
5050 player->es_player_push_mode = TRUE;
5052 player->es_player_push_mode = FALSE;
5055 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5056 LOGW("mms protocol is not supported format.");
5057 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5060 if (MMPLAYER_IS_STREAMING(player))
5061 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5063 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5065 player->smooth_streaming = FALSE;
5066 player->videodec_linked = 0;
5067 player->audiodec_linked = 0;
5068 player->textsink_linked = 0;
5069 player->is_external_subtitle_present = FALSE;
5070 player->is_external_subtitle_added_now = FALSE;
5071 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5072 player->video360_metadata.is_spherical = -1;
5073 player->is_openal_plugin_used = FALSE;
5074 player->demux_pad_index = 0;
5075 player->subtitle_language_list = NULL;
5076 player->is_subtitle_force_drop = FALSE;
5078 _mmplayer_track_initialize(player);
5079 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5081 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5082 gint prebuffer_ms = 0, rebuffer_ms = 0;
5084 player->streamer = _mm_player_streaming_create();
5085 _mm_player_streaming_initialize(player->streamer, TRUE);
5087 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5088 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5090 if (prebuffer_ms > 0) {
5091 prebuffer_ms = MAX(prebuffer_ms, 1000);
5092 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5095 if (rebuffer_ms > 0) {
5096 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5097 rebuffer_ms = MAX(rebuffer_ms, 1000);
5098 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5101 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5102 player->streamer->buffering_req.rebuffer_time);
5105 /* realize pipeline */
5106 ret = __mmplayer_gst_realize(player);
5107 if (ret != MM_ERROR_NONE)
5108 LOGE("fail to realize the player.");
5110 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5118 _mmplayer_unrealize(MMHandleType hplayer)
5120 mmplayer_t *player = (mmplayer_t *)hplayer;
5121 int ret = MM_ERROR_NONE;
5125 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5127 MMPLAYER_CMD_UNLOCK(player);
5128 /* destroy the gst bus msg thread which is created during realize.
5129 this funct have to be called before getting cmd lock. */
5130 _mmplayer_bus_msg_thread_destroy(player);
5131 MMPLAYER_CMD_LOCK(player);
5133 /* check current state */
5134 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5136 /* check async state transition */
5137 __mmplayer_check_async_state_transition(player);
5139 /* unrealize pipeline */
5140 ret = __mmplayer_gst_unrealize(player);
5142 if (!player->interrupted_by_resource) {
5143 if ((__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) ||
5144 (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE))
5145 LOGE("failed to release video resources");
5153 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5155 mmplayer_t *player = (mmplayer_t *)hplayer;
5157 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5159 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5163 _mmplayer_get_state(MMHandleType hplayer, int *state)
5165 mmplayer_t *player = (mmplayer_t *)hplayer;
5167 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5169 *state = MMPLAYER_CURRENT_STATE(player);
5171 return MM_ERROR_NONE;
5175 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5177 GstElement *vol_element = NULL;
5178 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5181 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5182 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5184 /* check pipeline handle */
5185 if (!player->pipeline || !player->pipeline->audiobin) {
5186 LOGD("'%s' will be applied when audiobin is created", prop_name);
5188 /* NOTE : stored value will be used in create_audiobin
5189 * returning MM_ERROR_NONE here makes application to able to
5190 * set audio volume or mute at anytime.
5192 return MM_ERROR_NONE;
5195 if (player->build_audio_offload) {
5196 LOGD("offload pipeline");
5197 volume_elem_id = MMPLAYER_A_SINK;
5200 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5202 LOGE("failed to get vol element %d", volume_elem_id);
5203 return MM_ERROR_PLAYER_INTERNAL;
5206 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5208 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5209 LOGE("there is no '%s' property", prop_name);
5210 return MM_ERROR_PLAYER_INTERNAL;
5213 if (!strcmp(prop_name, "volume")) {
5214 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5215 } else if (!strcmp(prop_name, "mute")) {
5216 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5218 LOGE("invalid property %s", prop_name);
5219 return MM_ERROR_PLAYER_INTERNAL;
5222 return MM_ERROR_NONE;
5226 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5228 int ret = MM_ERROR_NONE;
5229 mmplayer_t *player = (mmplayer_t *)hplayer;
5232 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5234 LOGD("volume = %f", volume);
5236 /* invalid factor range or not */
5237 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5238 LOGE("Invalid volume value");
5239 return MM_ERROR_INVALID_ARGUMENT;
5242 player->sound.volume = volume;
5244 ret = __mmplayer_gst_set_volume_property(player, "volume");
5251 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5253 mmplayer_t *player = (mmplayer_t *)hplayer;
5257 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5258 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5260 *volume = player->sound.volume;
5262 LOGD("current vol = %f", *volume);
5265 return MM_ERROR_NONE;
5269 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5271 int ret = MM_ERROR_NONE;
5272 mmplayer_t *player = (mmplayer_t *)hplayer;
5275 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5277 LOGD("mute = %d", mute);
5279 player->sound.mute = mute;
5281 ret = __mmplayer_gst_set_volume_property(player, "mute");
5288 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5290 mmplayer_t *player = (mmplayer_t *)hplayer;
5294 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5295 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5297 *mute = player->sound.mute;
5299 LOGD("current mute = %d", *mute);
5303 return MM_ERROR_NONE;
5307 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5309 mmplayer_t *player = (mmplayer_t *)hplayer;
5313 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5315 player->audio_stream_changed_cb = callback;
5316 player->audio_stream_changed_cb_user_param = user_param;
5317 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5321 return MM_ERROR_NONE;
5325 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5327 mmplayer_t *player = (mmplayer_t *)hplayer;
5331 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5333 player->audio_decoded_cb = callback;
5334 player->audio_decoded_cb_user_param = user_param;
5335 player->audio_extract_opt = opt;
5336 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5340 return MM_ERROR_NONE;
5344 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5346 mmplayer_t *player = (mmplayer_t *)hplayer;
5350 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5352 if (callback && !player->bufmgr)
5353 player->bufmgr = tbm_bufmgr_init(-1);
5355 player->set_mode.video_export = (callback) ? true : false;
5356 player->video_decoded_cb = callback;
5357 player->video_decoded_cb_user_param = user_param;
5359 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5363 return MM_ERROR_NONE;
5367 _mmplayer_start(MMHandleType hplayer)
5369 mmplayer_t *player = (mmplayer_t *)hplayer;
5370 gint ret = MM_ERROR_NONE;
5374 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5376 /* check current state */
5377 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5379 /* start pipeline */
5380 ret = _mmplayer_gst_start(player);
5381 if (ret != MM_ERROR_NONE)
5382 LOGE("failed to start player.");
5384 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5385 LOGD("force playing start even during buffering");
5386 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5394 /* NOTE: post "not supported codec message" to application
5395 * when one codec is not found during AUTOPLUGGING in MSL.
5396 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5397 * And, if any codec is not found, don't send message here.
5398 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5401 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5403 MMMessageParamType msg_param;
5404 memset(&msg_param, 0, sizeof(MMMessageParamType));
5405 gboolean post_msg_direct = FALSE;
5409 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5411 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5412 player->not_supported_codec, player->can_support_codec);
5414 if (player->not_found_demuxer) {
5415 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5416 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5418 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5419 MMPLAYER_FREEIF(msg_param.data);
5421 return MM_ERROR_NONE;
5424 if (player->not_supported_codec) {
5425 if (player->can_support_codec) {
5426 // There is one codec to play
5427 post_msg_direct = TRUE;
5429 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5430 post_msg_direct = TRUE;
5433 if (post_msg_direct) {
5434 MMMessageParamType msg_param;
5435 memset(&msg_param, 0, sizeof(MMMessageParamType));
5437 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5438 LOGW("not found AUDIO codec, posting error code to application.");
5440 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5441 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5442 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5443 LOGW("not found VIDEO codec, posting error code to application.");
5445 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5446 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5449 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5451 MMPLAYER_FREEIF(msg_param.data);
5453 return MM_ERROR_NONE;
5455 // no any supported codec case
5456 LOGW("not found any codec, posting error code to application.");
5458 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5459 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5460 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5462 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5463 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5466 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5468 MMPLAYER_FREEIF(msg_param.data);
5474 return MM_ERROR_NONE;
5478 __mmplayer_check_pipeline(mmplayer_t *player)
5480 GstState element_state = GST_STATE_VOID_PENDING;
5481 GstState element_pending_state = GST_STATE_VOID_PENDING;
5483 int ret = MM_ERROR_NONE;
5485 if (!player->gapless.reconfigure)
5488 LOGW("pipeline is under construction.");
5490 MMPLAYER_PLAYBACK_LOCK(player);
5491 MMPLAYER_PLAYBACK_UNLOCK(player);
5493 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5495 /* wait for state transition */
5496 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5497 if (ret == GST_STATE_CHANGE_FAILURE)
5498 LOGE("failed to change pipeline state within %d sec", timeout);
5501 /* NOTE : it should be able to call 'stop' anytime*/
5503 _mmplayer_stop(MMHandleType hplayer)
5505 mmplayer_t *player = (mmplayer_t *)hplayer;
5506 int ret = MM_ERROR_NONE;
5510 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5512 /* check current state */
5513 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5515 /* check pipline building state */
5516 __mmplayer_check_pipeline(player);
5517 __mmplayer_reset_gapless_state(player);
5519 /* NOTE : application should not wait for EOS after calling STOP */
5520 _mmplayer_cancel_eos_timer(player);
5523 player->seek_state = MMPLAYER_SEEK_NONE;
5526 ret = _mmplayer_gst_stop(player);
5528 if (ret != MM_ERROR_NONE)
5529 LOGE("failed to stop player.");
5537 _mmplayer_pause(MMHandleType hplayer)
5539 mmplayer_t *player = (mmplayer_t *)hplayer;
5540 gint64 pos_nsec = 0;
5541 gboolean async = FALSE;
5542 gint ret = MM_ERROR_NONE;
5546 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5548 /* check current state */
5549 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5551 /* check pipline building state */
5552 __mmplayer_check_pipeline(player);
5554 switch (MMPLAYER_CURRENT_STATE(player)) {
5555 case MM_PLAYER_STATE_READY:
5557 /* check prepare async or not.
5558 * In the case of streaming playback, it's recommned to avoid blocking wait.
5560 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5561 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5563 /* Changing back sync of rtspsrc to async */
5564 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5565 LOGD("async prepare working mode for rtsp");
5571 case MM_PLAYER_STATE_PLAYING:
5573 /* NOTE : store current point to overcome some bad operation
5574 *(returning zero when getting current position in paused state) of some
5577 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5578 LOGW("getting current position failed in paused");
5580 player->last_position = pos_nsec;
5582 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5583 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5584 This causes problem is position calculation during normal pause resume scenarios also.
5585 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5586 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5587 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5588 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5594 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5595 LOGD("doing async pause in case of ms buff src");
5599 /* pause pipeline */
5600 ret = _mmplayer_gst_pause(player, async);
5602 if (ret != MM_ERROR_NONE)
5603 LOGE("failed to pause player. ret : 0x%x", ret);
5605 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5606 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5607 LOGE("failed to update display_rotation");
5615 /* in case of streaming, pause could take long time.*/
5617 _mmplayer_abort_pause(MMHandleType hplayer)
5619 mmplayer_t *player = (mmplayer_t *)hplayer;
5620 int ret = MM_ERROR_NONE;
5624 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5626 player->pipeline->mainbin,
5627 MM_ERROR_PLAYER_NOT_INITIALIZED);
5629 LOGD("set the pipeline state to READY");
5631 /* set state to READY */
5632 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5633 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5634 if (ret != MM_ERROR_NONE) {
5635 LOGE("fail to change state to READY");
5636 return MM_ERROR_PLAYER_INTERNAL;
5639 LOGD("succeeded in changing state to READY");
5644 _mmplayer_resume(MMHandleType hplayer)
5646 mmplayer_t *player = (mmplayer_t *)hplayer;
5647 int ret = MM_ERROR_NONE;
5648 gboolean async = FALSE;
5652 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5654 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5655 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5656 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5660 /* Changing back sync mode rtspsrc to async */
5661 LOGD("async resume for rtsp case");
5665 /* check current state */
5666 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5668 ret = _mmplayer_gst_resume(player, async);
5669 if (ret != MM_ERROR_NONE)
5670 LOGE("failed to resume player.");
5672 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5673 LOGD("force resume even during buffering");
5674 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5683 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5685 mmplayer_t *player = (mmplayer_t *)hplayer;
5686 gint64 pos_nsec = 0;
5687 int ret = MM_ERROR_NONE;
5689 signed long long start = 0, stop = 0;
5690 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5693 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5694 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5696 /* The sound of video is not supported under 0.0 and over 2.0. */
5697 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5698 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5701 _mmplayer_set_mute(hplayer, mute);
5703 if (player->playback_rate == rate)
5704 return MM_ERROR_NONE;
5706 /* If the position is reached at start potion during fast backward, EOS is posted.
5707 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5709 player->playback_rate = rate;
5711 current_state = MMPLAYER_CURRENT_STATE(player);
5713 if (current_state != MM_PLAYER_STATE_PAUSED)
5714 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5716 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5718 if ((current_state == MM_PLAYER_STATE_PAUSED)
5719 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5720 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5721 pos_nsec = player->last_position;
5726 stop = GST_CLOCK_TIME_NONE;
5728 start = GST_CLOCK_TIME_NONE;
5732 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5733 player->playback_rate,
5735 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5736 GST_SEEK_TYPE_SET, start,
5737 GST_SEEK_TYPE_SET, stop)) {
5738 LOGE("failed to set speed playback");
5739 return MM_ERROR_PLAYER_SEEK;
5742 LOGD("succeeded to set speed playback as %0.1f", rate);
5746 return MM_ERROR_NONE;;
5750 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5752 mmplayer_t *player = (mmplayer_t *)hplayer;
5753 int ret = MM_ERROR_NONE;
5757 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5759 /* check pipline building state */
5760 __mmplayer_check_pipeline(player);
5762 ret = _mmplayer_gst_set_position(player, position, FALSE);
5770 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5772 mmplayer_t *player = (mmplayer_t *)hplayer;
5773 int ret = MM_ERROR_NONE;
5775 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5776 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5778 if (g_strrstr(player->type, "video/mpegts"))
5779 __mmplayer_update_duration_value(player);
5781 *duration = player->duration;
5786 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5788 mmplayer_t *player = (mmplayer_t *)hplayer;
5789 int ret = MM_ERROR_NONE;
5791 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5793 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5799 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5801 mmplayer_t *player = (mmplayer_t *)hplayer;
5802 int ret = MM_ERROR_NONE;
5806 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5808 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5816 __mmplayer_is_midi_type(gchar *str_caps)
5818 if ((g_strrstr(str_caps, "audio/midi")) ||
5819 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5820 (g_strrstr(str_caps, "application/x-smaf")) ||
5821 (g_strrstr(str_caps, "audio/x-imelody")) ||
5822 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5823 (g_strrstr(str_caps, "audio/xmf")) ||
5824 (g_strrstr(str_caps, "audio/mxmf"))) {
5833 __mmplayer_is_only_mp3_type(gchar *str_caps)
5835 if (g_strrstr(str_caps, "application/x-id3") ||
5836 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5842 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5844 GstStructure *caps_structure = NULL;
5845 gint samplerate = 0;
5849 MMPLAYER_RETURN_IF_FAIL(player && caps);
5851 caps_structure = gst_caps_get_structure(caps, 0);
5853 /* set stream information */
5854 gst_structure_get_int(caps_structure, "rate", &samplerate);
5855 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5857 gst_structure_get_int(caps_structure, "channels", &channels);
5858 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5860 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5864 __mmplayer_update_content_type_info(mmplayer_t *player)
5867 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5869 if (__mmplayer_is_midi_type(player->type)) {
5870 player->bypass_audio_effect = TRUE;
5874 if (!player->streamer) {
5875 LOGD("no need to check streaming type");
5879 if (g_strrstr(player->type, "application/x-hls")) {
5880 /* If it can't know exact type when it parses uri because of redirection case,
5881 * it will be fixed by typefinder or when doing autoplugging.
5883 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5884 player->streamer->is_adaptive_streaming = TRUE;
5885 } else if (g_strrstr(player->type, "application/dash+xml")) {
5886 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5887 player->streamer->is_adaptive_streaming = TRUE;
5890 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5891 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5892 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5894 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5895 if (player->streamer->is_adaptive_streaming)
5896 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5898 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5902 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5907 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5908 GstCaps *caps, gpointer data)
5910 mmplayer_t *player = (mmplayer_t *)data;
5915 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5917 /* store type string */
5918 MMPLAYER_FREEIF(player->type);
5919 player->type = gst_caps_to_string(caps);
5921 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5922 player, player->type, probability, gst_caps_get_size(caps));
5924 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5925 (g_strrstr(player->type, "audio/x-raw-int"))) {
5926 LOGE("not support media format");
5928 if (player->msg_posted == FALSE) {
5929 MMMessageParamType msg_param;
5930 memset(&msg_param, 0, sizeof(MMMessageParamType));
5932 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5933 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5935 /* don't post more if one was sent already */
5936 player->msg_posted = TRUE;
5941 __mmplayer_update_content_type_info(player);
5943 pad = gst_element_get_static_pad(tf, "src");
5945 LOGE("fail to get typefind src pad.");
5949 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5950 gboolean async = FALSE;
5951 LOGE("failed to autoplug %s", player->type);
5953 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5955 if (async && player->msg_posted == FALSE)
5956 __mmplayer_handle_missed_plugin(player);
5960 gst_object_unref(GST_OBJECT(pad));
5968 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5970 GstElement *decodebin = NULL;
5974 /* create decodebin */
5975 decodebin = gst_element_factory_make("decodebin", NULL);
5978 LOGE("fail to create decodebin");
5982 /* raw pad handling signal */
5983 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5984 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5986 /* no-more-pad pad handling signal */
5987 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5988 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5990 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5991 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5993 /* This signal is emitted when a pad for which there is no further possible
5994 decoding is added to the decodebin.*/
5995 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5996 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5998 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5999 before looking for any elements that can handle that stream.*/
6000 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6001 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6003 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6004 before looking for any elements that can handle that stream.*/
6005 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6006 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6008 /* This signal is emitted once decodebin has finished decoding all the data.*/
6009 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6010 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6012 /* This signal is emitted when a element is added to the bin.*/
6013 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6014 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6021 __mmplayer_gst_make_queue2(mmplayer_t *player)
6023 GstElement *queue2 = NULL;
6024 gint64 dur_bytes = 0L;
6025 mmplayer_gst_element_t *mainbin = NULL;
6026 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6029 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6031 mainbin = player->pipeline->mainbin;
6033 queue2 = gst_element_factory_make("queue2", "queue2");
6035 LOGE("failed to create buffering queue element");
6039 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6040 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6042 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6044 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6045 * skip the pull mode(file or ring buffering) setting. */
6046 if (dur_bytes > 0) {
6047 if (!g_strrstr(player->type, "video/mpegts")) {
6048 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6049 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6055 _mm_player_streaming_set_queue2(player->streamer,
6059 (guint64)dur_bytes); /* no meaning at the moment */
6065 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6067 mmplayer_gst_element_t *mainbin = NULL;
6068 GstElement *decodebin = NULL;
6069 GstElement *queue2 = NULL;
6070 GstPad *sinkpad = NULL;
6071 GstPad *qsrcpad = NULL;
6074 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6076 mainbin = player->pipeline->mainbin;
6078 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6080 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6081 LOGW("need to check: muxed buffer is not null");
6084 queue2 = __mmplayer_gst_make_queue2(player);
6086 LOGE("failed to make queue2");
6090 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6091 LOGE("failed to add buffering queue");
6095 sinkpad = gst_element_get_static_pad(queue2, "sink");
6096 qsrcpad = gst_element_get_static_pad(queue2, "src");
6098 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6099 LOGE("failed to link [%s:%s]-[%s:%s]",
6100 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6104 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6105 LOGE("failed to sync queue2 state with parent");
6109 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6110 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6114 gst_object_unref(GST_OBJECT(sinkpad));
6118 /* create decodebin */
6119 decodebin = _mmplayer_gst_make_decodebin(player);
6121 LOGE("failed to make decodebin");
6125 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6126 LOGE("failed to add decodebin");
6130 /* to force caps on the decodebin element and avoid reparsing stuff by
6131 * typefind. It also avoids a deadlock in the way typefind activates pads in
6132 * the state change */
6133 g_object_set(decodebin, "sink-caps", caps, NULL);
6135 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6137 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6138 LOGE("failed to link [%s:%s]-[%s:%s]",
6139 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6143 gst_object_unref(GST_OBJECT(sinkpad));
6145 gst_object_unref(GST_OBJECT(qsrcpad));
6148 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6149 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6151 /* set decodebin property about buffer in streaming playback. *
6152 * in case of HLS/DASH, it does not need to have big buffer *
6153 * because it is kind of adaptive streaming. */
6154 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6155 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6156 gint high_percent = 0;
6158 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6159 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6161 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6163 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6165 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6166 "high-percent", high_percent,
6167 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6168 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6169 "max-size-buffers", 0, NULL); // disable or automatic
6172 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6173 LOGE("failed to sync decodebin state with parent");
6184 gst_object_unref(GST_OBJECT(sinkpad));
6187 gst_object_unref(GST_OBJECT(qsrcpad));
6190 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6191 * You need to explicitly set elements to the NULL state before
6192 * dropping the final reference, to allow them to clean up.
6194 gst_element_set_state(queue2, GST_STATE_NULL);
6196 /* And, it still has a parent "player".
6197 * You need to let the parent manage the object instead of unreffing the object directly.
6199 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6200 gst_object_unref(queue2);
6205 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6206 * You need to explicitly set elements to the NULL state before
6207 * dropping the final reference, to allow them to clean up.
6209 gst_element_set_state(decodebin, GST_STATE_NULL);
6211 /* And, it still has a parent "player".
6212 * You need to let the parent manage the object instead of unreffing the object directly.
6215 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6216 gst_object_unref(decodebin);
6224 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6228 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6229 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6231 LOGD("class : %s, mime : %s", factory_class, mime);
6233 /* add missing plugin */
6234 /* NOTE : msl should check missing plugin for image mime type.
6235 * Some motion jpeg clips can have playable audio track.
6236 * So, msl have to play audio after displaying popup written video format not supported.
6238 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6239 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6240 LOGD("not found demuxer");
6241 player->not_found_demuxer = TRUE;
6242 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6248 if (!g_strrstr(factory_class, "Demuxer")) {
6249 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6250 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6251 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6253 /* check that clip have multi tracks or not */
6254 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6255 LOGD("video plugin is already linked");
6257 LOGW("add VIDEO to missing plugin");
6258 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6259 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6261 } else if (g_str_has_prefix(mime, "audio")) {
6262 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6263 LOGD("audio plugin is already linked");
6265 LOGW("add AUDIO to missing plugin");
6266 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6267 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6275 return MM_ERROR_NONE;
6279 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6281 mmplayer_t *player = (mmplayer_t *)data;
6285 MMPLAYER_RETURN_IF_FAIL(player);
6287 /* remove fakesink. */
6288 if (!_mmplayer_gst_remove_fakesink(player,
6289 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6290 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6291 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6292 * source element are not same. To overcome this situation, this function will called
6293 * several places and several times. Therefore, this is not an error case.
6298 LOGD("[handle: %p] pipeline has completely constructed", player);
6300 if ((player->ini.async_start) &&
6301 (player->msg_posted == FALSE) &&
6302 (player->cmd >= MMPLAYER_COMMAND_START))
6303 __mmplayer_handle_missed_plugin(player);
6305 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6309 __mmplayer_check_profile(void)
6312 static int profile_tv = -1;
6314 if (__builtin_expect(profile_tv != -1, 1))
6317 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6318 switch (*profileName) {
6333 __mmplayer_get_next_uri(mmplayer_t *player)
6335 mmplayer_parse_profile_t profile;
6337 guint num_of_list = 0;
6340 num_of_list = g_list_length(player->uri_info.uri_list);
6341 uri_idx = player->uri_info.uri_idx;
6343 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6344 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6345 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6347 LOGW("next uri does not exist");
6351 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6352 LOGE("failed to parse profile");
6356 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6357 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6358 LOGW("uri type is not supported(%d)", profile.uri_type);
6362 LOGD("success to find next uri %d", uri_idx);
6366 if (uri_idx == num_of_list) {
6367 LOGE("failed to find next uri");
6371 player->uri_info.uri_idx = uri_idx;
6372 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6374 if (mm_attrs_commit_all(player->attrs)) {
6375 LOGE("failed to commit");
6379 SECURE_LOGD("next playback uri: %s", uri);
6384 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6386 #define REPEAT_COUNT_INFINITE -1
6387 #define REPEAT_COUNT_MIN 2
6388 #define ORIGINAL_URI_ONLY 1
6390 MMHandleType attrs = 0;
6394 guint num_of_uri = 0;
6395 int profile_tv = -1;
6399 LOGD("checking for gapless play option");
6401 if (player->pipeline->textbin) {
6402 LOGE("subtitle path is enabled. gapless play is not supported.");
6406 attrs = MMPLAYER_GET_ATTRS(player);
6408 LOGE("fail to get attributes.");
6412 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6414 /* gapless playback is not supported in case of video at TV profile. */
6415 profile_tv = __mmplayer_check_profile();
6416 if (profile_tv && video) {
6417 LOGW("not support video gapless playback");
6421 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6422 LOGE("failed to get play count");
6424 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6425 LOGE("failed to get gapless mode");
6427 /* check repeat count in case of audio */
6429 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6430 LOGW("gapless is disabled");
6434 num_of_uri = g_list_length(player->uri_info.uri_list);
6436 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6438 if (num_of_uri == ORIGINAL_URI_ONLY) {
6439 /* audio looping path */
6440 if (count >= REPEAT_COUNT_MIN) {
6441 /* decrease play count */
6442 /* we succeeded to rewind. update play count and then wait for next EOS */
6444 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6445 /* commit attribute */
6446 if (mm_attrs_commit_all(attrs))
6447 LOGE("failed to commit attribute");
6449 } else if (count != REPEAT_COUNT_INFINITE) {
6450 LOGD("there is no next uri and no repeat");
6453 LOGD("looping cnt %d", count);
6455 /* gapless playback path */
6456 if (!__mmplayer_get_next_uri(player)) {
6457 LOGE("failed to get next uri");
6464 LOGE("unable to play gapless path. EOS will be posted soon");
6469 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6471 mmplayer_selector_t *selector = &player->selector[type];
6472 mmplayer_gst_element_t *sinkbin = NULL;
6473 main_element_id_e selectorId = MMPLAYER_M_NUM;
6474 main_element_id_e sinkId = MMPLAYER_M_NUM;
6475 GstPad *srcpad = NULL;
6476 GstPad *sinkpad = NULL;
6477 gboolean send_notice = FALSE;
6480 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6482 LOGD("type %d", type);
6485 case MM_PLAYER_TRACK_TYPE_AUDIO:
6486 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6487 sinkId = MMPLAYER_A_BIN;
6488 sinkbin = player->pipeline->audiobin;
6490 case MM_PLAYER_TRACK_TYPE_VIDEO:
6491 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6492 sinkId = MMPLAYER_V_BIN;
6493 sinkbin = player->pipeline->videobin;
6496 case MM_PLAYER_TRACK_TYPE_TEXT:
6497 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6498 sinkId = MMPLAYER_T_BIN;
6499 sinkbin = player->pipeline->textbin;
6502 LOGE("requested type is not supportable");
6507 if (player->pipeline->mainbin[selectorId].gst) {
6510 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6512 if (selector->event_probe_id != 0)
6513 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6514 selector->event_probe_id = 0;
6516 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6517 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6519 if (srcpad && sinkpad) {
6520 /* after getting drained signal there is no data flows, so no need to do pad_block */
6521 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6522 gst_pad_unlink(srcpad, sinkpad);
6524 /* send custom event to sink pad to handle it at video sink */
6526 LOGD("send custom event to sinkpad");
6527 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6528 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6529 gst_pad_send_event(sinkpad, event);
6533 gst_object_unref(sinkpad);
6536 gst_object_unref(srcpad);
6539 LOGD("selector release");
6541 /* release and unref requests pad from the selector */
6542 for (n = 0; n < selector->channels->len; n++) {
6543 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6544 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6546 g_ptr_array_set_size(selector->channels, 0);
6548 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6549 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6551 player->pipeline->mainbin[selectorId].gst = NULL;
6559 __mmplayer_deactivate_old_path(mmplayer_t *player)
6562 MMPLAYER_RETURN_IF_FAIL(player);
6564 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6565 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6566 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6567 LOGE("deactivate selector error");
6571 _mmplayer_track_destroy(player);
6572 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6574 if (player->streamer) {
6575 _mm_player_streaming_initialize(player->streamer, FALSE);
6576 _mm_player_streaming_destroy(player->streamer);
6577 player->streamer = NULL;
6580 MMPLAYER_PLAYBACK_LOCK(player);
6581 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6588 if (!player->msg_posted) {
6589 MMMessageParamType msg = {0,};
6592 msg.code = MM_ERROR_PLAYER_INTERNAL;
6593 LOGE("gapless_uri_play> deactivate error");
6595 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6596 player->msg_posted = TRUE;
6602 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6604 int result = MM_ERROR_NONE;
6605 mmplayer_t *player = (mmplayer_t *)hplayer;
6608 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6610 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6611 if (mm_attrs_commit_all(player->attrs)) {
6612 LOGE("failed to commit the original uri.");
6613 result = MM_ERROR_PLAYER_INTERNAL;
6615 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6616 LOGE("failed to add the original uri in the uri list.");
6624 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6626 mmplayer_t *player = (mmplayer_t *)hplayer;
6627 guint num_of_list = 0;
6631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6632 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6634 if (player->pipeline && player->pipeline->textbin) {
6635 LOGE("subtitle path is enabled.");
6636 return MM_ERROR_PLAYER_INVALID_STATE;
6639 num_of_list = g_list_length(player->uri_info.uri_list);
6641 if (is_first_path) {
6642 if (num_of_list == 0) {
6643 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6644 SECURE_LOGD("add original path : %s", uri);
6646 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6647 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6649 SECURE_LOGD("change original path : %s", uri);
6652 MMHandleType attrs = 0;
6653 attrs = MMPLAYER_GET_ATTRS(player);
6655 if (num_of_list == 0) {
6656 char *original_uri = NULL;
6659 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6661 if (!original_uri) {
6662 LOGE("there is no original uri.");
6663 return MM_ERROR_PLAYER_INVALID_STATE;
6666 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6667 player->uri_info.uri_idx = 0;
6669 SECURE_LOGD("add original path at first : %s", original_uri);
6673 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6674 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6678 return MM_ERROR_NONE;
6682 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6684 mmplayer_t *player = (mmplayer_t *)hplayer;
6685 char *next_uri = NULL;
6686 guint num_of_list = 0;
6689 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6691 num_of_list = g_list_length(player->uri_info.uri_list);
6693 if (num_of_list > 0) {
6694 gint uri_idx = player->uri_info.uri_idx;
6696 if (uri_idx < num_of_list-1)
6701 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6702 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6704 *uri = g_strdup(next_uri);
6708 return MM_ERROR_NONE;
6712 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6713 GstCaps *caps, gpointer data)
6715 mmplayer_t *player = (mmplayer_t *)data;
6716 const gchar *klass = NULL;
6717 const gchar *mime = NULL;
6718 gchar *caps_str = NULL;
6720 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6721 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6722 caps_str = gst_caps_to_string(caps);
6724 LOGW("unknown type of caps : %s from %s",
6725 caps_str, GST_ELEMENT_NAME(elem));
6727 MMPLAYER_FREEIF(caps_str);
6729 /* There is no available codec. */
6730 __mmplayer_check_not_supported_codec(player, klass, mime);
6734 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6735 GstCaps *caps, gpointer data)
6737 mmplayer_t *player = (mmplayer_t *)data;
6738 const char *mime = NULL;
6739 gboolean ret = TRUE;
6741 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6742 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6744 if (g_str_has_prefix(mime, "audio")) {
6745 GstStructure *caps_structure = NULL;
6746 gint samplerate = 0;
6748 gchar *caps_str = NULL;
6750 caps_structure = gst_caps_get_structure(caps, 0);
6751 gst_structure_get_int(caps_structure, "rate", &samplerate);
6752 gst_structure_get_int(caps_structure, "channels", &channels);
6754 if ((channels > 0 && samplerate == 0)) {
6755 LOGD("exclude audio...");
6759 caps_str = gst_caps_to_string(caps);
6760 /* set it directly because not sent by TAG */
6761 if (g_strrstr(caps_str, "mobile-xmf"))
6762 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6763 MMPLAYER_FREEIF(caps_str);
6764 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6765 MMMessageParamType msg_param;
6766 memset(&msg_param, 0, sizeof(MMMessageParamType));
6767 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6768 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6769 LOGD("video file is not supported on this device");
6771 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6772 LOGD("already video linked");
6775 LOGD("found new stream");
6782 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6784 gboolean ret = TRUE;
6785 GDBusConnection *conn = NULL;
6787 GVariant *result = NULL;
6788 const gchar *dbus_device_type = NULL;
6789 const gchar *dbus_ret = NULL;
6792 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6794 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6800 result = g_dbus_connection_call_sync(conn,
6801 "org.pulseaudio.Server",
6802 "/org/pulseaudio/StreamManager",
6803 "org.pulseaudio.StreamManager",
6804 "GetCurrentMediaRoutingPath",
6805 g_variant_new("(s)", "out"),
6806 G_VARIANT_TYPE("(ss)"),
6807 G_DBUS_CALL_FLAGS_NONE,
6811 if (!result || err) {
6812 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6818 /* device type is listed in stream-map.json at mmfw-sysconf */
6819 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6821 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6822 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6827 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6828 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6829 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6830 LOGD("audio offload is supportable");
6836 LOGD("audio offload is not supportable");
6840 g_variant_unref(result);
6841 g_object_unref(conn);
6846 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6848 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6849 gint64 position = 0;
6851 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6852 player->pipeline && player->pipeline->mainbin);
6854 MMPLAYER_CMD_LOCK(player);
6855 current_state = MMPLAYER_CURRENT_STATE(player);
6857 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6858 LOGW("getting current position failed in paused");
6860 _mmplayer_unrealize((MMHandleType)player);
6861 _mmplayer_realize((MMHandleType)player);
6863 _mmplayer_set_position((MMHandleType)player, position);
6865 /* async not to be blocked in streaming case */
6866 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6867 if (mm_attrs_commit_all(player->attrs))
6868 LOGE("failed to commit");
6870 _mmplayer_pause((MMHandleType)player);
6872 if (current_state == MM_PLAYER_STATE_PLAYING)
6873 _mmplayer_start((MMHandleType)player);
6874 MMPLAYER_CMD_UNLOCK(player);
6876 LOGD("rebuilding audio pipeline is completed.");
6879 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6881 mmplayer_t *player = (mmplayer_t *)user_data;
6882 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6883 gboolean is_supportable = FALSE;
6885 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6886 LOGW("failed to get device type");
6888 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6890 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6891 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6892 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6893 LOGD("ignore this dev connected info");
6897 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6898 if (player->build_audio_offload == is_supportable) {
6899 LOGD("keep current pipeline without re-building");
6903 /* rebuild pipeline */
6904 LOGD("re-build pipeline - offload: %d", is_supportable);
6905 player->build_audio_offload = FALSE;
6906 __mmplayer_rebuild_audio_pipeline(player);
6912 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6914 unsigned int id = 0;
6916 if (player->audio_device_cb_id != 0) {
6917 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6921 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6922 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6923 LOGD("added device connected cb (%u)", id);
6924 player->audio_device_cb_id = id;
6926 LOGW("failed to add device connected cb");
6934 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6936 gboolean ret = FALSE;
6937 GstElementFactory *factory = NULL;
6940 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6942 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6943 if (!__mmplayer_is_only_mp3_type(player->type))
6946 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6947 LOGD("there is no audio offload sink");
6951 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6952 LOGW("there is no audio device type to support offload");
6956 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6958 LOGW("there is no installed audio offload sink element");
6961 gst_object_unref(factory);
6963 if (!__mmplayer_add_audio_device_connected_cb(player))
6966 if (!__mmplayer_is_audio_offload_device_type(player))
6969 LOGD("audio offload can be built");
6977 static GstAutoplugSelectResult
6978 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6980 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6982 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6983 int audio_offload = 0;
6985 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6986 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6988 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6989 LOGD("expose audio path to build offload output path");
6990 player->build_audio_offload = TRUE;
6991 /* update codec info */
6992 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6993 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6994 player->audiodec_linked = 1;
6996 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7000 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7002 LOGD("audio codec type: %d", codec_type);
7003 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7004 /* sw codec will be skipped */
7005 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7006 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7007 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7008 ret = GST_AUTOPLUG_SELECT_SKIP;
7012 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7013 /* hw codec will be skipped */
7014 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7015 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7016 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7017 ret = GST_AUTOPLUG_SELECT_SKIP;
7022 /* set stream information */
7023 if (!player->audiodec_linked)
7024 __mmplayer_set_audio_attrs(player, caps);
7026 /* update codec info */
7027 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7028 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7029 player->audiodec_linked = 1;
7031 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7033 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7035 LOGD("video codec type: %d", codec_type);
7036 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7037 /* sw codec is skipped */
7038 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7039 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7040 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7041 ret = GST_AUTOPLUG_SELECT_SKIP;
7045 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7046 /* hw codec is skipped */
7047 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7048 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7049 ret = GST_AUTOPLUG_SELECT_SKIP;
7054 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7055 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7057 /* mark video decoder for acquire */
7058 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7059 LOGW("video decoder resource is already acquired, skip it.");
7060 ret = GST_AUTOPLUG_SELECT_SKIP;
7064 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7065 LOGE("failed to acquire video decoder resource");
7066 ret = GST_AUTOPLUG_SELECT_SKIP;
7069 player->interrupted_by_resource = FALSE;
7072 /* update codec info */
7073 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7074 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7075 player->videodec_linked = 1;
7083 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7084 GstCaps *caps, GstElementFactory *factory, gpointer data)
7086 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7087 mmplayer_t *player = (mmplayer_t *)data;
7089 gchar *factory_name = NULL;
7090 gchar *caps_str = NULL;
7091 const gchar *klass = NULL;
7094 factory_name = GST_OBJECT_NAME(factory);
7095 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7096 caps_str = gst_caps_to_string(caps);
7098 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7100 /* store type string */
7101 if (player->type == NULL) {
7102 player->type = gst_caps_to_string(caps);
7103 __mmplayer_update_content_type_info(player);
7106 /* filtering exclude keyword */
7107 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7108 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7109 LOGW("skipping [%s] by exculde keyword [%s]",
7110 factory_name, player->ini.exclude_element_keyword[idx]);
7112 result = GST_AUTOPLUG_SELECT_SKIP;
7117 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7118 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7119 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7120 factory_name, player->ini.unsupported_codec_keyword[idx]);
7121 result = GST_AUTOPLUG_SELECT_SKIP;
7126 /* exclude webm format */
7127 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7128 * because webm format is not supportable.
7129 * If webm is disabled in "autoplug-continue", there is no state change
7130 * failure or error because the decodebin will expose the pad directly.
7131 * It make MSL invoke _prepare_async_callback.
7132 * So, we need to disable webm format in "autoplug-select" */
7133 if (caps_str && strstr(caps_str, "webm")) {
7134 LOGW("webm is not supported");
7135 result = GST_AUTOPLUG_SELECT_SKIP;
7139 /* check factory class for filtering */
7140 /* NOTE : msl don't need to use image plugins.
7141 * So, those plugins should be skipped for error handling.
7143 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7144 LOGD("skipping [%s] by not required", factory_name);
7145 result = GST_AUTOPLUG_SELECT_SKIP;
7149 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7150 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7151 // TO CHECK : subtitle if needed, add subparse exception.
7152 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7153 result = GST_AUTOPLUG_SELECT_SKIP;
7157 if (g_strrstr(factory_name, "mpegpsdemux")) {
7158 LOGD("skipping PS container - not support");
7159 result = GST_AUTOPLUG_SELECT_SKIP;
7163 if (g_strrstr(factory_name, "mssdemux"))
7164 player->smooth_streaming = TRUE;
7166 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7167 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7170 GstStructure *str = NULL;
7171 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7173 /* don't make video because of not required */
7174 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7175 (!player->set_mode.video_export)) {
7176 LOGD("no need video decoding, expose pad");
7177 result = GST_AUTOPLUG_SELECT_EXPOSE;
7181 /* get w/h for omx state-tune */
7182 /* FIXME: deprecated? */
7183 str = gst_caps_get_structure(caps, 0);
7184 gst_structure_get_int(str, "width", &width);
7187 if (player->v_stream_caps) {
7188 gst_caps_unref(player->v_stream_caps);
7189 player->v_stream_caps = NULL;
7192 player->v_stream_caps = gst_caps_copy(caps);
7193 LOGD("take caps for video state tune");
7194 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7198 if (g_strrstr(klass, "Codec/Decoder")) {
7199 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7200 if (result != GST_AUTOPLUG_SELECT_TRY) {
7201 LOGW("skip add decoder");
7207 MMPLAYER_FREEIF(caps_str);
7213 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7216 //mmplayer_t *player = (mmplayer_t *)data;
7217 GstCaps *caps = NULL;
7219 LOGD("[Decodebin2] pad-removed signal");
7221 caps = gst_pad_query_caps(new_pad, NULL);
7223 LOGW("query caps is NULL");
7227 gchar *caps_str = NULL;
7228 caps_str = gst_caps_to_string(caps);
7230 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7232 MMPLAYER_FREEIF(caps_str);
7233 gst_caps_unref(caps);
7237 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7239 mmplayer_t *player = (mmplayer_t *)data;
7240 GstIterator *iter = NULL;
7241 GValue item = { 0, };
7243 gboolean done = FALSE;
7244 gboolean is_all_drained = TRUE;
7247 MMPLAYER_RETURN_IF_FAIL(player);
7249 LOGD("__mmplayer_gst_decode_drained");
7251 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7252 LOGW("Fail to get cmd lock");
7256 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7257 !__mmplayer_verify_gapless_play_path(player)) {
7258 LOGD("decoding is finished.");
7259 __mmplayer_reset_gapless_state(player);
7260 MMPLAYER_CMD_UNLOCK(player);
7264 player->gapless.reconfigure = TRUE;
7266 /* check decodebin src pads whether they received EOS or not */
7267 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7270 switch (gst_iterator_next(iter, &item)) {
7271 case GST_ITERATOR_OK:
7272 pad = g_value_get_object(&item);
7273 if (pad && !GST_PAD_IS_EOS(pad)) {
7274 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7275 is_all_drained = FALSE;
7278 g_value_reset(&item);
7280 case GST_ITERATOR_RESYNC:
7281 gst_iterator_resync(iter);
7283 case GST_ITERATOR_ERROR:
7284 case GST_ITERATOR_DONE:
7289 g_value_unset(&item);
7290 gst_iterator_free(iter);
7292 if (!is_all_drained) {
7293 LOGD("Wait util the all pads get EOS.");
7294 MMPLAYER_CMD_UNLOCK(player);
7299 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7300 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7302 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7303 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7304 __mmplayer_deactivate_old_path(player);
7305 MMPLAYER_CMD_UNLOCK(player);
7311 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7313 mmplayer_t *player = (mmplayer_t *)data;
7314 const gchar *klass = NULL;
7315 gchar *factory_name = NULL;
7317 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7318 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7320 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7322 if (__mmplayer_add_dump_buffer_probe(player, element))
7323 LOGD("add buffer probe");
7325 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7326 gchar *selected = NULL;
7327 selected = g_strdup(GST_ELEMENT_NAME(element));
7328 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7331 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7332 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7333 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7335 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7336 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7338 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7339 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7340 "max-video-width", player->adaptive_info.limit.width,
7341 "max-video-height", player->adaptive_info.limit.height, NULL);
7343 } else if (g_strrstr(klass, "Demuxer")) {
7344 //LOGD("plugged element is demuxer. take it");
7345 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7346 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7349 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7350 int surface_type = 0;
7352 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7355 // to support trust-zone only
7356 if (g_strrstr(factory_name, "asfdemux")) {
7357 LOGD("set file-location %s", player->profile.uri);
7358 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7359 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7360 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7361 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7362 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7363 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7364 (__mmplayer_is_only_mp3_type(player->type))) {
7365 LOGD("[mpegaudioparse] set streaming pull mode.");
7366 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7368 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7369 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7372 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7373 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7374 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7376 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7377 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7379 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7380 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7381 (MMPLAYER_IS_DASH_STREAMING(player))) {
7382 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7383 _mm_player_streaming_set_multiqueue(player->streamer, element);
7384 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7393 __mmplayer_release_misc(mmplayer_t *player)
7396 bool cur_mode = player->set_mode.rich_audio;
7399 MMPLAYER_RETURN_IF_FAIL(player);
7401 player->video_decoded_cb = NULL;
7402 player->video_decoded_cb_user_param = NULL;
7403 player->video_stream_prerolled = false;
7405 player->audio_decoded_cb = NULL;
7406 player->audio_decoded_cb_user_param = NULL;
7407 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7409 player->audio_stream_changed_cb = NULL;
7410 player->audio_stream_changed_cb_user_param = NULL;
7412 player->sent_bos = FALSE;
7413 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7415 player->seek_state = MMPLAYER_SEEK_NONE;
7417 player->total_bitrate = 0;
7418 player->total_maximum_bitrate = 0;
7420 player->not_found_demuxer = 0;
7422 player->last_position = 0;
7423 player->duration = 0;
7424 player->http_content_size = 0;
7425 player->not_supported_codec = MISSING_PLUGIN_NONE;
7426 player->can_support_codec = FOUND_PLUGIN_NONE;
7427 player->pending_seek.is_pending = false;
7428 player->pending_seek.pos = 0;
7429 player->msg_posted = FALSE;
7430 player->has_many_types = FALSE;
7431 player->is_subtitle_force_drop = FALSE;
7432 player->play_subtitle = FALSE;
7433 player->adjust_subtitle_pos = 0;
7434 player->has_closed_caption = FALSE;
7435 player->set_mode.video_export = false;
7436 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7437 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7439 player->set_mode.rich_audio = cur_mode;
7441 if (player->audio_device_cb_id > 0 &&
7442 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7443 LOGW("failed to remove audio device_connected_callback");
7444 player->audio_device_cb_id = 0;
7446 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7447 player->bitrate[i] = 0;
7448 player->maximum_bitrate[i] = 0;
7451 /* free memory related to audio effect */
7452 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7454 if (player->adaptive_info.var_list) {
7455 g_list_free_full(player->adaptive_info.var_list, g_free);
7456 player->adaptive_info.var_list = NULL;
7459 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7460 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7461 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7463 /* Reset video360 settings to their defaults in case if the pipeline is to be
7466 player->video360_metadata.is_spherical = -1;
7467 player->is_openal_plugin_used = FALSE;
7469 player->is_content_spherical = FALSE;
7470 player->is_video360_enabled = TRUE;
7471 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7472 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7473 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7474 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7475 player->video360_zoom = 1.0f;
7476 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7477 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7479 player->sound.rg_enable = false;
7481 __mmplayer_initialize_video_roi(player);
7486 __mmplayer_release_misc_post(mmplayer_t *player)
7488 char *original_uri = NULL;
7491 /* player->pipeline is already released before. */
7493 MMPLAYER_RETURN_IF_FAIL(player);
7495 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7497 /* clean found audio decoders */
7498 if (player->audio_decoders) {
7499 GList *a_dec = player->audio_decoders;
7500 for (; a_dec; a_dec = g_list_next(a_dec)) {
7501 gchar *name = a_dec->data;
7502 MMPLAYER_FREEIF(name);
7504 g_list_free(player->audio_decoders);
7505 player->audio_decoders = NULL;
7508 /* clean the uri list except original uri */
7509 if (player->uri_info.uri_list) {
7510 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7512 if (player->attrs) {
7513 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7514 LOGD("restore original uri = %s", original_uri);
7516 if (mm_attrs_commit_all(player->attrs))
7517 LOGE("failed to commit the original uri.");
7520 GList *uri_list = player->uri_info.uri_list;
7521 for (; uri_list; uri_list = g_list_next(uri_list)) {
7522 gchar *uri = uri_list->data;
7523 MMPLAYER_FREEIF(uri);
7525 g_list_free(player->uri_info.uri_list);
7526 player->uri_info.uri_list = NULL;
7529 /* clear the audio stream buffer list */
7530 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7532 /* clear the video stream bo list */
7533 __mmplayer_video_stream_destroy_bo_list(player);
7534 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7536 if (player->profile.input_mem.buf) {
7537 free(player->profile.input_mem.buf);
7538 player->profile.input_mem.buf = NULL;
7540 player->profile.input_mem.len = 0;
7541 player->profile.input_mem.offset = 0;
7543 player->uri_info.uri_idx = 0;
7548 __mmplayer_check_subtitle(mmplayer_t *player)
7550 MMHandleType attrs = 0;
7551 char *subtitle_uri = NULL;
7555 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7557 /* get subtitle attribute */
7558 attrs = MMPLAYER_GET_ATTRS(player);
7562 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7563 if (!subtitle_uri || !strlen(subtitle_uri))
7566 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7567 player->is_external_subtitle_present = TRUE;
7575 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7577 MMPLAYER_RETURN_IF_FAIL(player);
7579 if (player->eos_timer) {
7580 LOGD("cancel eos timer");
7581 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7582 player->eos_timer = 0;
7589 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7593 MMPLAYER_RETURN_IF_FAIL(player);
7594 MMPLAYER_RETURN_IF_FAIL(sink);
7596 player->sink_elements = g_list_append(player->sink_elements, sink);
7602 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7606 MMPLAYER_RETURN_IF_FAIL(player);
7607 MMPLAYER_RETURN_IF_FAIL(sink);
7609 player->sink_elements = g_list_remove(player->sink_elements, sink);
7615 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7616 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7618 mmplayer_signal_item_t *item = NULL;
7621 MMPLAYER_RETURN_IF_FAIL(player);
7623 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7624 LOGE("invalid signal type [%d]", type);
7628 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7630 LOGE("cannot connect signal [%s]", signal);
7635 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7636 player->signals[type] = g_list_append(player->signals[type], item);
7642 /* NOTE : be careful with calling this api. please refer to below glib comment
7643 * glib comment : Note that there is a bug in GObject that makes this function much
7644 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7645 * will no longer be called, but, the signal handler is not currently disconnected.
7646 * If the instance is itself being freed at the same time than this doesn't matter,
7647 * since the signal will automatically be removed, but if instance persists,
7648 * then the signal handler will leak. You should not remove the signal yourself
7649 * because in a future versions of GObject, the handler will automatically be
7652 * It's possible to work around this problem in a way that will continue to work
7653 * with future versions of GObject by checking that the signal handler is still
7654 * connected before disconnected it:
7656 * if (g_signal_handler_is_connected(instance, id))
7657 * g_signal_handler_disconnect(instance, id);
7660 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7662 GList *sig_list = NULL;
7663 mmplayer_signal_item_t *item = NULL;
7667 MMPLAYER_RETURN_IF_FAIL(player);
7669 LOGD("release signals type : %d", type);
7671 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7672 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7673 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7674 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7675 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7676 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7680 sig_list = player->signals[type];
7682 for (; sig_list; sig_list = sig_list->next) {
7683 item = sig_list->data;
7685 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7686 if (g_signal_handler_is_connected(item->obj, item->sig))
7687 g_signal_handler_disconnect(item->obj, item->sig);
7690 MMPLAYER_FREEIF(item);
7693 g_list_free(player->signals[type]);
7694 player->signals[type] = NULL;
7702 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7704 mmplayer_t *player = 0;
7705 int prev_display_surface_type = 0;
7706 void *prev_display_overlay = NULL;
7710 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7711 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7713 player = MM_PLAYER_CAST(handle);
7715 /* check video sinkbin is created */
7716 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7717 LOGE("Videosink is already created");
7718 return MM_ERROR_NONE;
7721 LOGD("videosink element is not yet ready");
7723 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7724 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7726 return MM_ERROR_INVALID_ARGUMENT;
7729 /* load previous attributes */
7730 if (player->attrs) {
7731 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7732 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7733 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7734 if (prev_display_surface_type == surface_type) {
7735 LOGD("incoming display surface type is same as previous one, do nothing..");
7737 return MM_ERROR_NONE;
7740 LOGE("failed to load attributes");
7742 return MM_ERROR_PLAYER_INTERNAL;
7745 /* videobin is not created yet, so we just set attributes related to display surface */
7746 LOGD("store display attribute for given surface type(%d)", surface_type);
7747 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7748 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7749 if (mm_attrs_commit_all(player->attrs)) {
7750 LOGE("failed to commit attribute");
7752 return MM_ERROR_PLAYER_INTERNAL;
7756 return MM_ERROR_NONE;
7759 /* Note : if silent is true, then subtitle would not be displayed. :*/
7761 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7763 mmplayer_t *player = (mmplayer_t *)hplayer;
7767 /* check player handle */
7768 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7770 player->set_mode.subtitle_off = silent;
7772 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7776 return MM_ERROR_NONE;
7780 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7782 mmplayer_gst_element_t *mainbin = NULL;
7783 mmplayer_gst_element_t *textbin = NULL;
7784 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7785 GstState current_state = GST_STATE_VOID_PENDING;
7786 GstState element_state = GST_STATE_VOID_PENDING;
7787 GstState element_pending_state = GST_STATE_VOID_PENDING;
7789 GstEvent *event = NULL;
7790 int result = MM_ERROR_NONE;
7792 GstClock *curr_clock = NULL;
7793 GstClockTime base_time, start_time, curr_time;
7798 /* check player handle */
7799 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7801 player->pipeline->mainbin &&
7802 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7804 mainbin = player->pipeline->mainbin;
7805 textbin = player->pipeline->textbin;
7807 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7809 // sync clock with current pipeline
7810 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7811 curr_time = gst_clock_get_time(curr_clock);
7813 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7814 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7816 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7817 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7819 if (current_state > GST_STATE_READY) {
7820 // sync state with current pipeline
7821 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7822 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7823 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7825 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7826 if (GST_STATE_CHANGE_FAILURE == ret) {
7827 LOGE("fail to state change.");
7828 result = MM_ERROR_PLAYER_INTERNAL;
7832 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7833 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7836 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7837 gst_object_unref(curr_clock);
7840 // seek to current position
7841 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7842 result = MM_ERROR_PLAYER_INVALID_STATE;
7843 LOGE("gst_element_query_position failed, invalid state");
7847 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7848 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);
7850 _mmplayer_gst_send_event_to_sink(player, event);
7852 result = MM_ERROR_PLAYER_INTERNAL;
7853 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7857 /* sync state with current pipeline */
7858 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7859 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7860 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7862 return MM_ERROR_NONE;
7865 /* release text pipeline resource */
7866 player->textsink_linked = 0;
7868 /* release signal */
7869 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7871 /* release textbin with it's childs */
7872 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7873 MMPLAYER_FREEIF(player->pipeline->textbin);
7874 player->pipeline->textbin = NULL;
7876 /* release subtitle elem */
7877 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7878 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7884 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7886 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7887 GstState current_state = GST_STATE_VOID_PENDING;
7889 MMHandleType attrs = 0;
7890 mmplayer_gst_element_t *mainbin = NULL;
7891 mmplayer_gst_element_t *textbin = NULL;
7893 gchar *subtitle_uri = NULL;
7894 int result = MM_ERROR_NONE;
7895 const gchar *charset = NULL;
7899 /* check player handle */
7900 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7902 player->pipeline->mainbin &&
7903 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7904 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7906 mainbin = player->pipeline->mainbin;
7907 textbin = player->pipeline->textbin;
7909 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7910 if (current_state < GST_STATE_READY) {
7911 result = MM_ERROR_PLAYER_INVALID_STATE;
7912 LOGE("Pipeline is not in proper state");
7916 attrs = MMPLAYER_GET_ATTRS(player);
7918 LOGE("cannot get content attribute");
7919 result = MM_ERROR_PLAYER_INTERNAL;
7923 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7924 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7925 LOGE("subtitle uri is not proper filepath");
7926 result = MM_ERROR_PLAYER_INVALID_URI;
7930 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7931 LOGE("failed to get storage info of subtitle path");
7932 result = MM_ERROR_PLAYER_INVALID_URI;
7936 LOGD("old subtitle file path is [%s]", subtitle_uri);
7937 LOGD("new subtitle file path is [%s]", filepath);
7939 if (!strcmp(filepath, subtitle_uri)) {
7940 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7943 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7944 if (mm_attrs_commit_all(player->attrs)) {
7945 LOGE("failed to commit.");
7950 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7951 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7952 player->subtitle_language_list = NULL;
7953 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7955 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7956 if (ret != GST_STATE_CHANGE_SUCCESS) {
7957 LOGE("failed to change state of textbin to READY");
7958 result = MM_ERROR_PLAYER_INTERNAL;
7962 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7963 if (ret != GST_STATE_CHANGE_SUCCESS) {
7964 LOGE("failed to change state of subparse to READY");
7965 result = MM_ERROR_PLAYER_INTERNAL;
7969 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7970 if (ret != GST_STATE_CHANGE_SUCCESS) {
7971 LOGE("failed to change state of filesrc to READY");
7972 result = MM_ERROR_PLAYER_INTERNAL;
7976 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7978 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7980 charset = _mmplayer_get_charset(filepath);
7982 LOGD("detected charset is %s", charset);
7983 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7986 result = _mmplayer_sync_subtitle_pipeline(player);
7993 /* API to switch between external subtitles */
7995 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7997 int result = MM_ERROR_NONE;
7998 mmplayer_t *player = (mmplayer_t *)hplayer;
8003 /* check player handle */
8004 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8006 /* filepath can be null in idle state */
8008 /* check file path */
8009 if ((path = strstr(filepath, "file://")))
8010 result = _mmplayer_exist_file_path(path + 7);
8012 result = _mmplayer_exist_file_path(filepath);
8014 if (result != MM_ERROR_NONE) {
8015 LOGE("invalid subtitle path 0x%X", result);
8016 return result; /* file not found or permission denied */
8020 if (!player->pipeline) {
8022 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8023 if (mm_attrs_commit_all(player->attrs)) {
8024 LOGE("failed to commit"); /* subtitle path will not be created */
8025 return MM_ERROR_PLAYER_INTERNAL;
8028 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8029 /* check filepath */
8030 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8032 if (!__mmplayer_check_subtitle(player)) {
8033 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8034 if (mm_attrs_commit_all(player->attrs)) {
8035 LOGE("failed to commit");
8036 return MM_ERROR_PLAYER_INTERNAL;
8039 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8040 LOGE("fail to create text pipeline");
8041 return MM_ERROR_PLAYER_INTERNAL;
8044 result = _mmplayer_sync_subtitle_pipeline(player);
8046 result = __mmplayer_change_external_subtitle_language(player, filepath);
8049 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8050 player->is_external_subtitle_added_now = TRUE;
8052 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8053 if (!player->subtitle_language_list) {
8054 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8055 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8056 LOGW("subtitle language list is not updated yet");
8058 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8066 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8068 int result = MM_ERROR_NONE;
8069 gchar *change_pad_name = NULL;
8070 GstPad *sinkpad = NULL;
8071 mmplayer_gst_element_t *mainbin = NULL;
8072 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8073 GstCaps *caps = NULL;
8074 gint total_track_num = 0;
8078 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8079 MM_ERROR_PLAYER_NOT_INITIALIZED);
8081 LOGD("Change Track(%d) to %d", type, index);
8083 mainbin = player->pipeline->mainbin;
8085 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8086 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8087 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8088 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8090 /* Changing Video Track is not supported. */
8091 LOGE("Track Type Error");
8095 if (mainbin[elem_idx].gst == NULL) {
8096 result = MM_ERROR_PLAYER_NO_OP;
8097 LOGD("Req track doesn't exist");
8101 total_track_num = player->selector[type].total_track_num;
8102 if (total_track_num <= 0) {
8103 result = MM_ERROR_PLAYER_NO_OP;
8104 LOGD("Language list is not available");
8108 if ((index < 0) || (index >= total_track_num)) {
8109 result = MM_ERROR_INVALID_ARGUMENT;
8110 LOGD("Not a proper index : %d", index);
8114 /*To get the new pad from the selector*/
8115 change_pad_name = g_strdup_printf("sink_%u", index);
8116 if (change_pad_name == NULL) {
8117 result = MM_ERROR_PLAYER_INTERNAL;
8118 LOGD("Pad does not exists");
8122 LOGD("new active pad name: %s", change_pad_name);
8124 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8125 if (sinkpad == NULL) {
8126 LOGD("sinkpad is NULL");
8127 result = MM_ERROR_PLAYER_INTERNAL;
8131 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8132 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8134 caps = gst_pad_get_current_caps(sinkpad);
8135 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8138 gst_object_unref(sinkpad);
8140 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8141 __mmplayer_set_audio_attrs(player, caps);
8144 MMPLAYER_FREEIF(change_pad_name);
8149 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8151 int result = MM_ERROR_NONE;
8152 mmplayer_t *player = NULL;
8153 mmplayer_gst_element_t *mainbin = NULL;
8155 gint current_active_index = 0;
8157 GstState current_state = GST_STATE_VOID_PENDING;
8158 GstEvent *event = NULL;
8163 player = (mmplayer_t *)hplayer;
8164 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8166 if (!player->pipeline) {
8167 LOGE("Track %d pre setting -> %d", type, index);
8169 player->selector[type].active_pad_index = index;
8173 mainbin = player->pipeline->mainbin;
8175 current_active_index = player->selector[type].active_pad_index;
8177 /*If index is same as running index no need to change the pad*/
8178 if (current_active_index == index)
8181 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8182 result = MM_ERROR_PLAYER_INVALID_STATE;
8186 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8187 if (current_state < GST_STATE_PAUSED) {
8188 result = MM_ERROR_PLAYER_INVALID_STATE;
8189 LOGW("Pipeline not in porper state");
8193 result = __mmplayer_change_selector_pad(player, type, index);
8194 if (result != MM_ERROR_NONE) {
8195 LOGE("change selector pad error");
8199 player->selector[type].active_pad_index = index;
8201 if (current_state == GST_STATE_PLAYING) {
8202 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8203 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8204 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8206 _mmplayer_gst_send_event_to_sink(player, event);
8208 result = MM_ERROR_PLAYER_INTERNAL;
8218 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8220 mmplayer_t *player = (mmplayer_t *)hplayer;
8224 /* check player handle */
8225 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8227 *silent = player->set_mode.subtitle_off;
8229 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8233 return MM_ERROR_NONE;
8237 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8239 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8240 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8242 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8243 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8247 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8248 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8249 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8250 mmplayer_dump_t *dump_s;
8251 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8252 if (dump_s == NULL) {
8253 LOGE("malloc fail");
8257 dump_s->dump_element_file = NULL;
8258 dump_s->dump_pad = NULL;
8259 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8261 if (dump_s->dump_pad) {
8262 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8263 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]);
8264 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8265 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);
8266 /* add list for removed buffer probe and close FILE */
8267 player->dump_list = g_list_append(player->dump_list, dump_s);
8268 LOGD("%s sink pad added buffer probe for dump", factory_name);
8271 MMPLAYER_FREEIF(dump_s);
8272 LOGE("failed to get %s sink pad added", factory_name);
8279 static GstPadProbeReturn
8280 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8282 FILE *dump_data = (FILE *)u_data;
8284 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8285 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8287 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8289 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8291 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8293 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8295 gst_buffer_unmap(buffer, &probe_info);
8297 return GST_PAD_PROBE_OK;
8301 __mmplayer_release_dump_list(GList *dump_list)
8303 GList *d_list = dump_list;
8308 for (; d_list; d_list = g_list_next(d_list)) {
8309 mmplayer_dump_t *dump_s = d_list->data;
8310 if (dump_s->dump_pad) {
8311 if (dump_s->probe_handle_id)
8312 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8313 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8315 if (dump_s->dump_element_file) {
8316 fclose(dump_s->dump_element_file);
8317 dump_s->dump_element_file = NULL;
8319 MMPLAYER_FREEIF(dump_s);
8321 g_list_free(dump_list);
8326 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8328 mmplayer_t *player = (mmplayer_t *)hplayer;
8332 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8333 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8335 *exist = (bool)player->has_closed_caption;
8339 return MM_ERROR_NONE;
8343 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8347 // LOGD("unref internal gst buffer %p", buffer);
8348 gst_buffer_unref((GstBuffer *)buffer);
8355 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8357 mmplayer_t *player = (mmplayer_t *)hplayer;
8361 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8362 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8364 if (MMPLAYER_IS_STREAMING(player))
8365 *timeout = (int)player->ini.live_state_change_timeout;
8367 *timeout = (int)player->ini.localplayback_state_change_timeout;
8369 LOGD("timeout = %d", *timeout);
8372 return MM_ERROR_NONE;
8376 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8380 MMPLAYER_RETURN_IF_FAIL(player);
8382 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8384 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8385 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8386 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8387 player->storage_info[i].id = -1;
8388 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8390 if (path_type != MMPLAYER_PATH_MAX)
8399 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8401 int ret = MM_ERROR_NONE;
8402 mmplayer_t *player = (mmplayer_t *)hplayer;
8403 MMMessageParamType msg_param = {0, };
8406 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8408 LOGW("state changed storage %d:%d", id, state);
8410 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8411 return MM_ERROR_NONE;
8413 /* FIXME: text path should be handled seperately. */
8414 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8415 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8416 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8417 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8418 LOGW("external storage is removed");
8420 if (player->msg_posted == FALSE) {
8421 memset(&msg_param, 0, sizeof(MMMessageParamType));
8422 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8423 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8424 player->msg_posted = TRUE;
8427 /* unrealize the player */
8428 ret = _mmplayer_unrealize(hplayer);
8429 if (ret != MM_ERROR_NONE)
8430 LOGE("failed to unrealize");
8438 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8440 int ret = MM_ERROR_NONE;
8441 mmplayer_t *player = (mmplayer_t *)hplayer;
8442 int idx = 0, total = 0;
8443 gchar *result = NULL, *tmp = NULL;
8446 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8447 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8449 total = *num = g_list_length(player->adaptive_info.var_list);
8451 LOGW("There is no stream variant info.");
8455 result = g_strdup("");
8456 for (idx = 0 ; idx < total ; idx++) {
8457 stream_variant_t *v_data = NULL;
8458 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8461 gchar data[64] = {0};
8462 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8464 tmp = g_strconcat(result, data, NULL);
8468 LOGW("There is no variant data in %d", idx);
8473 *var_info = (char *)result;
8475 LOGD("variant info %d:%s", *num, *var_info);
8481 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8483 int ret = MM_ERROR_NONE;
8484 mmplayer_t *player = (mmplayer_t *)hplayer;
8487 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8489 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8491 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8492 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8493 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8495 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8496 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8497 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8498 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8500 /* FIXME: seek to current position for applying new variant limitation */
8509 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8511 int ret = MM_ERROR_NONE;
8512 mmplayer_t *player = (mmplayer_t *)hplayer;
8515 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8516 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8518 *bandwidth = player->adaptive_info.limit.bandwidth;
8519 *width = player->adaptive_info.limit.width;
8520 *height = player->adaptive_info.limit.height;
8522 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8529 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8531 int ret = MM_ERROR_NONE;
8532 mmplayer_t *player = (mmplayer_t *)hplayer;
8535 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8536 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8537 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8539 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8541 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8542 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8543 else /* live case */
8544 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8546 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8553 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8555 #define IDX_FIRST_SW_CODEC 0
8556 mmplayer_t *player = (mmplayer_t *)hplayer;
8557 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8558 MMHandleType attrs = 0;
8561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8563 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8564 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8565 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8567 switch (stream_type) {
8568 case MM_PLAYER_STREAM_TYPE_AUDIO:
8569 /* to support audio codec selection, codec info have to be added in ini file as below.
8570 audio codec element hw = xxxx
8571 audio codec element sw = avdec */
8572 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8573 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8574 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8575 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8576 LOGE("There is no audio codec info for codec_type %d", codec_type);
8577 return MM_ERROR_PLAYER_NO_OP;
8580 case MM_PLAYER_STREAM_TYPE_VIDEO:
8581 /* to support video codec selection, codec info have to be added in ini file as below.
8582 video codec element hw = omx
8583 video codec element sw = avdec */
8584 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8585 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8586 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8587 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8588 LOGE("There is no video codec info for codec_type %d", codec_type);
8589 return MM_ERROR_PLAYER_NO_OP;
8593 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8594 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8598 LOGD("update %s codec_type to %d", attr_name, codec_type);
8600 attrs = MMPLAYER_GET_ATTRS(player);
8601 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8603 if (mm_attrs_commit_all(player->attrs)) {
8604 LOGE("failed to commit codec_type attributes");
8605 return MM_ERROR_PLAYER_INTERNAL;
8609 return MM_ERROR_NONE;
8613 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8615 mmplayer_t *player = (mmplayer_t *)hplayer;
8616 GstElement *rg_vol_element = NULL;
8620 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8622 player->sound.rg_enable = enabled;
8624 /* just hold rgvolume enable value if pipeline is not ready */
8625 if (!player->pipeline || !player->pipeline->audiobin) {
8626 LOGD("pipeline is not ready. holding rgvolume enable value");
8627 return MM_ERROR_NONE;
8630 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8632 if (!rg_vol_element) {
8633 LOGD("rgvolume element is not created");
8634 return MM_ERROR_PLAYER_INTERNAL;
8638 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8640 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8644 return MM_ERROR_NONE;
8648 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8650 mmplayer_t *player = (mmplayer_t *)hplayer;
8651 GstElement *rg_vol_element = NULL;
8652 gboolean enable = FALSE;
8656 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8657 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8659 /* just hold enable_rg value if pipeline is not ready */
8660 if (!player->pipeline || !player->pipeline->audiobin) {
8661 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8662 *enabled = player->sound.rg_enable;
8663 return MM_ERROR_NONE;
8666 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8668 if (!rg_vol_element) {
8669 LOGD("rgvolume element is not created");
8670 return MM_ERROR_PLAYER_INTERNAL;
8673 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8674 *enabled = (bool)enable;
8678 return MM_ERROR_NONE;
8682 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8684 mmplayer_t *player = (mmplayer_t *)hplayer;
8685 MMHandleType attrs = 0;
8686 void *handle = NULL;
8687 int ret = MM_ERROR_NONE;
8691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8693 attrs = MMPLAYER_GET_ATTRS(player);
8694 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8696 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8698 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8699 return MM_ERROR_PLAYER_INTERNAL;
8702 player->video_roi.scale_x = scale_x;
8703 player->video_roi.scale_y = scale_y;
8704 player->video_roi.scale_width = scale_width;
8705 player->video_roi.scale_height = scale_height;
8707 /* check video sinkbin is created */
8708 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8709 return MM_ERROR_NONE;
8711 if (!gst_video_overlay_set_video_roi_area(
8712 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8713 scale_x, scale_y, scale_width, scale_height))
8714 ret = MM_ERROR_PLAYER_INTERNAL;
8716 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8717 scale_x, scale_y, scale_width, scale_height);
8725 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8727 mmplayer_t *player = (mmplayer_t *)hplayer;
8728 int ret = MM_ERROR_NONE;
8732 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8733 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8735 *scale_x = player->video_roi.scale_x;
8736 *scale_y = player->video_roi.scale_y;
8737 *scale_width = player->video_roi.scale_width;
8738 *scale_height = player->video_roi.scale_height;
8740 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8741 *scale_x, *scale_y, *scale_width, *scale_height);
8747 __mmplayer_update_duration_value(mmplayer_t *player)
8749 gboolean ret = FALSE;
8750 gint64 dur_nsec = 0;
8751 LOGD("try to update duration");
8753 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8754 player->duration = dur_nsec;
8755 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8759 if (player->duration < 0) {
8760 LOGW("duration is Non-Initialized !!!");
8761 player->duration = 0;
8764 /* update streaming service type */
8765 player->streaming_type = _mmplayer_get_stream_service_type(player);
8767 /* check duration is OK */
8768 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8769 /* FIXIT : find another way to get duration here. */
8770 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8776 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8778 /* update audio params
8779 NOTE : We need original audio params and it can be only obtained from src pad of audio
8780 decoder. Below code only valid when we are not using 'resampler' just before
8781 'audioconverter'. */
8782 GstCaps *caps_a = NULL;
8784 gint samplerate = 0, channels = 0;
8785 GstStructure *p = NULL;
8786 GstElement *aconv = NULL;
8788 LOGD("try to update audio attrs");
8790 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8792 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8793 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8794 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8795 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8797 LOGE("there is no audio converter");
8801 pad = gst_element_get_static_pad(aconv, "sink");
8804 LOGW("failed to get pad from audio converter");
8808 caps_a = gst_pad_get_current_caps(pad);
8810 LOGW("not ready to get audio caps");
8811 gst_object_unref(pad);
8815 p = gst_caps_get_structure(caps_a, 0);
8817 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8819 gst_structure_get_int(p, "rate", &samplerate);
8820 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8822 gst_structure_get_int(p, "channels", &channels);
8823 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8825 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8827 gst_caps_unref(caps_a);
8828 gst_object_unref(pad);
8834 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8836 LOGD("try to update video attrs");
8838 GstCaps *caps_v = NULL;
8842 GstStructure *p = NULL;
8844 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8845 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8847 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8849 LOGD("no videosink sink pad");
8853 caps_v = gst_pad_get_current_caps(pad);
8854 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8855 if (!caps_v && player->v_stream_caps) {
8856 caps_v = player->v_stream_caps;
8857 gst_caps_ref(caps_v);
8861 LOGD("no negitiated caps from videosink");
8862 gst_object_unref(pad);
8866 p = gst_caps_get_structure(caps_v, 0);
8867 gst_structure_get_int(p, "width", &width);
8868 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8870 gst_structure_get_int(p, "height", &height);
8871 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8873 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8875 SECURE_LOGD("width : %d height : %d", width, height);
8877 gst_caps_unref(caps_v);
8878 gst_object_unref(pad);
8881 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8882 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8889 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8891 gboolean ret = FALSE;
8892 guint64 data_size = 0;
8896 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8897 if (!player->duration)
8900 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8901 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8902 if (stat(path, &sb) == 0)
8903 data_size = (guint64)sb.st_size;
8905 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8906 data_size = player->http_content_size;
8909 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8912 guint64 bitrate = 0;
8913 guint64 msec_dur = 0;
8915 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8917 bitrate = data_size * 8 * 1000 / msec_dur;
8918 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8919 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8923 LOGD("player duration is less than 0");
8927 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8928 if (player->total_bitrate) {
8929 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8938 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8940 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8941 data->uri_type = uri_type;
8945 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8947 int ret = MM_ERROR_PLAYER_INVALID_URI;
8949 char *buffer = NULL;
8950 char *seperator = strchr(path, ',');
8951 char ext[100] = {0,}, size[100] = {0,};
8954 if ((buffer = strstr(path, "ext="))) {
8955 buffer += strlen("ext=");
8957 if (strlen(buffer)) {
8958 strncpy(ext, buffer, 99);
8960 if ((seperator = strchr(ext, ','))
8961 || (seperator = strchr(ext, ' '))
8962 || (seperator = strchr(ext, '\0'))) {
8963 seperator[0] = '\0';
8968 if ((buffer = strstr(path, "size="))) {
8969 buffer += strlen("size=");
8971 if (strlen(buffer) > 0) {
8972 strncpy(size, buffer, 99);
8974 if ((seperator = strchr(size, ','))
8975 || (seperator = strchr(size, ' '))
8976 || (seperator = strchr(size, '\0'))) {
8977 seperator[0] = '\0';
8980 mem_size = atoi(size);
8985 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8987 if (mem_size && param) {
8988 if (data->input_mem.buf)
8989 free(data->input_mem.buf);
8990 data->input_mem.buf = malloc(mem_size);
8992 if (data->input_mem.buf) {
8993 memcpy(data->input_mem.buf, param, mem_size);
8994 data->input_mem.len = mem_size;
8995 ret = MM_ERROR_NONE;
8997 LOGE("failed to alloc mem %d", mem_size);
8998 ret = MM_ERROR_PLAYER_INTERNAL;
9001 data->input_mem.offset = 0;
9002 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9009 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9011 gchar *location = NULL;
9014 int ret = MM_ERROR_NONE;
9016 if ((path = strstr(uri, "file://"))) {
9017 location = g_filename_from_uri(uri, NULL, &err);
9018 if (!location || (err != NULL)) {
9019 LOGE("Invalid URI '%s' for filesrc: %s", path,
9020 (err != NULL) ? err->message : "unknown error");
9024 MMPLAYER_FREEIF(location);
9026 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9027 return MM_ERROR_PLAYER_INVALID_URI;
9029 LOGD("path from uri: %s", location);
9032 path = (location != NULL) ? (location) : ((char *)uri);
9035 ret = _mmplayer_exist_file_path(path);
9037 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9038 if (ret == MM_ERROR_NONE) {
9039 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9040 if (_mmplayer_is_sdp_file(path)) {
9041 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9042 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9044 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9046 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9047 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9049 LOGE("invalid uri, could not play..");
9050 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9053 MMPLAYER_FREEIF(location);
9058 static mmplayer_video_decoded_data_info_t *
9059 __mmplayer_create_stream_from_pad(GstPad *pad)
9061 GstCaps *caps = NULL;
9062 GstStructure *structure = NULL;
9063 unsigned int fourcc = 0;
9064 const gchar *string_format = NULL;
9065 mmplayer_video_decoded_data_info_t *stream = NULL;
9067 MMPixelFormatType format;
9070 caps = gst_pad_get_current_caps(pad);
9072 LOGE("Caps is NULL.");
9076 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9077 structure = gst_caps_get_structure(caps, 0);
9078 gst_structure_get_int(structure, "width", &width);
9079 gst_structure_get_int(structure, "height", &height);
9080 string_format = gst_structure_get_string(structure, "format");
9083 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9084 format = _mmplayer_get_pixtype(fourcc);
9085 gst_video_info_from_caps(&info, caps);
9086 gst_caps_unref(caps);
9089 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9090 LOGE("Wrong condition!!");
9094 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9096 LOGE("failed to alloc mem for video data");
9100 stream->width = width;
9101 stream->height = height;
9102 stream->format = format;
9103 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9109 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9111 unsigned int pitch = 0;
9112 unsigned int size = 0;
9114 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9117 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9118 bo = gst_tizen_memory_get_bos(mem, index);
9120 stream->bo[index] = tbm_bo_ref(bo);
9122 LOGE("failed to get bo for index %d", index);
9125 for (index = 0; index < stream->plane_num; index++) {
9126 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9127 stream->stride[index] = pitch;
9129 stream->elevation[index] = size / pitch;
9131 stream->elevation[index] = stream->height;
9136 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9138 if (stream->format == MM_PIXEL_FORMAT_I420) {
9139 int ret = TBM_SURFACE_ERROR_NONE;
9140 tbm_surface_h surface;
9141 tbm_surface_info_s info;
9143 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9145 ret = tbm_surface_get_info(surface, &info);
9146 if (ret != TBM_SURFACE_ERROR_NONE) {
9147 tbm_surface_destroy(surface);
9151 tbm_surface_destroy(surface);
9152 stream->stride[0] = info.planes[0].stride;
9153 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9154 stream->stride[1] = info.planes[1].stride;
9155 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9156 stream->stride[2] = info.planes[2].stride;
9157 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9158 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9159 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9160 stream->stride[0] = stream->width * 4;
9161 stream->elevation[0] = stream->height;
9162 stream->bo_size = stream->stride[0] * stream->height;
9164 LOGE("Not support format %d", stream->format);
9172 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9174 tbm_bo_handle thandle;
9176 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9177 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9178 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9182 unsigned char *src = NULL;
9183 unsigned char *dest = NULL;
9184 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9186 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9188 LOGE("fail to gst_memory_map");
9192 if (!mapinfo.data) {
9193 LOGE("data pointer is wrong");
9197 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9198 if (!stream->bo[0]) {
9199 LOGE("Fail to tbm_bo_alloc!!");
9203 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9205 LOGE("thandle pointer is wrong");
9209 if (stream->format == MM_PIXEL_FORMAT_I420) {
9210 src_stride[0] = GST_ROUND_UP_4(stream->width);
9211 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9212 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9213 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9216 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9217 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9219 for (i = 0; i < 3; i++) {
9220 src = mapinfo.data + src_offset[i];
9221 dest = thandle.ptr + dest_offset[i];
9226 for (j = 0; j < stream->height >> k; j++) {
9227 memcpy(dest, src, stream->width>>k);
9228 src += src_stride[i];
9229 dest += stream->stride[i];
9232 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9233 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9235 LOGE("Not support format %d", stream->format);
9239 tbm_bo_unmap(stream->bo[0]);
9240 gst_memory_unmap(mem, &mapinfo);
9246 tbm_bo_unmap(stream->bo[0]);
9249 gst_memory_unmap(mem, &mapinfo);
9255 __mmplayer_set_pause_state(mmplayer_t *player)
9257 if (player->sent_bos)
9260 /* rtsp case, get content attrs by GstMessage */
9261 if (MMPLAYER_IS_RTSP_STREAMING(player))
9264 /* it's first time to update all content attrs. */
9265 _mmplayer_update_content_attrs(player, ATTR_ALL);
9269 __mmplayer_set_playing_state(mmplayer_t *player)
9271 gchar *audio_codec = NULL;
9273 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9274 /* initialize because auto resume is done well. */
9275 player->resumed_by_rewind = FALSE;
9276 player->playback_rate = 1.0;
9279 if (player->sent_bos)
9282 /* try to get content metadata */
9284 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9285 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9286 * legacy mmfw-player api
9288 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9290 if ((player->cmd == MMPLAYER_COMMAND_START)
9291 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9292 __mmplayer_handle_missed_plugin(player);
9295 /* check audio codec field is set or not
9296 * we can get it from typefinder or codec's caps.
9298 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9300 /* The codec format can't be sent for audio only case like amr, mid etc.
9301 * Because, parser don't make related TAG.
9302 * So, if it's not set yet, fill it with found data.
9305 if (g_strrstr(player->type, "audio/midi"))
9306 audio_codec = "MIDI";
9307 else if (g_strrstr(player->type, "audio/x-amr"))
9308 audio_codec = "AMR";
9309 else if (g_strrstr(player->type, "audio/mpeg")
9310 && !g_strrstr(player->type, "mpegversion=(int)1"))
9311 audio_codec = "AAC";
9313 audio_codec = "unknown";
9315 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9317 if (mm_attrs_commit_all(player->attrs))
9318 LOGE("failed to update attributes");
9320 LOGD("set audio codec type with caps");