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_TYPE(event) != GST_EVENT_STREAM_START &&
965 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
966 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
967 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
968 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
971 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
975 if (strstr(name, "audio")) {
976 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
977 } else if (strstr(name, "video")) {
978 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
980 /* text track is not supportable */
981 LOGE("invalid name %s", name);
985 switch (GST_EVENT_TYPE(event)) {
988 /* in case of gapless, drop eos event not to send it to sink */
989 if (player->gapless.reconfigure && !player->msg_posted) {
990 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
991 ret = GST_PAD_PROBE_DROP;
995 case GST_EVENT_STREAM_START:
997 __mmplayer_gst_selector_update_start_time(player, stream_type);
1000 case GST_EVENT_FLUSH_STOP:
1002 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1003 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1004 player->gapless.start_time[stream_type] = 0;
1007 case GST_EVENT_SEGMENT:
1012 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1013 gst_event_copy_segment(event, &segment);
1015 if (segment.format != GST_FORMAT_TIME)
1018 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1019 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1020 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1021 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1022 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1023 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1025 /* keep the all the segment ev to cover the seeking */
1026 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1027 player->gapless.update_segment[stream_type] = TRUE;
1029 if (!player->gapless.running)
1032 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1034 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1036 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1037 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1038 gst_event_unref(event);
1039 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1045 gdouble proportion = 0.0;
1046 GstClockTimeDiff diff = 0;
1047 GstClockTime timestamp = 0;
1048 gint64 running_time_diff = -1;
1049 GstQOSType type = 0;
1050 GstEvent *tmpev = NULL;
1052 running_time_diff = player->gapless.segment[stream_type].base;
1054 if (running_time_diff <= 0) /* don't need to adjust */
1057 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1058 gst_event_unref(event);
1060 if (timestamp < running_time_diff) {
1061 LOGW("QOS event from previous group");
1062 ret = GST_PAD_PROBE_DROP;
1066 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1067 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1068 stream_type, GST_TIME_ARGS(timestamp),
1069 GST_TIME_ARGS(running_time_diff),
1070 GST_TIME_ARGS(timestamp - running_time_diff));
1072 timestamp -= running_time_diff;
1074 /* That case is invalid for QoS events */
1075 if (diff < 0 && -diff > timestamp) {
1076 LOGW("QOS event from previous group");
1077 ret = GST_PAD_PROBE_DROP;
1081 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1082 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1092 gst_caps_unref(caps);
1096 /* create fakesink for audio or video path witout audiobin or videobin */
1098 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1100 GstElement *pipeline = NULL;
1101 GstElement *fakesink = NULL;
1102 GstPad *sinkpad = NULL;
1105 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1107 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1110 fakesink = gst_element_factory_make("fakesink", NULL);
1111 if (fakesink == NULL) {
1112 LOGE("failed to create fakesink");
1116 /* store it as it's sink element */
1117 __mmplayer_add_sink(player, fakesink);
1119 gst_bin_add(GST_BIN(pipeline), fakesink);
1122 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1124 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1126 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1127 LOGE("failed to link fakesink");
1128 gst_object_unref(GST_OBJECT(fakesink));
1132 if (strstr(name, "video")) {
1133 if (player->v_stream_caps) {
1134 gst_caps_unref(player->v_stream_caps);
1135 player->v_stream_caps = NULL;
1137 if (player->ini.set_dump_element_flag)
1138 __mmplayer_add_dump_buffer_probe(player, fakesink);
1141 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1142 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1146 gst_object_unref(GST_OBJECT(sinkpad));
1153 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1155 GstElement *pipeline = NULL;
1156 GstElement *selector = NULL;
1157 GstPad *srcpad = NULL;
1160 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1162 selector = gst_element_factory_make("input-selector", NULL);
1164 LOGE("failed to create input-selector");
1167 g_object_set(selector, "sync-streams", TRUE, NULL);
1169 player->pipeline->mainbin[elem_idx].id = elem_idx;
1170 player->pipeline->mainbin[elem_idx].gst = selector;
1172 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1174 srcpad = gst_element_get_static_pad(selector, "src");
1176 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1177 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1178 __mmplayer_gst_selector_blocked, NULL, NULL);
1179 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1180 __mmplayer_gst_selector_event_probe, player, NULL);
1182 gst_element_set_state(selector, GST_STATE_PAUSED);
1184 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1185 gst_bin_add(GST_BIN(pipeline), selector);
1187 gst_object_unref(GST_OBJECT(srcpad));
1194 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1196 mmplayer_t *player = (mmplayer_t *)data;
1197 GstElement *selector = NULL;
1198 GstCaps *caps = NULL;
1199 GstStructure *str = NULL;
1200 const gchar *name = NULL;
1201 GstPad *sinkpad = NULL;
1202 gboolean first_track = FALSE;
1203 gboolean caps_ret = TRUE;
1205 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1206 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1209 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1210 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1212 LOGD("pad-added signal handling");
1214 /* get mimetype from caps */
1215 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1219 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1220 /* LOGD("detected mimetype : %s", name); */
1222 if (strstr(name, "video")) {
1224 gchar *caps_str = NULL;
1226 caps_str = gst_caps_to_string(caps);
1227 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1228 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1229 player->set_mode.video_zc = true;
1231 MMPLAYER_FREEIF(caps_str);
1233 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1234 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1236 LOGD("surface type : %d", stype);
1238 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1239 __mmplayer_gst_create_sinkbin(elem, pad, player);
1243 /* in case of exporting video frame, it requires the 360 video filter.
1244 * it will be handled in _no_more_pads(). */
1245 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1246 __mmplayer_gst_make_fakesink(player, pad, name);
1250 LOGD("video selector is required");
1251 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1252 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1253 } else if (strstr(name, "audio")) {
1254 gint samplerate = 0;
1257 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1258 if (player->build_audio_offload)
1259 player->no_more_pad = TRUE; /* remove state holder */
1260 __mmplayer_gst_create_sinkbin(elem, pad, player);
1264 gst_structure_get_int(str, "rate", &samplerate);
1265 gst_structure_get_int(str, "channels", &channels);
1267 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1268 __mmplayer_gst_make_fakesink(player, pad, name);
1272 LOGD("audio selector is required");
1273 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1274 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1276 } else if (strstr(name, "text")) {
1277 LOGD("text selector is required");
1278 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1279 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1281 LOGE("invalid caps info");
1285 /* check selector and create it */
1286 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1287 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1292 LOGD("input-selector is already created.");
1296 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1298 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1300 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1301 LOGE("failed to link selector");
1302 gst_object_unref(GST_OBJECT(selector));
1307 LOGD("this track will be activated");
1308 g_object_set(selector, "active-pad", sinkpad, NULL);
1311 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1317 gst_caps_unref(caps);
1320 gst_object_unref(GST_OBJECT(sinkpad));
1328 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1330 GstPad *srcpad = NULL;
1333 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1335 LOGD("type %d", type);
1338 LOGD("there is no %d track", type);
1342 srcpad = gst_element_get_static_pad(selector, "src");
1344 LOGE("failed to get srcpad from selector");
1348 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1350 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1352 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1353 if (player->selector[type].block_id) {
1354 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1355 player->selector[type].block_id = 0;
1359 gst_object_unref(GST_OBJECT(srcpad));
1368 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1370 MMHandleType attrs = 0;
1371 gint active_index = 0;
1374 MMPLAYER_RETURN_IF_FAIL(player);
1376 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1378 /* change track to active pad */
1379 active_index = player->selector[type].active_pad_index;
1380 if ((active_index != DEFAULT_TRACK) &&
1381 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1382 LOGW("failed to change %d type track to %d", type, active_index);
1383 player->selector[type].active_pad_index = DEFAULT_TRACK;
1387 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1388 attrs = MMPLAYER_GET_ATTRS(player);
1390 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1391 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1393 if (mm_attrs_commit_all(attrs))
1394 LOGW("failed to commit attrs.");
1396 LOGW("cannot get content attribute");
1405 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1408 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1410 if (!audio_selector) {
1411 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1413 /* in case the source is changed, output can be changed. */
1414 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1415 LOGD("remove previous audiobin if it exist");
1417 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1418 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1420 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1421 MMPLAYER_FREEIF(player->pipeline->audiobin);
1424 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1425 __mmplayer_pipeline_complete(NULL, player);
1430 /* apply the audio track information */
1431 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1433 /* create audio sink path */
1434 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1435 LOGE("failed to create audio sink path");
1444 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1447 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1449 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1450 LOGD("text path is not supproted");
1454 /* apply the text track information */
1455 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1457 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1458 player->has_closed_caption = TRUE;
1460 /* create text decode path */
1461 player->no_more_pad = TRUE;
1463 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1464 LOGE("failed to create text sink path");
1473 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1475 gint64 dur_bytes = 0L;
1478 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1479 player->pipeline->mainbin && player->streamer, FALSE);
1481 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1482 LOGE("fail to get duration.");
1484 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1485 * use file information was already set on Q2 when it was created. */
1486 _mm_player_streaming_set_queue2(player->streamer,
1487 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1488 TRUE, /* use_buffering */
1489 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1490 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1497 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1499 mmplayer_t *player = NULL;
1500 GstElement *video_selector = NULL;
1501 GstElement *audio_selector = NULL;
1502 GstElement *text_selector = NULL;
1505 player = (mmplayer_t *)data;
1507 LOGD("no-more-pad signal handling");
1509 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1510 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1511 LOGW("player is shutting down");
1515 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1516 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1517 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1518 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1519 LOGE("failed to set queue2 buffering");
1524 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1525 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1526 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1528 if (!video_selector && !audio_selector && !text_selector) {
1529 LOGW("there is no selector");
1530 player->no_more_pad = TRUE;
1534 /* create video path followed by video-select */
1535 if (video_selector && !audio_selector && !text_selector)
1536 player->no_more_pad = TRUE;
1538 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1541 /* create audio path followed by audio-select */
1542 if (audio_selector && !text_selector)
1543 player->no_more_pad = TRUE;
1545 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1548 /* create text path followed by text-select */
1549 __mmplayer_create_text_sink_path(player, text_selector);
1552 if (player->gapless.reconfigure) {
1553 player->gapless.reconfigure = FALSE;
1554 MMPLAYER_PLAYBACK_UNLOCK(player);
1561 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1563 gboolean ret = FALSE;
1564 GstElement *pipeline = NULL;
1565 GstPad *sinkpad = NULL;
1568 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1569 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1571 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1573 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1575 LOGE("failed to get pad from sinkbin");
1581 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1582 LOGE("failed to link sinkbin for reusing");
1583 goto EXIT; /* exit either pass or fail */
1587 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1588 LOGE("failed to set state(READY) to sinkbin");
1593 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1594 LOGE("failed to add sinkbin to pipeline");
1599 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1600 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1605 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1606 LOGE("failed to set state(PAUSED) to sinkbin");
1615 gst_object_unref(GST_OBJECT(sinkpad));
1623 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1625 mmplayer_t *player = NULL;
1626 GstCaps *caps = NULL;
1627 gchar *caps_str = NULL;
1628 GstStructure *str = NULL;
1629 const gchar *name = NULL;
1630 GstElement *sinkbin = NULL;
1631 gboolean reusing = FALSE;
1632 gboolean caps_ret = TRUE;
1633 gchar *sink_pad_name = "sink";
1636 player = (mmplayer_t *)data;
1639 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1640 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1642 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1646 caps_str = gst_caps_to_string(caps);
1648 /* LOGD("detected mimetype : %s", name); */
1649 if (strstr(name, "audio")) {
1650 if (player->pipeline->audiobin == NULL) {
1651 const gchar *audio_format = gst_structure_get_string(str, "format");
1653 LOGD("original audio format %s", audio_format);
1654 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1657 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1658 LOGE("failed to create audiobin. continuing without audio");
1662 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1663 LOGD("creating audiobin success");
1666 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1667 LOGD("reusing audiobin");
1668 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1670 } else if (strstr(name, "video")) {
1671 /* 1. zero copy is updated at _decode_pad_added()
1672 * 2. NULL surface type is handled in _decode_pad_added() */
1673 LOGD("zero copy %d", player->set_mode.video_zc);
1674 if (player->pipeline->videobin == NULL) {
1675 int surface_type = 0;
1676 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1677 LOGD("display_surface_type (%d)", surface_type);
1679 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1680 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1681 LOGE("failed to acquire video overlay resource");
1685 player->interrupted_by_resource = FALSE;
1687 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1688 LOGE("failed to create videobin. continuing without video");
1692 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1693 LOGD("creating videosink bin success");
1696 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1697 LOGD("re-using videobin");
1698 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1700 } else if (strstr(name, "text")) {
1701 if (player->pipeline->textbin == NULL) {
1702 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1703 LOGE("failed to create text sink bin. continuing without text");
1707 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1708 player->textsink_linked = 1;
1709 LOGD("creating textsink bin success");
1711 if (!player->textsink_linked) {
1712 LOGD("re-using textbin");
1714 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1715 player->textsink_linked = 1;
1717 /* linked textbin exist which means that the external subtitle path exist already */
1718 LOGW("ignoring internal subtutle since external subtitle is available");
1721 sink_pad_name = "text_sink";
1723 LOGW("unknown mime type %s, ignoring it", name);
1727 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1730 LOGD("[handle: %p] success to create and link sink bin", player);
1732 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1733 * streaming task. if the task blocked, then buffer will not flow to the next element
1734 *(autoplugging element). so this is special hack for streaming. please try to remove it
1736 /* dec stream count. we can remove fakesink if it's zero */
1737 if (player->num_dynamic_pad)
1738 player->num_dynamic_pad--;
1740 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1742 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1743 __mmplayer_pipeline_complete(NULL, player);
1747 MMPLAYER_FREEIF(caps_str);
1750 gst_caps_unref(caps);
1756 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1758 int required_angle = 0; /* Angle required for straight view */
1759 int rotation_angle = 0;
1761 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1762 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1764 /* Counter clockwise */
1765 switch (orientation) {
1770 required_angle = 270;
1773 required_angle = 180;
1776 required_angle = 90;
1780 rotation_angle = display_angle + required_angle;
1781 if (rotation_angle >= 360)
1782 rotation_angle -= 360;
1784 /* chech if supported or not */
1785 if (rotation_angle % 90) {
1786 LOGD("not supported rotation angle = %d", rotation_angle);
1790 switch (rotation_angle) {
1792 *value = MM_DISPLAY_ROTATION_NONE;
1795 *value = MM_DISPLAY_ROTATION_90;
1798 *value = MM_DISPLAY_ROTATION_180;
1801 *value = MM_DISPLAY_ROTATION_270;
1805 LOGD("setting rotation property value : %d", *value);
1811 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1813 /* check video sinkbin is created */
1814 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1816 player->pipeline->videobin &&
1817 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1818 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1819 MM_ERROR_PLAYER_NOT_INITIALIZED);
1821 return MM_ERROR_NONE;
1825 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1827 int display_rotation = 0;
1828 gchar *org_orient = NULL;
1829 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1832 LOGE("cannot get content attribute");
1833 return MM_ERROR_PLAYER_INTERNAL;
1836 if (display_angle) {
1837 /* update user roation */
1838 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1840 /* Counter clockwise */
1841 switch (display_rotation) {
1842 case MM_DISPLAY_ROTATION_NONE:
1845 case MM_DISPLAY_ROTATION_90:
1846 *display_angle = 90;
1848 case MM_DISPLAY_ROTATION_180:
1849 *display_angle = 180;
1851 case MM_DISPLAY_ROTATION_270:
1852 *display_angle = 270;
1855 LOGW("wrong angle type : %d", display_rotation);
1858 LOGD("check user angle: %d", *display_angle);
1862 /* Counter clockwise */
1863 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1866 if (!strcmp(org_orient, "rotate-90"))
1868 else if (!strcmp(org_orient, "rotate-180"))
1870 else if (!strcmp(org_orient, "rotate-270"))
1873 LOGD("original rotation is %s", org_orient);
1875 LOGD("content_video_orientation get fail");
1878 LOGD("check orientation: %d", *orientation);
1881 return MM_ERROR_NONE;
1885 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1887 int rotation_value = 0;
1888 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1889 int display_angle = 0;
1892 /* check video sinkbin is created */
1893 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1896 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1898 /* get rotation value to set */
1899 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1900 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1901 LOGD("set video param : rotate %d", rotation_value);
1905 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1907 MMHandleType attrs = 0;
1911 /* check video sinkbin is created */
1912 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1915 attrs = MMPLAYER_GET_ATTRS(player);
1916 MMPLAYER_RETURN_IF_FAIL(attrs);
1918 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1919 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1920 LOGD("set video param : visible %d", visible);
1924 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1926 MMHandleType attrs = 0;
1927 int display_method = 0;
1930 /* check video sinkbin is created */
1931 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1934 attrs = MMPLAYER_GET_ATTRS(player);
1935 MMPLAYER_RETURN_IF_FAIL(attrs);
1937 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1938 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1939 LOGD("set video param : method %d", display_method);
1943 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1945 MMHandleType attrs = 0;
1946 void *handle = NULL;
1949 /* check video sinkbin is created */
1950 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1951 LOGW("There is no video sink");
1955 attrs = MMPLAYER_GET_ATTRS(player);
1956 MMPLAYER_RETURN_IF_FAIL(attrs);
1957 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1959 gst_video_overlay_set_video_roi_area(
1960 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1961 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1962 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1963 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1968 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1970 MMHandleType attrs = 0;
1971 void *handle = NULL;
1975 int win_roi_width = 0;
1976 int win_roi_height = 0;
1979 /* check video sinkbin is created */
1980 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1981 LOGW("There is no video sink");
1985 attrs = MMPLAYER_GET_ATTRS(player);
1986 MMPLAYER_RETURN_IF_FAIL(attrs);
1988 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1991 /* It should be set after setting window */
1992 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1993 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1994 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1995 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1997 /* After setting window handle, set display roi area */
1998 gst_video_overlay_set_display_roi_area(
1999 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2000 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2001 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2002 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2007 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2009 MMHandleType attrs = 0;
2010 void *handle = NULL;
2012 /* check video sinkbin is created */
2013 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2016 attrs = MMPLAYER_GET_ATTRS(player);
2017 MMPLAYER_RETURN_IF_FAIL(attrs);
2019 /* common case if using overlay surface */
2020 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2023 /* default is using wl_surface_id */
2024 unsigned int wl_surface_id = 0;
2025 wl_surface_id = *(int *)handle;
2026 LOGD("set video param : wl_surface_id %d", wl_surface_id);
2027 gst_video_overlay_set_wl_window_wl_surface_id(
2028 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2031 /* FIXIT : is it error case? */
2032 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2037 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2039 gboolean update_all_param = FALSE;
2042 /* check video sinkbin is created */
2043 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2044 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2046 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2047 LOGE("can not find tizenwlsink");
2048 return MM_ERROR_PLAYER_INTERNAL;
2051 LOGD("param_name : %s", param_name);
2052 if (!g_strcmp0(param_name, "update_all_param"))
2053 update_all_param = TRUE;
2055 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2056 __mmplayer_video_param_set_display_overlay(player);
2057 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2058 __mmplayer_video_param_set_display_method(player);
2059 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2060 __mmplayer_video_param_set_display_visible(player);
2061 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2062 __mmplayer_video_param_set_display_rotation(player);
2063 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2064 __mmplayer_video_param_set_roi_area(player);
2065 if (update_all_param)
2066 __mmplayer_video_param_set_video_roi_area(player);
2068 return MM_ERROR_NONE;
2072 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2074 MMHandleType attrs = 0;
2075 int surface_type = 0;
2076 int ret = MM_ERROR_NONE;
2080 /* check video sinkbin is created */
2081 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2082 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2084 attrs = MMPLAYER_GET_ATTRS(player);
2086 LOGE("cannot get content attribute");
2087 return MM_ERROR_PLAYER_INTERNAL;
2089 LOGD("param_name : %s", param_name);
2091 /* update display surface */
2092 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2093 LOGD("check display surface type attribute: %d", surface_type);
2095 /* configuring display */
2096 switch (surface_type) {
2097 case MM_DISPLAY_SURFACE_OVERLAY:
2099 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2100 if (ret != MM_ERROR_NONE)
2108 return MM_ERROR_NONE;
2112 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2114 gboolean disable_overlay = FALSE;
2115 mmplayer_t *player = (mmplayer_t *)hplayer;
2118 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2119 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2120 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2121 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2123 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2124 LOGW("Display control is not supported");
2125 return MM_ERROR_PLAYER_INTERNAL;
2128 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2130 if (audio_only == (bool)disable_overlay) {
2131 LOGE("It's the same with current setting: (%d)", audio_only);
2132 return MM_ERROR_NONE;
2136 LOGE("disable overlay");
2137 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2139 /* release overlay resource */
2140 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2141 LOGE("failed to release overlay resource");
2145 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2146 LOGE("failed to acquire video overlay resource");
2149 player->interrupted_by_resource = FALSE;
2151 LOGD("enable overlay");
2152 __mmplayer_video_param_set_display_overlay(player);
2153 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2158 return MM_ERROR_NONE;
2162 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2164 mmplayer_t *player = (mmplayer_t *)hplayer;
2165 gboolean disable_overlay = FALSE;
2169 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2170 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2171 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2172 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2173 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2175 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2176 LOGW("Display control is not supported");
2177 return MM_ERROR_PLAYER_INTERNAL;
2180 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2182 *paudio_only = (bool)disable_overlay;
2184 LOGD("audio_only : %d", *paudio_only);
2188 return MM_ERROR_NONE;
2192 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2194 GList *bucket = element_bucket;
2195 mmplayer_gst_element_t *element = NULL;
2196 mmplayer_gst_element_t *prv_element = NULL;
2197 GstElement *tee_element = NULL;
2198 gint successful_link_count = 0;
2202 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2204 prv_element = (mmplayer_gst_element_t *)bucket->data;
2205 bucket = bucket->next;
2207 for (; bucket; bucket = bucket->next) {
2208 element = (mmplayer_gst_element_t *)bucket->data;
2210 if (element && element->gst) {
2211 if (prv_element && prv_element->gst) {
2212 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2214 prv_element->gst = tee_element;
2216 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2217 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2218 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2222 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2223 LOGD("linking [%s] to [%s] success",
2224 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2225 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2226 successful_link_count++;
2227 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2228 LOGD("keep audio-tee element for next audio pipeline branch");
2229 tee_element = prv_element->gst;
2232 LOGD("linking [%s] to [%s] failed",
2233 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2234 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2240 prv_element = element;
2245 return successful_link_count;
2249 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2251 GList *bucket = element_bucket;
2252 mmplayer_gst_element_t *element = NULL;
2253 int successful_add_count = 0;
2257 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2258 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2260 for (; bucket; bucket = bucket->next) {
2261 element = (mmplayer_gst_element_t *)bucket->data;
2263 if (element && element->gst) {
2264 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2265 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2266 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2267 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2270 successful_add_count++;
2276 return successful_add_count;
2280 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2282 mmplayer_t *player = (mmplayer_t *)data;
2283 GstCaps *caps = NULL;
2284 GstStructure *str = NULL;
2286 gboolean caps_ret = TRUE;
2290 MMPLAYER_RETURN_IF_FAIL(pad);
2291 MMPLAYER_RETURN_IF_FAIL(unused);
2292 MMPLAYER_RETURN_IF_FAIL(data);
2294 caps = gst_pad_get_current_caps(pad);
2298 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2302 LOGD("name = %s", name);
2304 if (strstr(name, "audio")) {
2305 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2307 if (player->audio_stream_changed_cb) {
2308 LOGE("call the audio stream changed cb");
2309 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2311 } else if (strstr(name, "video")) {
2312 if ((name = gst_structure_get_string(str, "format")))
2313 player->set_mode.video_zc = name[0] == 'S';
2315 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2316 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2318 LOGW("invalid caps info");
2323 gst_caps_unref(caps);
2331 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2336 MMPLAYER_RETURN_IF_FAIL(player);
2338 if (player->audio_stream_buff_list) {
2339 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2340 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2343 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2344 __mmplayer_audio_stream_send_data(player, tmp);
2346 MMPLAYER_FREEIF(tmp->pcm_data);
2347 MMPLAYER_FREEIF(tmp);
2350 g_list_free(player->audio_stream_buff_list);
2351 player->audio_stream_buff_list = NULL;
2358 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2360 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2363 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2365 audio_stream.bitrate = a_buffer->bitrate;
2366 audio_stream.channel = a_buffer->channel;
2367 audio_stream.depth = a_buffer->depth;
2368 audio_stream.is_little_endian = a_buffer->is_little_endian;
2369 audio_stream.channel_mask = a_buffer->channel_mask;
2370 audio_stream.data_size = a_buffer->data_size;
2371 audio_stream.data = a_buffer->pcm_data;
2372 audio_stream.pcm_format = a_buffer->pcm_format;
2374 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2375 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2381 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2383 mmplayer_t *player = (mmplayer_t *)data;
2384 const gchar *pcm_format = NULL;
2388 gint endianness = 0;
2389 guint64 channel_mask = 0;
2390 void *a_data = NULL;
2392 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2393 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2397 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2399 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2400 a_data = mapinfo.data;
2401 a_size = mapinfo.size;
2403 GstCaps *caps = gst_pad_get_current_caps(pad);
2404 GstStructure *structure = gst_caps_get_structure(caps, 0);
2406 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2407 pcm_format = gst_structure_get_string(structure, "format");
2408 gst_structure_get_int(structure, "rate", &rate);
2409 gst_structure_get_int(structure, "channels", &channel);
2410 gst_structure_get_int(structure, "depth", &depth);
2411 gst_structure_get_int(structure, "endianness", &endianness);
2412 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2413 gst_caps_unref(GST_CAPS(caps));
2415 /* In case of the sync is false, use buffer list. *
2416 * The num of buffer list depends on the num of audio channels */
2417 if (player->audio_stream_buff_list) {
2418 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2419 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2421 if (channel_mask == tmp->channel_mask) {
2422 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2423 if (tmp->data_size + a_size < tmp->buff_size) {
2424 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2425 tmp->data_size += a_size;
2427 /* send data to client */
2428 __mmplayer_audio_stream_send_data(player, tmp);
2430 if (a_size > tmp->buff_size) {
2431 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2432 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2433 if (tmp->pcm_data == NULL) {
2434 LOGE("failed to realloc data.");
2437 tmp->buff_size = a_size;
2439 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2440 memcpy(tmp->pcm_data, a_data, a_size);
2441 tmp->data_size = a_size;
2446 LOGE("data is empty in list.");
2452 /* create new audio stream data for newly found audio channel */
2453 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2454 if (a_buffer == NULL) {
2455 LOGE("failed to alloc data.");
2458 a_buffer->bitrate = rate;
2459 a_buffer->channel = channel;
2460 a_buffer->depth = depth;
2461 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2462 a_buffer->channel_mask = channel_mask;
2463 a_buffer->data_size = a_size;
2464 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2466 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2467 /* If sync is FALSE, use buffer list to reduce the IPC. */
2468 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2469 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2470 if (a_buffer->pcm_data == NULL) {
2471 LOGE("failed to alloc data.");
2472 MMPLAYER_FREEIF(a_buffer);
2475 memcpy(a_buffer->pcm_data, a_data, a_size);
2476 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2477 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2479 /* If sync is TRUE, send data directly. */
2480 a_buffer->pcm_data = a_data;
2481 __mmplayer_audio_stream_send_data(player, a_buffer);
2482 MMPLAYER_FREEIF(a_buffer);
2486 gst_buffer_unmap(buffer, &mapinfo);
2491 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2493 mmplayer_t *player = (mmplayer_t *)data;
2494 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2495 GstPad *sinkpad = NULL;
2496 GstElement *queue = NULL, *sink = NULL;
2499 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2501 queue = gst_element_factory_make("queue", NULL);
2502 if (queue == NULL) {
2503 LOGD("fail make queue");
2507 sink = gst_element_factory_make("fakesink", NULL);
2509 LOGD("fail make fakesink");
2513 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2515 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2516 LOGW("failed to link queue & sink");
2520 sinkpad = gst_element_get_static_pad(queue, "sink");
2522 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2523 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2527 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2529 gst_object_unref(sinkpad);
2530 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2531 g_object_set(sink, "sync", TRUE, NULL);
2532 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2534 /* keep the first sink reference only */
2535 if (!audiobin[MMPLAYER_A_SINK].gst) {
2536 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2537 audiobin[MMPLAYER_A_SINK].gst = sink;
2540 gst_element_set_state(sink, GST_STATE_PAUSED);
2541 gst_element_set_state(queue, GST_STATE_PAUSED);
2543 _mmplayer_add_signal_connection(player,
2545 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2547 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2550 __mmplayer_add_sink(player, sink);
2556 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2558 gst_object_unref(GST_OBJECT(queue));
2562 gst_object_unref(GST_OBJECT(sink));
2566 gst_object_unref(GST_OBJECT(sinkpad));
2574 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2576 #define MAX_PROPS_LEN 128
2577 mmplayer_gst_element_t *audiobin = NULL;
2578 gint latency_mode = 0;
2579 gchar *stream_type = NULL;
2580 gchar *latency = NULL;
2582 gchar stream_props[MAX_PROPS_LEN] = {0,};
2583 GstStructure *props = NULL;
2586 * It should be set after player creation through attribute.
2587 * But, it can not be changed during playing.
2590 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2592 audiobin = player->pipeline->audiobin;
2594 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2595 if (player->sound.mute) {
2596 LOGD("mute enabled");
2597 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2600 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2601 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2604 snprintf(stream_props, sizeof(stream_props) - 1, "props,application.process.id.origin=%d", player->client_pid);
2606 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2607 stream_type, stream_id, player->client_pid);
2609 props = gst_structure_from_string(stream_props, NULL);
2610 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2611 LOGI("props result[%s].", stream_props);
2612 gst_structure_free(props);
2614 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2616 switch (latency_mode) {
2617 case AUDIO_LATENCY_MODE_LOW:
2618 latency = g_strndup("low", 3);
2620 case AUDIO_LATENCY_MODE_MID:
2621 latency = g_strndup("mid", 3);
2623 case AUDIO_LATENCY_MODE_HIGH:
2624 latency = g_strndup("high", 4);
2628 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2630 LOGD("audiosink property - latency=%s", latency);
2632 MMPLAYER_FREEIF(latency);
2638 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2640 mmplayer_gst_element_t *audiobin = NULL;
2643 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2645 audiobin = player->pipeline->audiobin;
2647 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2648 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2649 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2651 if (player->video360_yaw_radians <= M_PI &&
2652 player->video360_yaw_radians >= -M_PI &&
2653 player->video360_pitch_radians <= M_PI_2 &&
2654 player->video360_pitch_radians >= -M_PI_2) {
2655 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2656 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2657 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2658 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2659 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2660 "source-orientation-y", player->video360_metadata.init_view_heading,
2661 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2668 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2670 mmplayer_gst_element_t *audiobin = NULL;
2671 GstPad *sink_pad = NULL;
2672 GstCaps *acaps = NULL;
2674 int pitch_control = 0;
2675 double pitch_value = 1.0;
2678 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2679 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2681 audiobin = player->pipeline->audiobin;
2683 LOGD("make element for normal audio playback");
2685 /* audio bin structure for playback. {} means optional.
2686 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2688 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2689 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2692 /* for pitch control */
2693 mm_attrs_multiple_get(player->attrs, NULL,
2694 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2695 MM_PLAYER_PITCH_VALUE, &pitch_value,
2698 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2699 if (pitch_control && (player->videodec_linked == 0)) {
2700 GstElementFactory *factory;
2702 factory = gst_element_factory_find("pitch");
2704 gst_object_unref(factory);
2707 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2710 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2711 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2713 LOGW("there is no pitch element");
2718 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2720 /* replaygain volume */
2721 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2722 if (player->sound.rg_enable)
2723 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2725 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2728 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2730 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2731 /* currently, only openalsink uses volume element */
2732 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2735 if (player->sound.mute) {
2736 LOGD("mute enabled");
2737 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2741 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2743 /* audio effect element. if audio effect is enabled */
2744 if ((strcmp(player->ini.audioeffect_element, ""))
2746 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2747 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2749 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2751 if ((!player->bypass_audio_effect)
2752 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2753 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2754 if (!_mmplayer_audio_effect_custom_apply(player))
2755 LOGI("apply audio effect(custom) setting success");
2759 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2760 && (player->set_mode.rich_audio)) {
2761 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2765 /* create audio sink */
2766 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2767 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2768 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2770 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2771 if (player->is_360_feature_enabled &&
2772 player->is_content_spherical &&
2774 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2775 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2776 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2778 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2780 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2782 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2783 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2784 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2785 gst_caps_unref(acaps);
2787 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2789 player->is_openal_plugin_used = TRUE;
2791 if (player->is_360_feature_enabled && player->is_content_spherical)
2792 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2793 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2796 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2797 (player->videodec_linked && player->ini.use_system_clock)) {
2798 LOGD("system clock will be used.");
2799 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2802 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2803 __mmplayer_gst_set_pulsesink_property(player);
2804 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2805 __mmplayer_gst_set_openalsink_property(player);
2808 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2809 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2811 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2812 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2813 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2814 gst_object_unref(GST_OBJECT(sink_pad));
2816 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2819 return MM_ERROR_NONE;
2821 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2823 return MM_ERROR_PLAYER_INTERNAL;
2827 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2829 mmplayer_gst_element_t *audiobin = NULL;
2830 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2832 gchar *dst_format = NULL;
2834 int dst_samplerate = 0;
2835 int dst_channels = 0;
2836 GstCaps *caps = NULL;
2837 char *caps_str = NULL;
2840 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2841 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2843 audiobin = player->pipeline->audiobin;
2845 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2847 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2849 [case 1] extract interleave audio pcm without playback
2850 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2851 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2853 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2855 [case 2] deinterleave for each channel without playback
2856 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2857 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2859 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2860 - fakesink (sync or not)
2863 [case 3] [case 1(sync only)] + playback
2864 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2866 * src - ... - tee - queue1 - playback path
2867 - queue2 - [case1 pipeline with sync]
2869 [case 4] [case 2(sync only)] + playback
2870 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2872 * src - ... - tee - queue1 - playback path
2873 - queue2 - [case2 pipeline with sync]
2877 /* 1. create tee and playback path
2878 'tee' should be added at first to copy the decoded stream
2880 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2881 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2882 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2884 /* tee - path 1 : for playback path */
2885 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2886 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2888 /* tee - path 2 : for extract path */
2889 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2890 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2893 /* if there is tee, 'tee - path 2' is linked here */
2895 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2898 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2900 /* 2. decide the extract pcm format */
2901 mm_attrs_multiple_get(player->attrs, NULL,
2902 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2903 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2904 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2907 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2908 dst_format, dst_len, dst_samplerate, dst_channels);
2910 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2911 mm_attrs_multiple_get(player->attrs, NULL,
2912 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2913 "content_audio_samplerate", &dst_samplerate,
2914 "content_audio_channels", &dst_channels,
2917 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2918 dst_format, dst_len, dst_samplerate, dst_channels);
2920 /* If there is no enough information, set it to platform default value. */
2921 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2922 LOGD("set platform default format");
2923 dst_format = DEFAULT_PCM_OUT_FORMAT;
2925 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2926 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2929 /* 3. create capsfilter */
2930 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2931 caps = gst_caps_new_simple("audio/x-raw",
2932 "format", G_TYPE_STRING, dst_format,
2933 "rate", G_TYPE_INT, dst_samplerate,
2934 "channels", G_TYPE_INT, dst_channels,
2937 caps_str = gst_caps_to_string(caps);
2938 LOGD("new caps : %s", caps_str);
2940 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2943 gst_caps_unref(caps);
2944 MMPLAYER_FREEIF(caps_str);
2946 /* 4-1. create deinterleave to extract pcm for each channel */
2947 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2948 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2949 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2951 /* audiosink will be added after getting signal for each channel */
2952 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2953 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2955 /* 4-2. create fakesink to extract interlevaed pcm */
2956 LOGD("add audio fakesink for interleaved audio");
2957 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2958 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2959 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2960 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2962 _mmplayer_add_signal_connection(player,
2963 G_OBJECT(audiobin[extract_sink_id].gst),
2964 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2966 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2969 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2973 return MM_ERROR_NONE;
2975 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2977 return MM_ERROR_PLAYER_INTERNAL;
2981 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2983 int ret = MM_ERROR_NONE;
2984 mmplayer_gst_element_t *audiobin = NULL;
2985 GList *element_bucket = NULL;
2988 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2989 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2991 audiobin = player->pipeline->audiobin;
2993 if (player->build_audio_offload) { /* skip all the audio filters */
2994 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2996 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2997 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2998 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3000 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3004 /* FIXME: need to mention the supportable condition at API reference */
3005 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3006 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3008 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3010 if (ret != MM_ERROR_NONE)
3013 LOGD("success to make audio bin element");
3014 *bucket = element_bucket;
3017 return MM_ERROR_NONE;
3020 LOGE("failed to make audio bin element");
3021 g_list_free(element_bucket);
3025 return MM_ERROR_PLAYER_INTERNAL;
3029 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3031 mmplayer_gst_element_t *first_element = NULL;
3032 mmplayer_gst_element_t *audiobin = NULL;
3034 GstPad *ghostpad = NULL;
3035 GList *element_bucket = NULL;
3039 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3042 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3044 LOGE("failed to allocate memory for audiobin");
3045 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3049 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3050 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3051 if (!audiobin[MMPLAYER_A_BIN].gst) {
3052 LOGE("failed to create audiobin");
3057 player->pipeline->audiobin = audiobin;
3059 /* create audio filters and audiosink */
3060 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3063 /* adding created elements to bin */
3064 LOGD("adding created elements to bin");
3065 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3068 /* linking elements in the bucket by added order. */
3069 LOGD("Linking elements in the bucket by added order.");
3070 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3073 /* get first element's sinkpad for creating ghostpad */
3074 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3075 if (!first_element) {
3076 LOGE("failed to get first elem");
3080 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3082 LOGE("failed to get pad from first element of audiobin");
3086 ghostpad = gst_ghost_pad_new("sink", pad);
3088 LOGE("failed to create ghostpad");
3092 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3093 LOGE("failed to add ghostpad to audiobin");
3097 gst_object_unref(pad);
3099 g_list_free(element_bucket);
3102 return MM_ERROR_NONE;
3105 LOGD("ERROR : releasing audiobin");
3108 gst_object_unref(GST_OBJECT(pad));
3111 gst_object_unref(GST_OBJECT(ghostpad));
3114 g_list_free(element_bucket);
3116 /* release element which are not added to bin */
3117 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3118 /* NOTE : skip bin */
3119 if (audiobin[i].gst) {
3120 GstObject *parent = NULL;
3121 parent = gst_element_get_parent(audiobin[i].gst);
3124 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3125 audiobin[i].gst = NULL;
3127 gst_object_unref(GST_OBJECT(parent));
3131 /* release audiobin with it's childs */
3132 if (audiobin[MMPLAYER_A_BIN].gst)
3133 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3135 MMPLAYER_FREEIF(audiobin);
3137 player->pipeline->audiobin = NULL;
3139 return MM_ERROR_PLAYER_INTERNAL;
3143 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3145 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3149 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3151 int ret = MM_ERROR_NONE;
3153 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3154 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3156 MMPLAYER_VIDEO_BO_LOCK(player);
3158 if (player->video_bo_list) {
3159 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3160 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3161 if (tmp && tmp->bo == bo) {
3163 LOGD("release bo %p", bo);
3164 tbm_bo_unref(tmp->bo);
3165 MMPLAYER_VIDEO_BO_UNLOCK(player);
3166 MMPLAYER_VIDEO_BO_SIGNAL(player);
3171 /* hw codec is running or the list was reset for DRC. */
3172 LOGW("there is no bo list.");
3174 MMPLAYER_VIDEO_BO_UNLOCK(player);
3176 LOGW("failed to find bo %p", bo);
3181 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3186 MMPLAYER_RETURN_IF_FAIL(player);
3188 MMPLAYER_VIDEO_BO_LOCK(player);
3189 if (player->video_bo_list) {
3190 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3191 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3192 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3195 tbm_bo_unref(tmp->bo);
3199 g_list_free(player->video_bo_list);
3200 player->video_bo_list = NULL;
3202 player->video_bo_size = 0;
3203 MMPLAYER_VIDEO_BO_UNLOCK(player);
3210 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3213 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3214 gboolean ret = TRUE;
3216 /* check DRC, if it is, destroy the prev bo list to create again */
3217 if (player->video_bo_size != size) {
3218 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3219 __mmplayer_video_stream_destroy_bo_list(player);
3220 player->video_bo_size = size;
3223 MMPLAYER_VIDEO_BO_LOCK(player);
3225 if ((!player->video_bo_list) ||
3226 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3228 /* create bo list */
3230 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3232 if (player->video_bo_list) {
3233 /* if bo list did not created all, try it again. */
3234 idx = g_list_length(player->video_bo_list);
3235 LOGD("bo list exist(len: %d)", idx);
3238 for (; idx < player->ini.num_of_video_bo; idx++) {
3239 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3241 LOGE("Fail to alloc bo_info.");
3244 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3246 LOGE("Fail to tbm_bo_alloc.");
3247 MMPLAYER_FREEIF(bo_info);
3250 bo_info->used = FALSE;
3251 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3254 /* update video num buffers */
3255 LOGD("video_num_buffers : %d", idx);
3256 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3257 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3260 MMPLAYER_VIDEO_BO_UNLOCK(player);
3266 /* get bo from list*/
3267 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3268 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3269 if (tmp && (tmp->used == FALSE)) {
3270 LOGD("found bo %p to use", tmp->bo);
3272 MMPLAYER_VIDEO_BO_UNLOCK(player);
3273 return tbm_bo_ref(tmp->bo);
3277 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3278 MMPLAYER_VIDEO_BO_UNLOCK(player);
3282 if (player->ini.video_bo_timeout <= 0) {
3283 MMPLAYER_VIDEO_BO_WAIT(player);
3285 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3286 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3293 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3295 mmplayer_t *player = (mmplayer_t *)data;
3297 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3299 /* send prerolled pkt */
3300 player->video_stream_prerolled = false;
3302 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3304 /* not to send prerolled pkt again */
3305 player->video_stream_prerolled = true;
3309 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3311 mmplayer_t *player = (mmplayer_t *)data;
3312 mmplayer_video_decoded_data_info_t *stream = NULL;
3313 GstMemory *mem = NULL;
3316 MMPLAYER_RETURN_IF_FAIL(player);
3317 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3319 if (player->video_stream_prerolled) {
3320 player->video_stream_prerolled = false;
3321 LOGD("skip the prerolled pkt not to send it again");
3325 /* clear stream data structure */
3326 stream = __mmplayer_create_stream_from_pad(pad);
3328 LOGE("failed to alloc stream");
3332 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3334 /* set size and timestamp */
3335 mem = gst_buffer_peek_memory(buffer, 0);
3336 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3337 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3339 /* check zero-copy */
3340 if (player->set_mode.video_zc &&
3341 player->set_mode.video_export &&
3342 gst_is_tizen_memory(mem)) {
3343 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3344 stream->internal_buffer = gst_buffer_ref(buffer);
3345 } else { /* sw codec */
3346 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3349 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3353 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3354 LOGE("failed to send video decoded data.");
3361 LOGE("release video stream resource.");
3362 if (gst_is_tizen_memory(mem)) {
3364 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3366 tbm_bo_unref(stream->bo[i]);
3369 /* unref gst buffer */
3370 if (stream->internal_buffer)
3371 gst_buffer_unref(stream->internal_buffer);
3374 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3376 MMPLAYER_FREEIF(stream);
3381 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3383 mmplayer_gst_element_t *videobin = NULL;
3386 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3388 videobin = player->pipeline->videobin;
3390 /* Set spatial media metadata and/or user settings to the element.
3392 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3393 "projection-type", player->video360_metadata.projection_type, NULL);
3395 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3396 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3398 if (player->video360_metadata.full_pano_width_pixels &&
3399 player->video360_metadata.full_pano_height_pixels &&
3400 player->video360_metadata.cropped_area_image_width &&
3401 player->video360_metadata.cropped_area_image_height) {
3402 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3403 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3404 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3405 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3406 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3407 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3408 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3412 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3413 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3414 "horizontal-fov", player->video360_horizontal_fov,
3415 "vertical-fov", player->video360_vertical_fov, NULL);
3418 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3419 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3420 "zoom", 1.0f / player->video360_zoom, NULL);
3423 if (player->video360_yaw_radians <= M_PI &&
3424 player->video360_yaw_radians >= -M_PI &&
3425 player->video360_pitch_radians <= M_PI_2 &&
3426 player->video360_pitch_radians >= -M_PI_2) {
3427 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3428 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3429 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3430 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3431 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3432 "pose-yaw", player->video360_metadata.init_view_heading,
3433 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3436 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3437 "passthrough", !player->is_video360_enabled, NULL);
3444 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3446 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3447 GList *element_bucket = NULL;
3450 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3452 /* create video360 filter */
3453 if (player->is_360_feature_enabled && player->is_content_spherical) {
3454 LOGD("create video360 element");
3455 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3456 __mmplayer_gst_set_video360_property(player);
3460 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3461 LOGD("skip creating the videoconv and rotator");
3462 return MM_ERROR_NONE;
3465 /* in case of sw codec & overlay surface type, except 360 playback.
3466 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3467 LOGD("create video converter: %s", video_csc);
3468 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3471 *bucket = element_bucket;
3473 return MM_ERROR_NONE;
3475 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3476 g_list_free(element_bucket);
3480 return MM_ERROR_PLAYER_INTERNAL;
3484 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3486 gchar *factory_name = NULL;
3488 switch (surface_type) {
3489 case MM_DISPLAY_SURFACE_OVERLAY:
3490 if (strlen(player->ini.videosink_element_overlay) > 0)
3491 factory_name = player->ini.videosink_element_overlay;
3493 case MM_DISPLAY_SURFACE_REMOTE:
3494 case MM_DISPLAY_SURFACE_NULL:
3495 if (strlen(player->ini.videosink_element_fake) > 0)
3496 factory_name = player->ini.videosink_element_fake;
3499 LOGE("unidentified surface type");
3503 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3504 return factory_name;
3508 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3510 gchar *factory_name = NULL;
3511 mmplayer_gst_element_t *videobin = NULL;
3516 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3518 videobin = player->pipeline->videobin;
3519 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3521 attrs = MMPLAYER_GET_ATTRS(player);
3523 LOGE("cannot get content attribute");
3524 return MM_ERROR_PLAYER_INTERNAL;
3527 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3528 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3529 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3531 /* support shard memory with S/W codec on HawkP */
3532 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3533 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3534 "use-tbm", use_tbm, NULL);
3538 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3539 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3542 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3544 LOGD("disable last-sample");
3545 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3548 if (player->set_mode.video_export) {
3550 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3551 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3552 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3554 _mmplayer_add_signal_connection(player,
3555 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3556 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3558 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3561 _mmplayer_add_signal_connection(player,
3562 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3563 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3565 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3569 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3570 return MM_ERROR_PLAYER_INTERNAL;
3572 if (videobin[MMPLAYER_V_SINK].gst) {
3573 GstPad *sink_pad = NULL;
3574 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3576 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3577 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3578 gst_object_unref(GST_OBJECT(sink_pad));
3580 LOGE("failed to get sink pad from videosink");
3584 return MM_ERROR_NONE;
3589 * - video overlay surface(arm/x86) : tizenwlsink
3592 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3595 GList *element_bucket = NULL;
3596 mmplayer_gst_element_t *first_element = NULL;
3597 mmplayer_gst_element_t *videobin = NULL;
3598 gchar *videosink_factory_name = NULL;
3601 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3604 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3606 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3608 player->pipeline->videobin = videobin;
3611 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3612 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3613 if (!videobin[MMPLAYER_V_BIN].gst) {
3614 LOGE("failed to create videobin");
3618 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3621 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3622 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3624 /* additional setting for sink plug-in */
3625 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3626 LOGE("failed to set video property");
3630 /* store it as it's sink element */
3631 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3633 /* adding created elements to bin */
3634 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3635 LOGE("failed to add elements");
3639 /* Linking elements in the bucket by added order */
3640 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3641 LOGE("failed to link elements");
3645 /* get first element's sinkpad for creating ghostpad */
3646 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3647 if (!first_element) {
3648 LOGE("failed to get first element from bucket");
3652 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3654 LOGE("failed to get pad from first element");
3658 /* create ghostpad */
3659 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3660 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3661 LOGE("failed to add ghostpad to videobin");
3664 gst_object_unref(pad);
3666 /* done. free allocated variables */
3667 g_list_free(element_bucket);
3671 return MM_ERROR_NONE;
3674 LOGE("ERROR : releasing videobin");
3675 g_list_free(element_bucket);
3678 gst_object_unref(GST_OBJECT(pad));
3680 /* release videobin with it's childs */
3681 if (videobin[MMPLAYER_V_BIN].gst)
3682 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3684 MMPLAYER_FREEIF(videobin);
3685 player->pipeline->videobin = NULL;
3687 return MM_ERROR_PLAYER_INTERNAL;
3691 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3693 GList *element_bucket = NULL;
3694 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3696 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3697 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3698 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3699 "signal-handoffs", FALSE,
3702 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3703 _mmplayer_add_signal_connection(player,
3704 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3705 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3707 G_CALLBACK(__mmplayer_update_subtitle),
3710 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3711 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3713 if (!player->play_subtitle) {
3714 LOGD("add textbin sink as sink element of whole pipeline.");
3715 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3718 /* adding created elements to bin */
3719 LOGD("adding created elements to bin");
3720 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3721 LOGE("failed to add elements");
3725 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3726 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3727 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3729 /* linking elements in the bucket by added order. */
3730 LOGD("Linking elements in the bucket by added order.");
3731 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3732 LOGE("failed to link elements");
3736 /* done. free allocated variables */
3737 g_list_free(element_bucket);
3739 if (textbin[MMPLAYER_T_QUEUE].gst) {
3741 GstPad *ghostpad = NULL;
3743 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3745 LOGE("failed to get sink pad of text queue");
3749 ghostpad = gst_ghost_pad_new("text_sink", pad);
3750 gst_object_unref(pad);
3753 LOGE("failed to create ghostpad of textbin");
3757 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3758 LOGE("failed to add ghostpad to textbin");
3759 gst_object_unref(ghostpad);
3764 return MM_ERROR_NONE;
3767 g_list_free(element_bucket);
3769 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3770 LOGE("remove textbin sink from sink list");
3771 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3774 /* release element at __mmplayer_gst_create_text_sink_bin */
3775 return MM_ERROR_PLAYER_INTERNAL;
3779 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3781 mmplayer_gst_element_t *textbin = NULL;
3782 GList *element_bucket = NULL;
3783 int surface_type = 0;
3788 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3791 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3793 LOGE("failed to allocate memory for textbin");
3794 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3798 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3799 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3800 if (!textbin[MMPLAYER_T_BIN].gst) {
3801 LOGE("failed to create textbin");
3806 player->pipeline->textbin = textbin;
3809 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3810 LOGD("surface type for subtitle : %d", surface_type);
3811 switch (surface_type) {
3812 case MM_DISPLAY_SURFACE_OVERLAY:
3813 case MM_DISPLAY_SURFACE_NULL:
3814 case MM_DISPLAY_SURFACE_REMOTE:
3815 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3816 LOGE("failed to make plain text elements");
3827 return MM_ERROR_NONE;
3831 LOGD("ERROR : releasing textbin");
3833 g_list_free(element_bucket);
3835 /* release signal */
3836 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3838 /* release element which are not added to bin */
3839 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3840 /* NOTE : skip bin */
3841 if (textbin[i].gst) {
3842 GstObject *parent = NULL;
3843 parent = gst_element_get_parent(textbin[i].gst);
3846 gst_object_unref(GST_OBJECT(textbin[i].gst));
3847 textbin[i].gst = NULL;
3849 gst_object_unref(GST_OBJECT(parent));
3854 /* release textbin with it's childs */
3855 if (textbin[MMPLAYER_T_BIN].gst)
3856 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3858 MMPLAYER_FREEIF(player->pipeline->textbin);
3859 player->pipeline->textbin = NULL;
3862 return MM_ERROR_PLAYER_INTERNAL;
3866 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3868 mmplayer_gst_element_t *mainbin = NULL;
3869 mmplayer_gst_element_t *textbin = NULL;
3870 MMHandleType attrs = 0;
3871 GstElement *subsrc = NULL;
3872 GstElement *subparse = NULL;
3873 gchar *subtitle_uri = NULL;
3874 const gchar *charset = NULL;
3880 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3882 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3884 mainbin = player->pipeline->mainbin;
3886 attrs = MMPLAYER_GET_ATTRS(player);
3888 LOGE("cannot get content attribute");
3889 return MM_ERROR_PLAYER_INTERNAL;
3892 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3893 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3894 LOGE("subtitle uri is not proper filepath.");
3895 return MM_ERROR_PLAYER_INVALID_URI;
3898 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3899 LOGE("failed to get storage info of subtitle path");
3900 return MM_ERROR_PLAYER_INVALID_URI;
3903 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3905 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3906 player->subtitle_language_list = NULL;
3907 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3909 /* create the subtitle source */
3910 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3912 LOGE("failed to create filesrc element");
3915 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3917 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3918 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3920 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3921 LOGW("failed to add queue");
3922 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3923 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3924 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3929 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3931 LOGE("failed to create subparse element");
3935 charset = _mmplayer_get_charset(subtitle_uri);
3937 LOGD("detected charset is %s", charset);
3938 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3941 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3942 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3944 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3945 LOGW("failed to add subparse");
3946 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3947 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3948 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3952 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3953 LOGW("failed to link subsrc and subparse");
3957 player->play_subtitle = TRUE;
3958 player->adjust_subtitle_pos = 0;
3960 LOGD("play subtitle using subtitle file");
3962 if (player->pipeline->textbin == NULL) {
3963 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3964 LOGE("failed to create text sink bin. continuing without text");
3968 textbin = player->pipeline->textbin;
3970 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3971 LOGW("failed to add textbin");
3973 /* release signal */
3974 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3976 /* release textbin with it's childs */
3977 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3978 MMPLAYER_FREEIF(player->pipeline->textbin);
3979 player->pipeline->textbin = textbin = NULL;
3983 LOGD("link text input selector and textbin ghost pad");
3985 player->textsink_linked = 1;
3986 player->external_text_idx = 0;
3987 LOGI("textsink is linked");
3989 textbin = player->pipeline->textbin;
3990 LOGD("text bin has been created. reuse it.");
3991 player->external_text_idx = 1;
3994 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3995 LOGW("failed to link subparse and textbin");
3999 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4001 LOGE("failed to get sink pad from textsink to probe data");
4005 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4006 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4008 gst_object_unref(pad);
4011 /* create dot. for debugging */
4012 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4015 return MM_ERROR_NONE;
4018 /* release text pipeline resource */
4019 player->textsink_linked = 0;
4021 /* release signal */
4022 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4024 if (player->pipeline->textbin) {
4025 LOGE("remove textbin");
4027 /* release textbin with it's childs */
4028 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4029 MMPLAYER_FREEIF(player->pipeline->textbin);
4030 player->pipeline->textbin = NULL;
4034 /* release subtitle elem */
4035 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4036 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4038 return MM_ERROR_PLAYER_INTERNAL;
4042 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4044 mmplayer_t *player = (mmplayer_t *)data;
4045 MMMessageParamType msg = {0, };
4046 GstClockTime duration = 0;
4047 gpointer text = NULL;
4048 guint text_size = 0;
4049 gboolean ret = TRUE;
4050 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4054 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4055 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4057 if (player->is_subtitle_force_drop) {
4058 LOGW("subtitle is dropped forcedly.");
4062 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4063 text = mapinfo.data;
4064 text_size = mapinfo.size;
4066 if (player->set_mode.subtitle_off) {
4067 LOGD("subtitle is OFF.");
4071 if (!text || (text_size == 0)) {
4072 LOGD("There is no subtitle to be displayed.");
4076 msg.data = (void *)text;
4078 duration = GST_BUFFER_DURATION(buffer);
4080 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4081 if (player->duration > GST_BUFFER_PTS(buffer))
4082 duration = player->duration - GST_BUFFER_PTS(buffer);
4085 LOGI("subtitle duration is invalid, subtitle duration change "
4086 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4088 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4090 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4092 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4093 gst_buffer_unmap(buffer, &mapinfo);
4100 static GstPadProbeReturn
4101 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4103 mmplayer_t *player = (mmplayer_t *)u_data;
4104 GstClockTime cur_timestamp = 0;
4105 gint64 adjusted_timestamp = 0;
4106 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4108 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4110 if (player->set_mode.subtitle_off) {
4111 LOGD("subtitle is OFF.");
4115 if (player->adjust_subtitle_pos == 0) {
4116 LOGD("nothing to do");
4120 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4121 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4123 if (adjusted_timestamp < 0) {
4124 LOGD("adjusted_timestamp under zero");
4129 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4130 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4131 GST_TIME_ARGS(cur_timestamp),
4132 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4134 return GST_PAD_PROBE_OK;
4138 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4142 /* check player and subtitlebin are created */
4143 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4144 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4146 if (position == 0) {
4147 LOGD("nothing to do");
4149 return MM_ERROR_NONE;
4152 /* check current postion */
4153 player->adjust_subtitle_pos = position;
4155 LOGD("save adjust_subtitle_pos in player");
4159 return MM_ERROR_NONE;
4163 * This function is to create audio or video pipeline for playing.
4165 * @param player [in] handle of player
4167 * @return This function returns zero on success.
4172 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4174 int ret = MM_ERROR_NONE;
4175 mmplayer_gst_element_t *mainbin = NULL;
4176 MMHandleType attrs = 0;
4179 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4181 /* get profile attribute */
4182 attrs = MMPLAYER_GET_ATTRS(player);
4184 LOGE("failed to get content attribute");
4188 /* create pipeline handles */
4189 if (player->pipeline) {
4190 LOGE("pipeline should be released before create new one");
4194 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4195 if (player->pipeline == NULL)
4198 /* create mainbin */
4199 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4200 if (mainbin == NULL)
4203 /* create pipeline */
4204 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4205 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4206 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4207 LOGE("failed to create pipeline");
4212 player->pipeline->mainbin = mainbin;
4214 /* create the source and decoder elements */
4215 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4216 ret = _mmplayer_gst_build_es_pipeline(player);
4218 ret = _mmplayer_gst_build_pipeline(player);
4220 if (ret != MM_ERROR_NONE) {
4221 LOGE("failed to create some elements");
4225 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4226 if (__mmplayer_check_subtitle(player)
4227 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4228 LOGE("failed to create text pipeline");
4231 ret = _mmplayer_gst_add_bus_watch(player);
4232 if (ret != MM_ERROR_NONE) {
4233 LOGE("failed to add bus watch");
4238 return MM_ERROR_NONE;
4241 __mmplayer_gst_destroy_pipeline(player);
4242 return MM_ERROR_PLAYER_INTERNAL;
4246 __mmplayer_reset_gapless_state(mmplayer_t *player)
4249 MMPLAYER_RETURN_IF_FAIL(player
4251 && player->pipeline->audiobin
4252 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4254 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4261 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4264 int ret = MM_ERROR_NONE;
4268 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4270 /* cleanup stuffs */
4271 MMPLAYER_FREEIF(player->type);
4272 player->no_more_pad = FALSE;
4273 player->num_dynamic_pad = 0;
4274 player->demux_pad_index = 0;
4276 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4277 player->subtitle_language_list = NULL;
4278 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4280 __mmplayer_reset_gapless_state(player);
4282 if (player->streamer) {
4283 _mm_player_streaming_initialize(player->streamer, FALSE);
4284 _mm_player_streaming_destroy(player->streamer);
4285 player->streamer = NULL;
4288 /* cleanup unlinked mime type */
4289 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4290 MMPLAYER_FREEIF(player->unlinked_video_mime);
4291 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4293 /* cleanup running stuffs */
4294 _mmplayer_cancel_eos_timer(player);
4296 /* cleanup gst stuffs */
4297 if (player->pipeline) {
4298 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4299 GstTagList *tag_list = player->pipeline->tag_list;
4301 /* first we need to disconnect all signal hander */
4302 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4305 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4306 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4307 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4308 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4309 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4310 gst_object_unref(bus);
4312 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4313 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4314 if (ret != MM_ERROR_NONE) {
4315 LOGE("fail to change state to NULL");
4316 return MM_ERROR_PLAYER_INTERNAL;
4319 LOGW("succeeded in changing state to NULL");
4321 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4324 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4325 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4327 /* free avsysaudiosink
4328 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4329 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4331 MMPLAYER_FREEIF(audiobin);
4332 MMPLAYER_FREEIF(videobin);
4333 MMPLAYER_FREEIF(textbin);
4334 MMPLAYER_FREEIF(mainbin);
4338 gst_tag_list_unref(tag_list);
4340 MMPLAYER_FREEIF(player->pipeline);
4342 MMPLAYER_FREEIF(player->album_art);
4344 if (player->v_stream_caps) {
4345 gst_caps_unref(player->v_stream_caps);
4346 player->v_stream_caps = NULL;
4349 if (player->a_stream_caps) {
4350 gst_caps_unref(player->a_stream_caps);
4351 player->a_stream_caps = NULL;
4354 if (player->s_stream_caps) {
4355 gst_caps_unref(player->s_stream_caps);
4356 player->s_stream_caps = NULL;
4358 _mmplayer_track_destroy(player);
4360 if (player->sink_elements)
4361 g_list_free(player->sink_elements);
4362 player->sink_elements = NULL;
4364 if (player->bufmgr) {
4365 tbm_bufmgr_deinit(player->bufmgr);
4366 player->bufmgr = NULL;
4369 LOGW("finished destroy pipeline");
4377 __mmplayer_gst_realize(mmplayer_t *player)
4380 int ret = MM_ERROR_NONE;
4384 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4386 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4388 ret = __mmplayer_gst_create_pipeline(player);
4390 LOGE("failed to create pipeline");
4394 /* set pipeline state to READY */
4395 /* NOTE : state change to READY must be performed sync. */
4396 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4397 ret = _mmplayer_gst_set_state(player,
4398 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4400 if (ret != MM_ERROR_NONE) {
4401 /* return error if failed to set state */
4402 LOGE("failed to set READY state");
4406 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4408 /* create dot before error-return. for debugging */
4409 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4417 __mmplayer_gst_unrealize(mmplayer_t *player)
4419 int ret = MM_ERROR_NONE;
4423 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4425 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4426 MMPLAYER_PRINT_STATE(player);
4428 /* release miscellaneous information */
4429 __mmplayer_release_misc(player);
4431 /* destroy pipeline */
4432 ret = __mmplayer_gst_destroy_pipeline(player);
4433 if (ret != MM_ERROR_NONE) {
4434 LOGE("failed to destory pipeline");
4438 /* release miscellaneous information.
4439 these info needs to be released after pipeline is destroyed. */
4440 __mmplayer_release_misc_post(player);
4442 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4450 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4455 LOGW("set_message_callback is called with invalid player handle");
4456 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4459 player->msg_cb = callback;
4460 player->msg_cb_param = user_param;
4462 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4466 return MM_ERROR_NONE;
4470 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4472 int ret = MM_ERROR_NONE;
4477 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4478 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4479 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4481 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4483 if (strstr(uri, "es_buff://")) {
4484 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4485 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4486 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4487 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4489 tmp = g_ascii_strdown(uri, strlen(uri));
4490 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4491 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4493 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4495 } else if (strstr(uri, "mms://")) {
4496 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4497 } else if ((path = strstr(uri, "mem://"))) {
4498 ret = __mmplayer_set_mem_uri(data, path, param);
4500 ret = __mmplayer_set_file_uri(data, uri);
4503 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4504 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4505 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4506 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4508 /* dump parse result */
4509 SECURE_LOGW("incoming uri : %s", uri);
4510 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4511 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4519 __mmplayer_can_do_interrupt(mmplayer_t *player)
4521 if (!player || !player->pipeline || !player->attrs) {
4522 LOGW("not initialized");
4526 if (player->audio_decoded_cb) {
4527 LOGW("not support in pcm extraction mode");
4531 /* check if seeking */
4532 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4533 MMMessageParamType msg_param;
4534 memset(&msg_param, 0, sizeof(MMMessageParamType));
4535 msg_param.code = MM_ERROR_PLAYER_SEEK;
4536 player->seek_state = MMPLAYER_SEEK_NONE;
4537 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4541 /* check other thread */
4542 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4543 LOGW("locked already, cmd state : %d", player->cmd);
4545 /* check application command */
4546 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4547 LOGW("playing.. should wait cmd lock then, will be interrupted");
4549 /* lock will be released at mrp_resource_release_cb() */
4550 MMPLAYER_CMD_LOCK(player);
4553 LOGW("nothing to do");
4556 LOGW("can interrupt immediately");
4560 FAILED: /* with CMD UNLOCKED */
4563 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4568 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4571 mmplayer_t *player = NULL;
4572 MMMessageParamType msg = {0, };
4574 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4579 LOGE("user_data is null");
4582 player = (mmplayer_t *)user_data;
4584 if (!__mmplayer_can_do_interrupt(player)) {
4585 LOGW("no need to interrupt, so leave");
4586 /* FIXME: there is no way to avoid releasing resource. */
4590 player->interrupted_by_resource = TRUE;
4592 /* get last play position */
4593 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4594 msg.union_type = MM_MSG_UNION_TIME;
4595 msg.time.elapsed = pos;
4596 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4598 LOGW("failed to get play position.");
4601 LOGD("video resource conflict so, resource will be freed by unrealizing");
4602 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4603 LOGE("failed to unrealize");
4605 /* lock is called in __mmplayer_can_do_interrupt() */
4606 MMPLAYER_CMD_UNLOCK(player);
4608 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4609 player->hw_resource[res_idx] = NULL;
4613 return TRUE; /* release all the resources */
4617 __mmplayer_initialize_video_roi(mmplayer_t *player)
4619 player->video_roi.scale_x = 0.0;
4620 player->video_roi.scale_y = 0.0;
4621 player->video_roi.scale_width = 1.0;
4622 player->video_roi.scale_height = 1.0;
4626 _mmplayer_create_player(MMHandleType handle)
4628 int ret = MM_ERROR_PLAYER_INTERNAL;
4629 bool enabled = false;
4631 mmplayer_t *player = MM_PLAYER_CAST(handle);
4635 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4637 /* initialize player state */
4638 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4639 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4640 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4641 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4643 /* check current state */
4644 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4646 /* construct attributes */
4647 player->attrs = _mmplayer_construct_attribute(handle);
4649 if (!player->attrs) {
4650 LOGE("Failed to construct attributes");
4654 /* initialize gstreamer with configured parameter */
4655 if (!__mmplayer_init_gstreamer(player)) {
4656 LOGE("Initializing gstreamer failed");
4657 _mmplayer_deconstruct_attribute(handle);
4661 /* create lock. note that g_tread_init() has already called in gst_init() */
4662 g_mutex_init(&player->fsink_lock);
4664 /* create update tag lock */
4665 g_mutex_init(&player->update_tag_lock);
4667 /* create gapless play mutex */
4668 g_mutex_init(&player->gapless_play_thread_mutex);
4670 /* create gapless play cond */
4671 g_cond_init(&player->gapless_play_thread_cond);
4673 /* create gapless play thread */
4674 player->gapless_play_thread =
4675 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4676 if (!player->gapless_play_thread) {
4677 LOGE("failed to create gapless play thread");
4678 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4679 g_mutex_clear(&player->gapless_play_thread_mutex);
4680 g_cond_clear(&player->gapless_play_thread_cond);
4684 player->bus_msg_q = g_queue_new();
4685 if (!player->bus_msg_q) {
4686 LOGE("failed to create queue for bus_msg");
4687 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4691 ret = _mmplayer_initialize_video_capture(player);
4692 if (ret != MM_ERROR_NONE) {
4693 LOGE("failed to initialize video capture");
4697 /* initialize resource manager */
4698 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4699 __resource_release_cb, player, &player->resource_manager)
4700 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4701 LOGE("failed to initialize resource manager");
4702 ret = MM_ERROR_PLAYER_INTERNAL;
4706 /* create video bo lock and cond */
4707 g_mutex_init(&player->video_bo_mutex);
4708 g_cond_init(&player->video_bo_cond);
4710 /* create subtitle info lock and cond */
4711 g_mutex_init(&player->subtitle_info_mutex);
4712 g_cond_init(&player->subtitle_info_cond);
4714 player->streaming_type = STREAMING_SERVICE_NONE;
4716 /* give default value of audio effect setting */
4717 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4718 player->sound.rg_enable = false;
4719 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4721 player->play_subtitle = FALSE;
4722 player->has_closed_caption = FALSE;
4723 player->pending_resume = FALSE;
4724 if (player->ini.dump_element_keyword[0][0] == '\0')
4725 player->ini.set_dump_element_flag = FALSE;
4727 player->ini.set_dump_element_flag = TRUE;
4729 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4730 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4731 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4733 /* Set video360 settings to their defaults for just-created player.
4736 player->is_360_feature_enabled = FALSE;
4737 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4738 LOGI("spherical feature info: %d", enabled);
4740 player->is_360_feature_enabled = TRUE;
4742 LOGE("failed to get spherical feature info");
4745 player->is_content_spherical = FALSE;
4746 player->is_video360_enabled = TRUE;
4747 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4748 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4749 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4750 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4751 player->video360_zoom = 1.0f;
4752 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4753 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4755 __mmplayer_initialize_video_roi(player);
4757 /* set player state to null */
4758 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4759 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4763 return MM_ERROR_NONE;
4767 g_mutex_clear(&player->fsink_lock);
4768 /* free update tag lock */
4769 g_mutex_clear(&player->update_tag_lock);
4770 g_queue_free(player->bus_msg_q);
4771 player->bus_msg_q = NULL;
4772 /* free gapless play thread */
4773 if (player->gapless_play_thread) {
4774 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4775 player->gapless_play_thread_exit = TRUE;
4776 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4777 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4779 g_thread_join(player->gapless_play_thread);
4780 player->gapless_play_thread = NULL;
4782 g_mutex_clear(&player->gapless_play_thread_mutex);
4783 g_cond_clear(&player->gapless_play_thread_cond);
4786 /* release attributes */
4787 _mmplayer_deconstruct_attribute(handle);
4795 __mmplayer_init_gstreamer(mmplayer_t *player)
4797 static gboolean initialized = FALSE;
4798 static const int max_argc = 50;
4800 gchar **argv = NULL;
4801 gchar **argv2 = NULL;
4807 LOGD("gstreamer already initialized.");
4812 argc = malloc(sizeof(int));
4813 argv = malloc(sizeof(gchar *) * max_argc);
4814 argv2 = malloc(sizeof(gchar *) * max_argc);
4816 if (!argc || !argv || !argv2)
4819 memset(argv, 0, sizeof(gchar *) * max_argc);
4820 memset(argv2, 0, sizeof(gchar *) * max_argc);
4824 argv[0] = g_strdup("mmplayer");
4827 for (i = 0; i < 5; i++) {
4828 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4829 if (strlen(player->ini.gst_param[i]) > 0) {
4830 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4835 /* we would not do fork for scanning plugins */
4836 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4839 /* check disable registry scan */
4840 if (player->ini.skip_rescan) {
4841 argv[*argc] = g_strdup("--gst-disable-registry-update");
4845 /* check disable segtrap */
4846 if (player->ini.disable_segtrap) {
4847 argv[*argc] = g_strdup("--gst-disable-segtrap");
4851 LOGD("initializing gstreamer with following parameter");
4852 LOGD("argc : %d", *argc);
4855 for (i = 0; i < arg_count; i++) {
4857 LOGD("argv[%d] : %s", i, argv2[i]);
4860 /* initializing gstreamer */
4861 if (!gst_init_check(argc, &argv, &err)) {
4862 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4869 for (i = 0; i < arg_count; i++) {
4870 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4871 MMPLAYER_FREEIF(argv2[i]);
4874 MMPLAYER_FREEIF(argv);
4875 MMPLAYER_FREEIF(argv2);
4876 MMPLAYER_FREEIF(argc);
4886 for (i = 0; i < arg_count; i++) {
4887 LOGD("free[%d] : %s", i, argv2[i]);
4888 MMPLAYER_FREEIF(argv2[i]);
4891 MMPLAYER_FREEIF(argv);
4892 MMPLAYER_FREEIF(argv2);
4893 MMPLAYER_FREEIF(argc);
4899 __mmplayer_check_async_state_transition(mmplayer_t *player)
4901 GstState element_state = GST_STATE_VOID_PENDING;
4902 GstState element_pending_state = GST_STATE_VOID_PENDING;
4903 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4904 GstElement *element = NULL;
4905 gboolean async = FALSE;
4907 /* check player handle */
4908 MMPLAYER_RETURN_IF_FAIL(player &&
4910 player->pipeline->mainbin &&
4911 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4914 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4916 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4917 LOGD("don't need to check the pipeline state");
4921 MMPLAYER_PRINT_STATE(player);
4923 /* wait for state transition */
4924 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4925 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4927 if (ret == GST_STATE_CHANGE_FAILURE) {
4928 LOGE(" [%s] state : %s pending : %s",
4929 GST_ELEMENT_NAME(element),
4930 gst_element_state_get_name(element_state),
4931 gst_element_state_get_name(element_pending_state));
4933 /* dump state of all element */
4934 _mmplayer_dump_pipeline_state(player);
4939 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4944 _mmplayer_destroy(MMHandleType handle)
4946 mmplayer_t *player = MM_PLAYER_CAST(handle);
4950 /* check player handle */
4951 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4953 /* destroy can called at anytime */
4954 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4956 /* check async state transition */
4957 __mmplayer_check_async_state_transition(player);
4959 /* release gapless play thread */
4960 if (player->gapless_play_thread) {
4961 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4962 player->gapless_play_thread_exit = TRUE;
4963 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4964 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4966 LOGD("waitting for gapless play thread exit");
4967 g_thread_join(player->gapless_play_thread);
4968 g_mutex_clear(&player->gapless_play_thread_mutex);
4969 g_cond_clear(&player->gapless_play_thread_cond);
4970 LOGD("gapless play thread released");
4973 _mmplayer_release_video_capture(player);
4975 /* de-initialize resource manager */
4976 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4977 player->resource_manager))
4978 LOGE("failed to deinitialize resource manager");
4980 /* release pipeline */
4981 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4982 LOGE("failed to destory pipeline");
4983 return MM_ERROR_PLAYER_INTERNAL;
4986 g_queue_free(player->bus_msg_q);
4988 /* release subtitle info lock and cond */
4989 g_mutex_clear(&player->subtitle_info_mutex);
4990 g_cond_clear(&player->subtitle_info_cond);
4992 __mmplayer_release_dump_list(player->dump_list);
4994 /* release miscellaneous information */
4995 __mmplayer_release_misc(player);
4997 /* release miscellaneous information.
4998 these info needs to be released after pipeline is destroyed. */
4999 __mmplayer_release_misc_post(player);
5001 /* release attributes */
5002 _mmplayer_deconstruct_attribute(handle);
5005 g_mutex_clear(&player->fsink_lock);
5008 g_mutex_clear(&player->update_tag_lock);
5010 /* release video bo lock and cond */
5011 g_mutex_clear(&player->video_bo_mutex);
5012 g_cond_clear(&player->video_bo_cond);
5016 return MM_ERROR_NONE;
5020 _mmplayer_realize(MMHandleType hplayer)
5022 mmplayer_t *player = (mmplayer_t *)hplayer;
5025 MMHandleType attrs = 0;
5026 int ret = MM_ERROR_NONE;
5030 /* check player handle */
5031 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5033 /* check current state */
5034 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5036 attrs = MMPLAYER_GET_ATTRS(player);
5038 LOGE("fail to get attributes.");
5039 return MM_ERROR_PLAYER_INTERNAL;
5041 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5042 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5044 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5045 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5047 if (ret != MM_ERROR_NONE) {
5048 LOGE("failed to parse profile");
5053 if (uri && (strstr(uri, "es_buff://"))) {
5054 if (strstr(uri, "es_buff://push_mode"))
5055 player->es_player_push_mode = TRUE;
5057 player->es_player_push_mode = FALSE;
5060 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5061 LOGW("mms protocol is not supported format.");
5062 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5065 if (MMPLAYER_IS_STREAMING(player))
5066 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5068 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5070 player->smooth_streaming = FALSE;
5071 player->videodec_linked = 0;
5072 player->audiodec_linked = 0;
5073 player->textsink_linked = 0;
5074 player->is_external_subtitle_present = FALSE;
5075 player->is_external_subtitle_added_now = FALSE;
5076 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5077 player->video360_metadata.is_spherical = -1;
5078 player->is_openal_plugin_used = FALSE;
5079 player->demux_pad_index = 0;
5080 player->subtitle_language_list = NULL;
5081 player->is_subtitle_force_drop = FALSE;
5083 _mmplayer_track_initialize(player);
5084 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5086 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5087 gint prebuffer_ms = 0, rebuffer_ms = 0;
5089 player->streamer = _mm_player_streaming_create();
5090 _mm_player_streaming_initialize(player->streamer, TRUE);
5092 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5093 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5095 if (prebuffer_ms > 0) {
5096 prebuffer_ms = MAX(prebuffer_ms, 1000);
5097 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5100 if (rebuffer_ms > 0) {
5101 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5102 rebuffer_ms = MAX(rebuffer_ms, 1000);
5103 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5106 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5107 player->streamer->buffering_req.rebuffer_time);
5110 /* realize pipeline */
5111 ret = __mmplayer_gst_realize(player);
5112 if (ret != MM_ERROR_NONE)
5113 LOGE("fail to realize the player.");
5115 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5123 _mmplayer_unrealize(MMHandleType hplayer)
5125 mmplayer_t *player = (mmplayer_t *)hplayer;
5126 int ret = MM_ERROR_NONE;
5130 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5132 MMPLAYER_CMD_UNLOCK(player);
5133 /* destroy the gst bus msg thread which is created during realize.
5134 this funct have to be called before getting cmd lock. */
5135 _mmplayer_bus_msg_thread_destroy(player);
5136 MMPLAYER_CMD_LOCK(player);
5138 /* check current state */
5139 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5141 /* check async state transition */
5142 __mmplayer_check_async_state_transition(player);
5144 /* unrealize pipeline */
5145 ret = __mmplayer_gst_unrealize(player);
5147 if (!player->interrupted_by_resource) {
5148 if ((__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) ||
5149 (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE))
5150 LOGE("failed to release video resources");
5158 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5160 mmplayer_t *player = (mmplayer_t *)hplayer;
5162 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5164 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5168 _mmplayer_get_state(MMHandleType hplayer, int *state)
5170 mmplayer_t *player = (mmplayer_t *)hplayer;
5172 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5174 *state = MMPLAYER_CURRENT_STATE(player);
5176 return MM_ERROR_NONE;
5180 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5182 GstElement *vol_element = NULL;
5183 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5186 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5187 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5189 /* check pipeline handle */
5190 if (!player->pipeline || !player->pipeline->audiobin) {
5191 LOGD("'%s' will be applied when audiobin is created", prop_name);
5193 /* NOTE : stored value will be used in create_audiobin
5194 * returning MM_ERROR_NONE here makes application to able to
5195 * set audio volume or mute at anytime.
5197 return MM_ERROR_NONE;
5200 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5201 volume_elem_id = MMPLAYER_A_SINK;
5203 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5205 LOGE("failed to get vol element %d", volume_elem_id);
5206 return MM_ERROR_PLAYER_INTERNAL;
5209 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5211 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5212 LOGE("there is no '%s' property", prop_name);
5213 return MM_ERROR_PLAYER_INTERNAL;
5216 if (!strcmp(prop_name, "volume")) {
5217 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5218 } else if (!strcmp(prop_name, "mute")) {
5219 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5221 LOGE("invalid property %s", prop_name);
5222 return MM_ERROR_PLAYER_INTERNAL;
5225 return MM_ERROR_NONE;
5229 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5231 int ret = MM_ERROR_NONE;
5232 mmplayer_t *player = (mmplayer_t *)hplayer;
5235 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5237 LOGD("volume = %f", volume);
5239 /* invalid factor range or not */
5240 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5241 LOGE("Invalid volume value");
5242 return MM_ERROR_INVALID_ARGUMENT;
5245 player->sound.volume = volume;
5247 ret = __mmplayer_gst_set_volume_property(player, "volume");
5254 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5256 mmplayer_t *player = (mmplayer_t *)hplayer;
5260 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5261 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5263 *volume = player->sound.volume;
5265 LOGD("current vol = %f", *volume);
5268 return MM_ERROR_NONE;
5272 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5274 int ret = MM_ERROR_NONE;
5275 mmplayer_t *player = (mmplayer_t *)hplayer;
5278 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5280 LOGD("mute = %d", mute);
5282 player->sound.mute = mute;
5284 ret = __mmplayer_gst_set_volume_property(player, "mute");
5291 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5293 mmplayer_t *player = (mmplayer_t *)hplayer;
5297 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5298 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5300 *mute = player->sound.mute;
5302 LOGD("current mute = %d", *mute);
5306 return MM_ERROR_NONE;
5310 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5312 mmplayer_t *player = (mmplayer_t *)hplayer;
5316 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5318 player->audio_stream_changed_cb = callback;
5319 player->audio_stream_changed_cb_user_param = user_param;
5320 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5324 return MM_ERROR_NONE;
5328 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5330 mmplayer_t *player = (mmplayer_t *)hplayer;
5334 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5336 player->audio_decoded_cb = callback;
5337 player->audio_decoded_cb_user_param = user_param;
5338 player->audio_extract_opt = opt;
5339 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5343 return MM_ERROR_NONE;
5347 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5349 mmplayer_t *player = (mmplayer_t *)hplayer;
5353 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5355 if (callback && !player->bufmgr)
5356 player->bufmgr = tbm_bufmgr_init(-1);
5358 player->set_mode.video_export = (callback) ? true : false;
5359 player->video_decoded_cb = callback;
5360 player->video_decoded_cb_user_param = user_param;
5362 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5366 return MM_ERROR_NONE;
5370 _mmplayer_start(MMHandleType hplayer)
5372 mmplayer_t *player = (mmplayer_t *)hplayer;
5373 gint ret = MM_ERROR_NONE;
5377 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5379 /* check current state */
5380 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5382 /* start pipeline */
5383 ret = _mmplayer_gst_start(player);
5384 if (ret != MM_ERROR_NONE)
5385 LOGE("failed to start player.");
5387 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5388 LOGD("force playing start even during buffering");
5389 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5397 /* NOTE: post "not supported codec message" to application
5398 * when one codec is not found during AUTOPLUGGING in MSL.
5399 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5400 * And, if any codec is not found, don't send message here.
5401 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5404 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5406 MMMessageParamType msg_param;
5407 memset(&msg_param, 0, sizeof(MMMessageParamType));
5408 gboolean post_msg_direct = FALSE;
5412 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5414 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5415 player->not_supported_codec, player->can_support_codec);
5417 if (player->not_found_demuxer) {
5418 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5419 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5421 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5422 MMPLAYER_FREEIF(msg_param.data);
5424 return MM_ERROR_NONE;
5427 if (player->not_supported_codec) {
5428 if (player->can_support_codec) {
5429 // There is one codec to play
5430 post_msg_direct = TRUE;
5432 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5433 post_msg_direct = TRUE;
5436 if (post_msg_direct) {
5437 MMMessageParamType msg_param;
5438 memset(&msg_param, 0, sizeof(MMMessageParamType));
5440 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5441 LOGW("not found AUDIO codec, posting error code to application.");
5443 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5444 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5445 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5446 LOGW("not found VIDEO codec, posting error code to application.");
5448 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5449 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5452 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5454 MMPLAYER_FREEIF(msg_param.data);
5456 return MM_ERROR_NONE;
5458 // no any supported codec case
5459 LOGW("not found any codec, posting error code to application.");
5461 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5462 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5463 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5465 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5466 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5469 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5471 MMPLAYER_FREEIF(msg_param.data);
5477 return MM_ERROR_NONE;
5481 __mmplayer_check_pipeline(mmplayer_t *player)
5483 GstState element_state = GST_STATE_VOID_PENDING;
5484 GstState element_pending_state = GST_STATE_VOID_PENDING;
5486 int ret = MM_ERROR_NONE;
5488 if (!player->gapless.reconfigure)
5491 LOGW("pipeline is under construction.");
5493 MMPLAYER_PLAYBACK_LOCK(player);
5494 MMPLAYER_PLAYBACK_UNLOCK(player);
5496 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5498 /* wait for state transition */
5499 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5500 if (ret == GST_STATE_CHANGE_FAILURE)
5501 LOGE("failed to change pipeline state within %d sec", timeout);
5504 /* NOTE : it should be able to call 'stop' anytime*/
5506 _mmplayer_stop(MMHandleType hplayer)
5508 mmplayer_t *player = (mmplayer_t *)hplayer;
5509 int ret = MM_ERROR_NONE;
5513 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5515 /* check current state */
5516 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5518 /* check pipline building state */
5519 __mmplayer_check_pipeline(player);
5520 __mmplayer_reset_gapless_state(player);
5522 /* NOTE : application should not wait for EOS after calling STOP */
5523 _mmplayer_cancel_eos_timer(player);
5526 player->seek_state = MMPLAYER_SEEK_NONE;
5529 ret = _mmplayer_gst_stop(player);
5531 if (ret != MM_ERROR_NONE)
5532 LOGE("failed to stop player.");
5540 _mmplayer_pause(MMHandleType hplayer)
5542 mmplayer_t *player = (mmplayer_t *)hplayer;
5543 gint64 pos_nsec = 0;
5544 gboolean async = FALSE;
5545 gint ret = MM_ERROR_NONE;
5549 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5551 /* check current state */
5552 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5554 /* check pipline building state */
5555 __mmplayer_check_pipeline(player);
5557 switch (MMPLAYER_CURRENT_STATE(player)) {
5558 case MM_PLAYER_STATE_READY:
5560 /* check prepare async or not.
5561 * In the case of streaming playback, it's recommned to avoid blocking wait.
5563 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5564 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5566 /* Changing back sync of rtspsrc to async */
5567 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5568 LOGD("async prepare working mode for rtsp");
5574 case MM_PLAYER_STATE_PLAYING:
5576 /* NOTE : store current point to overcome some bad operation
5577 *(returning zero when getting current position in paused state) of some
5580 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5581 LOGW("getting current position failed in paused");
5583 player->last_position = pos_nsec;
5585 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5586 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5587 This causes problem is position calculation during normal pause resume scenarios also.
5588 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5589 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5590 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5591 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5597 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5598 LOGD("doing async pause in case of ms buff src");
5602 /* pause pipeline */
5603 ret = _mmplayer_gst_pause(player, async);
5605 if (ret != MM_ERROR_NONE)
5606 LOGE("failed to pause player. ret : 0x%x", ret);
5608 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5609 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5610 LOGE("failed to update display_rotation");
5618 /* in case of streaming, pause could take long time.*/
5620 _mmplayer_abort_pause(MMHandleType hplayer)
5622 mmplayer_t *player = (mmplayer_t *)hplayer;
5623 int ret = MM_ERROR_NONE;
5627 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5629 player->pipeline->mainbin,
5630 MM_ERROR_PLAYER_NOT_INITIALIZED);
5632 LOGD("set the pipeline state to READY");
5634 /* set state to READY */
5635 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5636 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5637 if (ret != MM_ERROR_NONE) {
5638 LOGE("fail to change state to READY");
5639 return MM_ERROR_PLAYER_INTERNAL;
5642 LOGD("succeeded in changing state to READY");
5647 _mmplayer_resume(MMHandleType hplayer)
5649 mmplayer_t *player = (mmplayer_t *)hplayer;
5650 int ret = MM_ERROR_NONE;
5651 gboolean async = FALSE;
5655 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5657 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5658 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5659 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5663 /* Changing back sync mode rtspsrc to async */
5664 LOGD("async resume for rtsp case");
5668 /* check current state */
5669 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5671 ret = _mmplayer_gst_resume(player, async);
5672 if (ret != MM_ERROR_NONE)
5673 LOGE("failed to resume player.");
5675 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5676 LOGD("force resume even during buffering");
5677 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5686 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5688 mmplayer_t *player = (mmplayer_t *)hplayer;
5689 gint64 pos_nsec = 0;
5690 int ret = MM_ERROR_NONE;
5692 signed long long start = 0, stop = 0;
5693 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5696 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5697 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5699 /* The sound of video is not supported under 0.0 and over 2.0. */
5700 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5701 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5704 _mmplayer_set_mute(hplayer, mute);
5706 if (player->playback_rate == rate)
5707 return MM_ERROR_NONE;
5709 /* If the position is reached at start potion during fast backward, EOS is posted.
5710 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5712 player->playback_rate = rate;
5714 current_state = MMPLAYER_CURRENT_STATE(player);
5716 if (current_state != MM_PLAYER_STATE_PAUSED)
5717 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5719 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5721 if ((current_state == MM_PLAYER_STATE_PAUSED)
5722 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5723 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5724 pos_nsec = player->last_position;
5729 stop = GST_CLOCK_TIME_NONE;
5731 start = GST_CLOCK_TIME_NONE;
5735 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5736 player->playback_rate,
5738 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5739 GST_SEEK_TYPE_SET, start,
5740 GST_SEEK_TYPE_SET, stop)) {
5741 LOGE("failed to set speed playback");
5742 return MM_ERROR_PLAYER_SEEK;
5745 LOGD("succeeded to set speed playback as %0.1f", rate);
5749 return MM_ERROR_NONE;;
5753 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5755 mmplayer_t *player = (mmplayer_t *)hplayer;
5756 int ret = MM_ERROR_NONE;
5760 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5762 /* check pipline building state */
5763 __mmplayer_check_pipeline(player);
5765 ret = _mmplayer_gst_set_position(player, position, FALSE);
5773 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5775 mmplayer_t *player = (mmplayer_t *)hplayer;
5776 int ret = MM_ERROR_NONE;
5778 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5779 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5781 if (g_strrstr(player->type, "video/mpegts"))
5782 __mmplayer_update_duration_value(player);
5784 *duration = player->duration;
5789 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5791 mmplayer_t *player = (mmplayer_t *)hplayer;
5792 int ret = MM_ERROR_NONE;
5794 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5796 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5802 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5804 mmplayer_t *player = (mmplayer_t *)hplayer;
5805 int ret = MM_ERROR_NONE;
5809 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5811 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5819 __mmplayer_is_midi_type(gchar *str_caps)
5821 if ((g_strrstr(str_caps, "audio/midi")) ||
5822 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5823 (g_strrstr(str_caps, "application/x-smaf")) ||
5824 (g_strrstr(str_caps, "audio/x-imelody")) ||
5825 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5826 (g_strrstr(str_caps, "audio/xmf")) ||
5827 (g_strrstr(str_caps, "audio/mxmf"))) {
5836 __mmplayer_is_only_mp3_type(gchar *str_caps)
5838 if (g_strrstr(str_caps, "application/x-id3") ||
5839 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5845 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5847 GstStructure *caps_structure = NULL;
5848 gint samplerate = 0;
5852 MMPLAYER_RETURN_IF_FAIL(player && caps);
5854 caps_structure = gst_caps_get_structure(caps, 0);
5856 /* set stream information */
5857 gst_structure_get_int(caps_structure, "rate", &samplerate);
5858 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5860 gst_structure_get_int(caps_structure, "channels", &channels);
5861 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5863 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5867 __mmplayer_update_content_type_info(mmplayer_t *player)
5870 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5872 if (__mmplayer_is_midi_type(player->type)) {
5873 player->bypass_audio_effect = TRUE;
5877 if (!player->streamer) {
5878 LOGD("no need to check streaming type");
5882 if (g_strrstr(player->type, "application/x-hls")) {
5883 /* If it can't know exact type when it parses uri because of redirection case,
5884 * it will be fixed by typefinder or when doing autoplugging.
5886 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5887 player->streamer->is_adaptive_streaming = TRUE;
5888 } else if (g_strrstr(player->type, "application/dash+xml")) {
5889 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5890 player->streamer->is_adaptive_streaming = TRUE;
5893 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5894 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5895 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5897 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5898 if (player->streamer->is_adaptive_streaming)
5899 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5901 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5905 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5910 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5911 GstCaps *caps, gpointer data)
5913 mmplayer_t *player = (mmplayer_t *)data;
5918 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5920 /* store type string */
5921 MMPLAYER_FREEIF(player->type);
5922 player->type = gst_caps_to_string(caps);
5924 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5925 player, player->type, probability, gst_caps_get_size(caps));
5927 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5928 (g_strrstr(player->type, "audio/x-raw-int"))) {
5929 LOGE("not support media format");
5931 if (player->msg_posted == FALSE) {
5932 MMMessageParamType msg_param;
5933 memset(&msg_param, 0, sizeof(MMMessageParamType));
5935 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5936 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5938 /* don't post more if one was sent already */
5939 player->msg_posted = TRUE;
5944 __mmplayer_update_content_type_info(player);
5946 pad = gst_element_get_static_pad(tf, "src");
5948 LOGE("fail to get typefind src pad.");
5952 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5953 gboolean async = FALSE;
5954 LOGE("failed to autoplug %s", player->type);
5956 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5958 if (async && player->msg_posted == FALSE)
5959 __mmplayer_handle_missed_plugin(player);
5963 gst_object_unref(GST_OBJECT(pad));
5971 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5973 GstElement *decodebin = NULL;
5977 /* create decodebin */
5978 decodebin = gst_element_factory_make("decodebin", NULL);
5981 LOGE("fail to create decodebin");
5985 /* raw pad handling signal */
5986 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5987 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5989 /* no-more-pad pad handling signal */
5990 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5991 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5993 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5994 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5996 /* This signal is emitted when a pad for which there is no further possible
5997 decoding is added to the decodebin.*/
5998 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5999 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6001 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6002 before looking for any elements that can handle that stream.*/
6003 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6004 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6006 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6007 before looking for any elements that can handle that stream.*/
6008 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6009 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6011 /* This signal is emitted once decodebin has finished decoding all the data.*/
6012 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6013 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6015 /* This signal is emitted when a element is added to the bin.*/
6016 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6017 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6024 __mmplayer_gst_make_queue2(mmplayer_t *player)
6026 GstElement *queue2 = NULL;
6027 gint64 dur_bytes = 0L;
6028 mmplayer_gst_element_t *mainbin = NULL;
6029 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6032 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6034 mainbin = player->pipeline->mainbin;
6036 queue2 = gst_element_factory_make("queue2", "queue2");
6038 LOGE("failed to create buffering queue element");
6042 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6043 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6045 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6047 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6048 * skip the pull mode(file or ring buffering) setting. */
6049 if (dur_bytes > 0) {
6050 if (!g_strrstr(player->type, "video/mpegts")) {
6051 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6052 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6058 _mm_player_streaming_set_queue2(player->streamer,
6062 (guint64)dur_bytes); /* no meaning at the moment */
6068 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6070 mmplayer_gst_element_t *mainbin = NULL;
6071 GstElement *decodebin = NULL;
6072 GstElement *queue2 = NULL;
6073 GstPad *sinkpad = NULL;
6074 GstPad *qsrcpad = NULL;
6077 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6079 mainbin = player->pipeline->mainbin;
6081 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6083 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6084 LOGW("need to check: muxed buffer is not null");
6087 queue2 = __mmplayer_gst_make_queue2(player);
6089 LOGE("failed to make queue2");
6093 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6094 LOGE("failed to add buffering queue");
6098 sinkpad = gst_element_get_static_pad(queue2, "sink");
6099 qsrcpad = gst_element_get_static_pad(queue2, "src");
6101 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6102 LOGE("failed to link [%s:%s]-[%s:%s]",
6103 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6107 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6108 LOGE("failed to sync queue2 state with parent");
6112 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6113 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6117 gst_object_unref(GST_OBJECT(sinkpad));
6121 /* create decodebin */
6122 decodebin = _mmplayer_gst_make_decodebin(player);
6124 LOGE("failed to make decodebin");
6128 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6129 LOGE("failed to add decodebin");
6133 /* to force caps on the decodebin element and avoid reparsing stuff by
6134 * typefind. It also avoids a deadlock in the way typefind activates pads in
6135 * the state change */
6136 g_object_set(decodebin, "sink-caps", caps, NULL);
6138 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6140 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6141 LOGE("failed to link [%s:%s]-[%s:%s]",
6142 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6146 gst_object_unref(GST_OBJECT(sinkpad));
6148 gst_object_unref(GST_OBJECT(qsrcpad));
6151 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6152 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6154 /* set decodebin property about buffer in streaming playback. *
6155 * in case of HLS/DASH, it does not need to have big buffer *
6156 * because it is kind of adaptive streaming. */
6157 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6158 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6159 gint high_percent = 0;
6161 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6162 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6164 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6166 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6168 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6169 "high-percent", high_percent,
6170 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6171 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6172 "max-size-buffers", 0, NULL); // disable or automatic
6175 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6176 LOGE("failed to sync decodebin state with parent");
6187 gst_object_unref(GST_OBJECT(sinkpad));
6190 gst_object_unref(GST_OBJECT(qsrcpad));
6193 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6194 * You need to explicitly set elements to the NULL state before
6195 * dropping the final reference, to allow them to clean up.
6197 gst_element_set_state(queue2, GST_STATE_NULL);
6199 /* And, it still has a parent "player".
6200 * You need to let the parent manage the object instead of unreffing the object directly.
6202 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6203 gst_object_unref(queue2);
6208 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6209 * You need to explicitly set elements to the NULL state before
6210 * dropping the final reference, to allow them to clean up.
6212 gst_element_set_state(decodebin, GST_STATE_NULL);
6214 /* And, it still has a parent "player".
6215 * You need to let the parent manage the object instead of unreffing the object directly.
6218 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6219 gst_object_unref(decodebin);
6227 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6231 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6232 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6234 LOGD("class : %s, mime : %s", factory_class, mime);
6236 /* add missing plugin */
6237 /* NOTE : msl should check missing plugin for image mime type.
6238 * Some motion jpeg clips can have playable audio track.
6239 * So, msl have to play audio after displaying popup written video format not supported.
6241 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6242 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6243 LOGD("not found demuxer");
6244 player->not_found_demuxer = TRUE;
6245 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6251 if (!g_strrstr(factory_class, "Demuxer")) {
6252 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6253 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6254 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6256 /* check that clip have multi tracks or not */
6257 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6258 LOGD("video plugin is already linked");
6260 LOGW("add VIDEO to missing plugin");
6261 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6262 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6264 } else if (g_str_has_prefix(mime, "audio")) {
6265 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6266 LOGD("audio plugin is already linked");
6268 LOGW("add AUDIO to missing plugin");
6269 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6270 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6278 return MM_ERROR_NONE;
6282 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6284 mmplayer_t *player = (mmplayer_t *)data;
6288 MMPLAYER_RETURN_IF_FAIL(player);
6290 /* remove fakesink. */
6291 if (!_mmplayer_gst_remove_fakesink(player,
6292 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6293 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6294 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6295 * source element are not same. To overcome this situation, this function will called
6296 * several places and several times. Therefore, this is not an error case.
6301 LOGD("[handle: %p] pipeline has completely constructed", player);
6303 if ((player->ini.async_start) &&
6304 (player->msg_posted == FALSE) &&
6305 (player->cmd >= MMPLAYER_COMMAND_START))
6306 __mmplayer_handle_missed_plugin(player);
6308 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6312 __mmplayer_check_profile(void)
6315 static int profile_tv = -1;
6317 if (__builtin_expect(profile_tv != -1, 1))
6320 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6321 switch (*profileName) {
6336 __mmplayer_get_next_uri(mmplayer_t *player)
6338 mmplayer_parse_profile_t profile;
6340 guint num_of_list = 0;
6343 num_of_list = g_list_length(player->uri_info.uri_list);
6344 uri_idx = player->uri_info.uri_idx;
6346 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6347 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6348 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6350 LOGW("next uri does not exist");
6354 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6355 LOGE("failed to parse profile");
6359 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6360 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6361 LOGW("uri type is not supported(%d)", profile.uri_type);
6365 LOGD("success to find next uri %d", uri_idx);
6369 if (uri_idx == num_of_list) {
6370 LOGE("failed to find next uri");
6374 player->uri_info.uri_idx = uri_idx;
6375 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6377 if (mm_attrs_commit_all(player->attrs)) {
6378 LOGE("failed to commit");
6382 SECURE_LOGD("next playback uri: %s", uri);
6387 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6389 #define REPEAT_COUNT_INFINITE -1
6390 #define REPEAT_COUNT_MIN 2
6391 #define ORIGINAL_URI_ONLY 1
6393 MMHandleType attrs = 0;
6397 guint num_of_uri = 0;
6398 int profile_tv = -1;
6402 LOGD("checking for gapless play option");
6404 if (player->pipeline->textbin) {
6405 LOGE("subtitle path is enabled. gapless play is not supported.");
6409 attrs = MMPLAYER_GET_ATTRS(player);
6411 LOGE("fail to get attributes.");
6415 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6417 /* gapless playback is not supported in case of video at TV profile. */
6418 profile_tv = __mmplayer_check_profile();
6419 if (profile_tv && video) {
6420 LOGW("not support video gapless playback");
6424 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6425 LOGE("failed to get play count");
6427 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6428 LOGE("failed to get gapless mode");
6430 /* check repeat count in case of audio */
6432 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6433 LOGW("gapless is disabled");
6437 num_of_uri = g_list_length(player->uri_info.uri_list);
6439 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6441 if (num_of_uri == ORIGINAL_URI_ONLY) {
6442 /* audio looping path */
6443 if (count >= REPEAT_COUNT_MIN) {
6444 /* decrease play count */
6445 /* we succeeded to rewind. update play count and then wait for next EOS */
6447 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6448 /* commit attribute */
6449 if (mm_attrs_commit_all(attrs))
6450 LOGE("failed to commit attribute");
6452 } else if (count != REPEAT_COUNT_INFINITE) {
6453 LOGD("there is no next uri and no repeat");
6456 LOGD("looping cnt %d", count);
6458 /* gapless playback path */
6459 if (!__mmplayer_get_next_uri(player)) {
6460 LOGE("failed to get next uri");
6467 LOGE("unable to play gapless path. EOS will be posted soon");
6472 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6474 mmplayer_selector_t *selector = &player->selector[type];
6475 mmplayer_gst_element_t *sinkbin = NULL;
6476 main_element_id_e selectorId = MMPLAYER_M_NUM;
6477 main_element_id_e sinkId = MMPLAYER_M_NUM;
6478 GstPad *srcpad = NULL;
6479 GstPad *sinkpad = NULL;
6480 gboolean send_notice = FALSE;
6483 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6485 LOGD("type %d", type);
6488 case MM_PLAYER_TRACK_TYPE_AUDIO:
6489 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6490 sinkId = MMPLAYER_A_BIN;
6491 sinkbin = player->pipeline->audiobin;
6493 case MM_PLAYER_TRACK_TYPE_VIDEO:
6494 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6495 sinkId = MMPLAYER_V_BIN;
6496 sinkbin = player->pipeline->videobin;
6499 case MM_PLAYER_TRACK_TYPE_TEXT:
6500 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6501 sinkId = MMPLAYER_T_BIN;
6502 sinkbin = player->pipeline->textbin;
6505 LOGE("requested type is not supportable");
6510 if (player->pipeline->mainbin[selectorId].gst) {
6513 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6515 if (selector->event_probe_id != 0)
6516 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6517 selector->event_probe_id = 0;
6519 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6520 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6522 if (srcpad && sinkpad) {
6523 /* after getting drained signal there is no data flows, so no need to do pad_block */
6524 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6525 gst_pad_unlink(srcpad, sinkpad);
6527 /* send custom event to sink pad to handle it at video sink */
6529 LOGD("send custom event to sinkpad");
6530 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6531 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6532 gst_pad_send_event(sinkpad, event);
6536 gst_object_unref(sinkpad);
6539 gst_object_unref(srcpad);
6542 LOGD("selector release");
6544 /* release and unref requests pad from the selector */
6545 for (n = 0; n < selector->channels->len; n++) {
6546 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6547 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6549 g_ptr_array_set_size(selector->channels, 0);
6551 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6552 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6554 player->pipeline->mainbin[selectorId].gst = NULL;
6562 __mmplayer_deactivate_old_path(mmplayer_t *player)
6565 MMPLAYER_RETURN_IF_FAIL(player);
6567 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6568 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6569 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6570 LOGE("deactivate selector error");
6574 _mmplayer_track_destroy(player);
6575 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6577 if (player->streamer) {
6578 _mm_player_streaming_initialize(player->streamer, FALSE);
6579 _mm_player_streaming_destroy(player->streamer);
6580 player->streamer = NULL;
6583 MMPLAYER_PLAYBACK_LOCK(player);
6584 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6591 if (!player->msg_posted) {
6592 MMMessageParamType msg = {0,};
6595 msg.code = MM_ERROR_PLAYER_INTERNAL;
6596 LOGE("gapless_uri_play> deactivate error");
6598 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6599 player->msg_posted = TRUE;
6605 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6607 int result = MM_ERROR_NONE;
6608 mmplayer_t *player = (mmplayer_t *)hplayer;
6611 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6613 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6614 if (mm_attrs_commit_all(player->attrs)) {
6615 LOGE("failed to commit the original uri.");
6616 result = MM_ERROR_PLAYER_INTERNAL;
6618 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6619 LOGE("failed to add the original uri in the uri list.");
6627 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6629 mmplayer_t *player = (mmplayer_t *)hplayer;
6630 guint num_of_list = 0;
6634 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6635 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6637 if (player->pipeline && player->pipeline->textbin) {
6638 LOGE("subtitle path is enabled.");
6639 return MM_ERROR_PLAYER_INVALID_STATE;
6642 num_of_list = g_list_length(player->uri_info.uri_list);
6644 if (is_first_path) {
6645 if (num_of_list == 0) {
6646 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6647 SECURE_LOGD("add original path : %s", uri);
6649 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6650 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6652 SECURE_LOGD("change original path : %s", uri);
6655 MMHandleType attrs = 0;
6656 attrs = MMPLAYER_GET_ATTRS(player);
6658 if (num_of_list == 0) {
6659 char *original_uri = NULL;
6662 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6664 if (!original_uri) {
6665 LOGE("there is no original uri.");
6666 return MM_ERROR_PLAYER_INVALID_STATE;
6669 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6670 player->uri_info.uri_idx = 0;
6672 SECURE_LOGD("add original path at first : %s", original_uri);
6676 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6677 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6681 return MM_ERROR_NONE;
6685 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6687 mmplayer_t *player = (mmplayer_t *)hplayer;
6688 char *next_uri = NULL;
6689 guint num_of_list = 0;
6692 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6694 num_of_list = g_list_length(player->uri_info.uri_list);
6696 if (num_of_list > 0) {
6697 gint uri_idx = player->uri_info.uri_idx;
6699 if (uri_idx < num_of_list-1)
6704 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6705 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6707 *uri = g_strdup(next_uri);
6711 return MM_ERROR_NONE;
6715 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6716 GstCaps *caps, gpointer data)
6718 mmplayer_t *player = (mmplayer_t *)data;
6719 const gchar *klass = NULL;
6720 const gchar *mime = NULL;
6721 gchar *caps_str = NULL;
6723 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6724 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6725 caps_str = gst_caps_to_string(caps);
6727 LOGW("unknown type of caps : %s from %s",
6728 caps_str, GST_ELEMENT_NAME(elem));
6730 MMPLAYER_FREEIF(caps_str);
6732 /* There is no available codec. */
6733 __mmplayer_check_not_supported_codec(player, klass, mime);
6737 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6738 GstCaps *caps, gpointer data)
6740 mmplayer_t *player = (mmplayer_t *)data;
6741 const char *mime = NULL;
6742 gboolean ret = TRUE;
6744 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6745 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6747 if (g_str_has_prefix(mime, "audio")) {
6748 GstStructure *caps_structure = NULL;
6749 gint samplerate = 0;
6751 gchar *caps_str = NULL;
6753 caps_structure = gst_caps_get_structure(caps, 0);
6754 gst_structure_get_int(caps_structure, "rate", &samplerate);
6755 gst_structure_get_int(caps_structure, "channels", &channels);
6757 if ((channels > 0 && samplerate == 0)) {
6758 LOGD("exclude audio...");
6762 caps_str = gst_caps_to_string(caps);
6763 /* set it directly because not sent by TAG */
6764 if (g_strrstr(caps_str, "mobile-xmf"))
6765 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6766 MMPLAYER_FREEIF(caps_str);
6767 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6768 MMMessageParamType msg_param;
6769 memset(&msg_param, 0, sizeof(MMMessageParamType));
6770 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6771 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6772 LOGD("video file is not supported on this device");
6774 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6775 LOGD("already video linked");
6778 LOGD("found new stream");
6785 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6787 gboolean ret = TRUE;
6788 GDBusConnection *conn = NULL;
6790 GVariant *result = NULL;
6791 const gchar *dbus_device_type = NULL;
6792 const gchar *dbus_ret = NULL;
6795 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6797 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6803 result = g_dbus_connection_call_sync(conn,
6804 "org.pulseaudio.Server",
6805 "/org/pulseaudio/StreamManager",
6806 "org.pulseaudio.StreamManager",
6807 "GetCurrentMediaRoutingPath",
6808 g_variant_new("(s)", "out"),
6809 G_VARIANT_TYPE("(ss)"),
6810 G_DBUS_CALL_FLAGS_NONE,
6814 if (!result || err) {
6815 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6821 /* device type is listed in stream-map.json at mmfw-sysconf */
6822 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6824 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6825 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6830 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6831 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6832 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6833 LOGD("audio offload is supportable");
6839 LOGD("audio offload is not supportable");
6843 g_variant_unref(result);
6844 g_object_unref(conn);
6849 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6851 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6852 gint64 position = 0;
6854 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6855 player->pipeline && player->pipeline->mainbin);
6857 MMPLAYER_CMD_LOCK(player);
6858 current_state = MMPLAYER_CURRENT_STATE(player);
6860 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6861 LOGW("getting current position failed in paused");
6863 _mmplayer_unrealize((MMHandleType)player);
6864 _mmplayer_realize((MMHandleType)player);
6866 _mmplayer_set_position((MMHandleType)player, position);
6868 /* async not to be blocked in streaming case */
6869 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6870 if (mm_attrs_commit_all(player->attrs))
6871 LOGE("failed to commit");
6873 _mmplayer_pause((MMHandleType)player);
6875 if (current_state == MM_PLAYER_STATE_PLAYING)
6876 _mmplayer_start((MMHandleType)player);
6877 MMPLAYER_CMD_UNLOCK(player);
6879 LOGD("rebuilding audio pipeline is completed.");
6882 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6884 mmplayer_t *player = (mmplayer_t *)user_data;
6885 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6886 gboolean is_supportable = FALSE;
6888 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6889 LOGW("failed to get device type");
6891 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6893 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6894 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6895 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6896 LOGD("ignore this dev connected info");
6900 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6901 if (player->build_audio_offload == is_supportable) {
6902 LOGD("keep current pipeline without re-building");
6906 /* rebuild pipeline */
6907 LOGD("re-build pipeline - offload: %d", is_supportable);
6908 player->build_audio_offload = FALSE;
6909 __mmplayer_rebuild_audio_pipeline(player);
6915 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6917 unsigned int id = 0;
6919 if (player->audio_device_cb_id != 0) {
6920 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6924 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6925 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6926 LOGD("added device connected cb (%u)", id);
6927 player->audio_device_cb_id = id;
6929 LOGW("failed to add device connected cb");
6937 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6939 gboolean ret = FALSE;
6940 GstElementFactory *factory = NULL;
6943 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6945 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6946 if (!__mmplayer_is_only_mp3_type(player->type))
6949 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6950 LOGD("there is no audio offload sink");
6954 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6955 LOGW("there is no audio device type to support offload");
6959 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6961 LOGW("there is no installed audio offload sink element");
6964 gst_object_unref(factory);
6966 if (!__mmplayer_add_audio_device_connected_cb(player))
6969 if (!__mmplayer_is_audio_offload_device_type(player))
6972 LOGD("audio offload can be built");
6980 static GstAutoplugSelectResult
6981 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6983 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6985 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6986 int audio_offload = 0;
6988 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6989 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6991 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6992 LOGD("expose audio path to build offload output path");
6993 player->build_audio_offload = TRUE;
6994 /* update codec info */
6995 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6996 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6997 player->audiodec_linked = 1;
6999 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7003 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7005 LOGD("audio codec type: %d", codec_type);
7006 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7007 /* sw codec will be skipped */
7008 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7009 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7010 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7011 ret = GST_AUTOPLUG_SELECT_SKIP;
7015 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7016 /* hw codec will be skipped */
7017 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7018 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7019 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7020 ret = GST_AUTOPLUG_SELECT_SKIP;
7025 /* set stream information */
7026 if (!player->audiodec_linked)
7027 __mmplayer_set_audio_attrs(player, caps);
7029 /* update codec info */
7030 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7031 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7032 player->audiodec_linked = 1;
7034 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7036 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7038 LOGD("video codec type: %d", codec_type);
7039 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7040 /* sw codec is skipped */
7041 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7042 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7043 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7044 ret = GST_AUTOPLUG_SELECT_SKIP;
7048 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7049 /* hw codec is skipped */
7050 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7051 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7052 ret = GST_AUTOPLUG_SELECT_SKIP;
7057 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7058 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7060 /* mark video decoder for acquire */
7061 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7062 LOGW("video decoder resource is already acquired, skip it.");
7063 ret = GST_AUTOPLUG_SELECT_SKIP;
7067 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7068 LOGE("failed to acquire video decoder resource");
7069 ret = GST_AUTOPLUG_SELECT_SKIP;
7072 player->interrupted_by_resource = FALSE;
7075 /* update codec info */
7076 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7077 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7078 player->videodec_linked = 1;
7086 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7087 GstCaps *caps, GstElementFactory *factory, gpointer data)
7089 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7090 mmplayer_t *player = (mmplayer_t *)data;
7092 gchar *factory_name = NULL;
7093 gchar *caps_str = NULL;
7094 const gchar *klass = NULL;
7097 factory_name = GST_OBJECT_NAME(factory);
7098 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7099 caps_str = gst_caps_to_string(caps);
7101 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7103 /* store type string */
7104 if (player->type == NULL) {
7105 player->type = gst_caps_to_string(caps);
7106 __mmplayer_update_content_type_info(player);
7109 /* filtering exclude keyword */
7110 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7111 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7112 LOGW("skipping [%s] by exculde keyword [%s]",
7113 factory_name, player->ini.exclude_element_keyword[idx]);
7115 result = GST_AUTOPLUG_SELECT_SKIP;
7120 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7121 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7122 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7123 factory_name, player->ini.unsupported_codec_keyword[idx]);
7124 result = GST_AUTOPLUG_SELECT_SKIP;
7129 /* exclude webm format */
7130 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7131 * because webm format is not supportable.
7132 * If webm is disabled in "autoplug-continue", there is no state change
7133 * failure or error because the decodebin will expose the pad directly.
7134 * It make MSL invoke _prepare_async_callback.
7135 * So, we need to disable webm format in "autoplug-select" */
7136 if (caps_str && strstr(caps_str, "webm")) {
7137 LOGW("webm is not supported");
7138 result = GST_AUTOPLUG_SELECT_SKIP;
7142 /* check factory class for filtering */
7143 /* NOTE : msl don't need to use image plugins.
7144 * So, those plugins should be skipped for error handling.
7146 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7147 LOGD("skipping [%s] by not required", factory_name);
7148 result = GST_AUTOPLUG_SELECT_SKIP;
7152 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7153 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7154 // TO CHECK : subtitle if needed, add subparse exception.
7155 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7156 result = GST_AUTOPLUG_SELECT_SKIP;
7160 if (g_strrstr(factory_name, "mpegpsdemux")) {
7161 LOGD("skipping PS container - not support");
7162 result = GST_AUTOPLUG_SELECT_SKIP;
7166 if (g_strrstr(factory_name, "mssdemux"))
7167 player->smooth_streaming = TRUE;
7169 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7170 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7173 GstStructure *str = NULL;
7174 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7176 /* don't make video because of not required */
7177 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7178 (!player->set_mode.video_export)) {
7179 LOGD("no need video decoding, expose pad");
7180 result = GST_AUTOPLUG_SELECT_EXPOSE;
7184 /* get w/h for omx state-tune */
7185 /* FIXME: deprecated? */
7186 str = gst_caps_get_structure(caps, 0);
7187 gst_structure_get_int(str, "width", &width);
7190 if (player->v_stream_caps) {
7191 gst_caps_unref(player->v_stream_caps);
7192 player->v_stream_caps = NULL;
7195 player->v_stream_caps = gst_caps_copy(caps);
7196 LOGD("take caps for video state tune");
7197 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7201 if (g_strrstr(klass, "Codec/Decoder")) {
7202 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7203 if (result != GST_AUTOPLUG_SELECT_TRY) {
7204 LOGW("skip add decoder");
7210 MMPLAYER_FREEIF(caps_str);
7216 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7219 //mmplayer_t *player = (mmplayer_t *)data;
7220 GstCaps *caps = NULL;
7222 LOGD("[Decodebin2] pad-removed signal");
7224 caps = gst_pad_query_caps(new_pad, NULL);
7226 LOGW("query caps is NULL");
7230 gchar *caps_str = NULL;
7231 caps_str = gst_caps_to_string(caps);
7233 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7235 MMPLAYER_FREEIF(caps_str);
7236 gst_caps_unref(caps);
7240 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7242 mmplayer_t *player = (mmplayer_t *)data;
7243 GstIterator *iter = NULL;
7244 GValue item = { 0, };
7246 gboolean done = FALSE;
7247 gboolean is_all_drained = TRUE;
7250 MMPLAYER_RETURN_IF_FAIL(player);
7252 LOGD("__mmplayer_gst_decode_drained");
7254 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7255 LOGW("Fail to get cmd lock");
7259 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7260 !__mmplayer_verify_gapless_play_path(player)) {
7261 LOGD("decoding is finished.");
7262 __mmplayer_reset_gapless_state(player);
7263 MMPLAYER_CMD_UNLOCK(player);
7267 player->gapless.reconfigure = TRUE;
7269 /* check decodebin src pads whether they received EOS or not */
7270 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7273 switch (gst_iterator_next(iter, &item)) {
7274 case GST_ITERATOR_OK:
7275 pad = g_value_get_object(&item);
7276 if (pad && !GST_PAD_IS_EOS(pad)) {
7277 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7278 is_all_drained = FALSE;
7281 g_value_reset(&item);
7283 case GST_ITERATOR_RESYNC:
7284 gst_iterator_resync(iter);
7286 case GST_ITERATOR_ERROR:
7287 case GST_ITERATOR_DONE:
7292 g_value_unset(&item);
7293 gst_iterator_free(iter);
7295 if (!is_all_drained) {
7296 LOGD("Wait util the all pads get EOS.");
7297 MMPLAYER_CMD_UNLOCK(player);
7302 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7303 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7305 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7306 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7307 __mmplayer_deactivate_old_path(player);
7308 MMPLAYER_CMD_UNLOCK(player);
7314 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7316 mmplayer_t *player = (mmplayer_t *)data;
7317 const gchar *klass = NULL;
7318 gchar *factory_name = NULL;
7320 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7321 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7323 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7325 if (__mmplayer_add_dump_buffer_probe(player, element))
7326 LOGD("add buffer probe");
7328 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7329 gchar *selected = NULL;
7330 selected = g_strdup(GST_ELEMENT_NAME(element));
7331 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7334 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7335 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7336 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7338 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7339 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7341 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7342 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7343 "max-video-width", player->adaptive_info.limit.width,
7344 "max-video-height", player->adaptive_info.limit.height, NULL);
7346 } else if (g_strrstr(klass, "Demuxer")) {
7347 //LOGD("plugged element is demuxer. take it");
7348 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7349 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7352 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7353 int surface_type = 0;
7355 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7358 // to support trust-zone only
7359 if (g_strrstr(factory_name, "asfdemux")) {
7360 LOGD("set file-location %s", player->profile.uri);
7361 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7362 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7363 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7364 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7365 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7366 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7367 (__mmplayer_is_only_mp3_type(player->type))) {
7368 LOGD("[mpegaudioparse] set streaming pull mode.");
7369 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7371 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7372 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7375 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7376 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7377 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7379 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7380 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7382 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7383 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7384 (MMPLAYER_IS_DASH_STREAMING(player))) {
7385 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7386 _mm_player_streaming_set_multiqueue(player->streamer, element);
7387 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7396 __mmplayer_release_misc(mmplayer_t *player)
7399 bool cur_mode = player->set_mode.rich_audio;
7402 MMPLAYER_RETURN_IF_FAIL(player);
7404 player->video_decoded_cb = NULL;
7405 player->video_decoded_cb_user_param = NULL;
7406 player->video_stream_prerolled = false;
7408 player->audio_decoded_cb = NULL;
7409 player->audio_decoded_cb_user_param = NULL;
7410 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7412 player->audio_stream_changed_cb = NULL;
7413 player->audio_stream_changed_cb_user_param = NULL;
7415 player->sent_bos = FALSE;
7416 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7418 player->seek_state = MMPLAYER_SEEK_NONE;
7420 player->total_bitrate = 0;
7421 player->total_maximum_bitrate = 0;
7423 player->not_found_demuxer = 0;
7425 player->last_position = 0;
7426 player->duration = 0;
7427 player->http_content_size = 0;
7428 player->not_supported_codec = MISSING_PLUGIN_NONE;
7429 player->can_support_codec = FOUND_PLUGIN_NONE;
7430 player->pending_seek.is_pending = false;
7431 player->pending_seek.pos = 0;
7432 player->msg_posted = FALSE;
7433 player->has_many_types = FALSE;
7434 player->is_subtitle_force_drop = FALSE;
7435 player->play_subtitle = FALSE;
7436 player->adjust_subtitle_pos = 0;
7437 player->has_closed_caption = FALSE;
7438 player->set_mode.video_export = false;
7439 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7440 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7442 player->set_mode.rich_audio = cur_mode;
7444 if (player->audio_device_cb_id > 0 &&
7445 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7446 LOGW("failed to remove audio device_connected_callback");
7447 player->audio_device_cb_id = 0;
7449 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7450 player->bitrate[i] = 0;
7451 player->maximum_bitrate[i] = 0;
7454 /* free memory related to audio effect */
7455 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7457 if (player->adaptive_info.var_list) {
7458 g_list_free_full(player->adaptive_info.var_list, g_free);
7459 player->adaptive_info.var_list = NULL;
7462 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7463 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7464 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7466 /* Reset video360 settings to their defaults in case if the pipeline is to be
7469 player->video360_metadata.is_spherical = -1;
7470 player->is_openal_plugin_used = FALSE;
7472 player->is_content_spherical = FALSE;
7473 player->is_video360_enabled = TRUE;
7474 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7475 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7476 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7477 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7478 player->video360_zoom = 1.0f;
7479 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7480 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7482 player->sound.rg_enable = false;
7484 __mmplayer_initialize_video_roi(player);
7489 __mmplayer_release_misc_post(mmplayer_t *player)
7491 char *original_uri = NULL;
7494 /* player->pipeline is already released before. */
7496 MMPLAYER_RETURN_IF_FAIL(player);
7498 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7500 /* clean found audio decoders */
7501 if (player->audio_decoders) {
7502 GList *a_dec = player->audio_decoders;
7503 for (; a_dec; a_dec = g_list_next(a_dec)) {
7504 gchar *name = a_dec->data;
7505 MMPLAYER_FREEIF(name);
7507 g_list_free(player->audio_decoders);
7508 player->audio_decoders = NULL;
7511 /* clean the uri list except original uri */
7512 if (player->uri_info.uri_list) {
7513 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7515 if (player->attrs) {
7516 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7517 LOGD("restore original uri = %s", original_uri);
7519 if (mm_attrs_commit_all(player->attrs))
7520 LOGE("failed to commit the original uri.");
7523 GList *uri_list = player->uri_info.uri_list;
7524 for (; uri_list; uri_list = g_list_next(uri_list)) {
7525 gchar *uri = uri_list->data;
7526 MMPLAYER_FREEIF(uri);
7528 g_list_free(player->uri_info.uri_list);
7529 player->uri_info.uri_list = NULL;
7532 /* clear the audio stream buffer list */
7533 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7535 /* clear the video stream bo list */
7536 __mmplayer_video_stream_destroy_bo_list(player);
7537 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7539 if (player->profile.input_mem.buf) {
7540 free(player->profile.input_mem.buf);
7541 player->profile.input_mem.buf = NULL;
7543 player->profile.input_mem.len = 0;
7544 player->profile.input_mem.offset = 0;
7546 player->uri_info.uri_idx = 0;
7551 __mmplayer_check_subtitle(mmplayer_t *player)
7553 MMHandleType attrs = 0;
7554 char *subtitle_uri = NULL;
7558 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7560 /* get subtitle attribute */
7561 attrs = MMPLAYER_GET_ATTRS(player);
7565 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7566 if (!subtitle_uri || !strlen(subtitle_uri))
7569 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7570 player->is_external_subtitle_present = TRUE;
7578 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7580 MMPLAYER_RETURN_IF_FAIL(player);
7582 if (player->eos_timer) {
7583 LOGD("cancel eos timer");
7584 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7585 player->eos_timer = 0;
7592 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7596 MMPLAYER_RETURN_IF_FAIL(player);
7597 MMPLAYER_RETURN_IF_FAIL(sink);
7599 player->sink_elements = g_list_append(player->sink_elements, sink);
7605 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7609 MMPLAYER_RETURN_IF_FAIL(player);
7610 MMPLAYER_RETURN_IF_FAIL(sink);
7612 player->sink_elements = g_list_remove(player->sink_elements, sink);
7618 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7619 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7621 mmplayer_signal_item_t *item = NULL;
7624 MMPLAYER_RETURN_IF_FAIL(player);
7626 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7627 LOGE("invalid signal type [%d]", type);
7631 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7633 LOGE("cannot connect signal [%s]", signal);
7638 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7639 player->signals[type] = g_list_append(player->signals[type], item);
7645 /* NOTE : be careful with calling this api. please refer to below glib comment
7646 * glib comment : Note that there is a bug in GObject that makes this function much
7647 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7648 * will no longer be called, but, the signal handler is not currently disconnected.
7649 * If the instance is itself being freed at the same time than this doesn't matter,
7650 * since the signal will automatically be removed, but if instance persists,
7651 * then the signal handler will leak. You should not remove the signal yourself
7652 * because in a future versions of GObject, the handler will automatically be
7655 * It's possible to work around this problem in a way that will continue to work
7656 * with future versions of GObject by checking that the signal handler is still
7657 * connected before disconnected it:
7659 * if (g_signal_handler_is_connected(instance, id))
7660 * g_signal_handler_disconnect(instance, id);
7663 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7665 GList *sig_list = NULL;
7666 mmplayer_signal_item_t *item = NULL;
7670 MMPLAYER_RETURN_IF_FAIL(player);
7672 LOGD("release signals type : %d", type);
7674 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7675 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7676 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7677 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7678 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7679 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7683 sig_list = player->signals[type];
7685 for (; sig_list; sig_list = sig_list->next) {
7686 item = sig_list->data;
7688 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7689 if (g_signal_handler_is_connected(item->obj, item->sig))
7690 g_signal_handler_disconnect(item->obj, item->sig);
7693 MMPLAYER_FREEIF(item);
7696 g_list_free(player->signals[type]);
7697 player->signals[type] = NULL;
7705 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7707 mmplayer_t *player = 0;
7708 int prev_display_surface_type = 0;
7709 void *prev_display_overlay = NULL;
7713 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7714 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7716 player = MM_PLAYER_CAST(handle);
7718 /* check video sinkbin is created */
7719 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7720 LOGE("Videosink is already created");
7721 return MM_ERROR_NONE;
7724 LOGD("videosink element is not yet ready");
7726 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7727 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7729 return MM_ERROR_INVALID_ARGUMENT;
7732 /* load previous attributes */
7733 if (player->attrs) {
7734 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7735 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7736 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7737 if (prev_display_surface_type == surface_type) {
7738 LOGD("incoming display surface type is same as previous one, do nothing..");
7740 return MM_ERROR_NONE;
7743 LOGE("failed to load attributes");
7745 return MM_ERROR_PLAYER_INTERNAL;
7748 /* videobin is not created yet, so we just set attributes related to display surface */
7749 LOGD("store display attribute for given surface type(%d)", surface_type);
7750 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7751 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7752 if (mm_attrs_commit_all(player->attrs)) {
7753 LOGE("failed to commit attribute");
7755 return MM_ERROR_PLAYER_INTERNAL;
7759 return MM_ERROR_NONE;
7762 /* Note : if silent is true, then subtitle would not be displayed. :*/
7764 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7766 mmplayer_t *player = (mmplayer_t *)hplayer;
7770 /* check player handle */
7771 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7773 player->set_mode.subtitle_off = silent;
7775 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7779 return MM_ERROR_NONE;
7783 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7785 mmplayer_gst_element_t *mainbin = NULL;
7786 mmplayer_gst_element_t *textbin = NULL;
7787 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7788 GstState current_state = GST_STATE_VOID_PENDING;
7789 GstState element_state = GST_STATE_VOID_PENDING;
7790 GstState element_pending_state = GST_STATE_VOID_PENDING;
7792 GstEvent *event = NULL;
7793 int result = MM_ERROR_NONE;
7795 GstClock *curr_clock = NULL;
7796 GstClockTime base_time, start_time, curr_time;
7801 /* check player handle */
7802 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7804 player->pipeline->mainbin &&
7805 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7807 mainbin = player->pipeline->mainbin;
7808 textbin = player->pipeline->textbin;
7810 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7812 // sync clock with current pipeline
7813 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7814 curr_time = gst_clock_get_time(curr_clock);
7816 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7817 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7819 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7820 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7822 if (current_state > GST_STATE_READY) {
7823 // sync state with current pipeline
7824 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7825 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7826 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7828 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7829 if (GST_STATE_CHANGE_FAILURE == ret) {
7830 LOGE("fail to state change.");
7831 result = MM_ERROR_PLAYER_INTERNAL;
7835 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7836 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7839 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7840 gst_object_unref(curr_clock);
7843 // seek to current position
7844 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7845 result = MM_ERROR_PLAYER_INVALID_STATE;
7846 LOGE("gst_element_query_position failed, invalid state");
7850 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7851 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);
7853 _mmplayer_gst_send_event_to_sink(player, event);
7855 result = MM_ERROR_PLAYER_INTERNAL;
7856 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7860 /* sync state with current pipeline */
7861 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7862 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7863 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7865 return MM_ERROR_NONE;
7868 /* release text pipeline resource */
7869 player->textsink_linked = 0;
7871 /* release signal */
7872 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7874 /* release textbin with it's childs */
7875 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7876 MMPLAYER_FREEIF(player->pipeline->textbin);
7877 player->pipeline->textbin = NULL;
7879 /* release subtitle elem */
7880 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7881 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7887 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7889 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7890 GstState current_state = GST_STATE_VOID_PENDING;
7892 MMHandleType attrs = 0;
7893 mmplayer_gst_element_t *mainbin = NULL;
7894 mmplayer_gst_element_t *textbin = NULL;
7896 gchar *subtitle_uri = NULL;
7897 int result = MM_ERROR_NONE;
7898 const gchar *charset = NULL;
7902 /* check player handle */
7903 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7905 player->pipeline->mainbin &&
7906 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7907 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7909 mainbin = player->pipeline->mainbin;
7910 textbin = player->pipeline->textbin;
7912 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7913 if (current_state < GST_STATE_READY) {
7914 result = MM_ERROR_PLAYER_INVALID_STATE;
7915 LOGE("Pipeline is not in proper state");
7919 attrs = MMPLAYER_GET_ATTRS(player);
7921 LOGE("cannot get content attribute");
7922 result = MM_ERROR_PLAYER_INTERNAL;
7926 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7927 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7928 LOGE("subtitle uri is not proper filepath");
7929 result = MM_ERROR_PLAYER_INVALID_URI;
7933 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7934 LOGE("failed to get storage info of subtitle path");
7935 result = MM_ERROR_PLAYER_INVALID_URI;
7939 LOGD("old subtitle file path is [%s]", subtitle_uri);
7940 LOGD("new subtitle file path is [%s]", filepath);
7942 if (!strcmp(filepath, subtitle_uri)) {
7943 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7946 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7947 if (mm_attrs_commit_all(player->attrs)) {
7948 LOGE("failed to commit.");
7953 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7954 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7955 player->subtitle_language_list = NULL;
7956 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7958 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7959 if (ret != GST_STATE_CHANGE_SUCCESS) {
7960 LOGE("failed to change state of textbin to READY");
7961 result = MM_ERROR_PLAYER_INTERNAL;
7965 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7966 if (ret != GST_STATE_CHANGE_SUCCESS) {
7967 LOGE("failed to change state of subparse to READY");
7968 result = MM_ERROR_PLAYER_INTERNAL;
7972 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7973 if (ret != GST_STATE_CHANGE_SUCCESS) {
7974 LOGE("failed to change state of filesrc to READY");
7975 result = MM_ERROR_PLAYER_INTERNAL;
7979 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7981 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7983 charset = _mmplayer_get_charset(filepath);
7985 LOGD("detected charset is %s", charset);
7986 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7989 result = _mmplayer_sync_subtitle_pipeline(player);
7996 /* API to switch between external subtitles */
7998 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8000 int result = MM_ERROR_NONE;
8001 mmplayer_t *player = (mmplayer_t *)hplayer;
8006 /* check player handle */
8007 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8009 /* filepath can be null in idle state */
8011 /* check file path */
8012 if ((path = strstr(filepath, "file://")))
8013 result = _mmplayer_exist_file_path(path + 7);
8015 result = _mmplayer_exist_file_path(filepath);
8017 if (result != MM_ERROR_NONE) {
8018 LOGE("invalid subtitle path 0x%X", result);
8019 return result; /* file not found or permission denied */
8023 if (!player->pipeline) {
8025 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8026 if (mm_attrs_commit_all(player->attrs)) {
8027 LOGE("failed to commit"); /* subtitle path will not be created */
8028 return MM_ERROR_PLAYER_INTERNAL;
8031 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8032 /* check filepath */
8033 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8035 if (!__mmplayer_check_subtitle(player)) {
8036 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8037 if (mm_attrs_commit_all(player->attrs)) {
8038 LOGE("failed to commit");
8039 return MM_ERROR_PLAYER_INTERNAL;
8042 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8043 LOGE("fail to create text pipeline");
8044 return MM_ERROR_PLAYER_INTERNAL;
8047 result = _mmplayer_sync_subtitle_pipeline(player);
8049 result = __mmplayer_change_external_subtitle_language(player, filepath);
8052 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8053 player->is_external_subtitle_added_now = TRUE;
8055 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8056 if (!player->subtitle_language_list) {
8057 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8058 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8059 LOGW("subtitle language list is not updated yet");
8061 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8069 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8071 int result = MM_ERROR_NONE;
8072 gchar *change_pad_name = NULL;
8073 GstPad *sinkpad = NULL;
8074 mmplayer_gst_element_t *mainbin = NULL;
8075 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8076 GstCaps *caps = NULL;
8077 gint total_track_num = 0;
8081 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8082 MM_ERROR_PLAYER_NOT_INITIALIZED);
8084 LOGD("Change Track(%d) to %d", type, index);
8086 mainbin = player->pipeline->mainbin;
8088 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8089 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8090 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8091 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8093 /* Changing Video Track is not supported. */
8094 LOGE("Track Type Error");
8098 if (mainbin[elem_idx].gst == NULL) {
8099 result = MM_ERROR_PLAYER_NO_OP;
8100 LOGD("Req track doesn't exist");
8104 total_track_num = player->selector[type].total_track_num;
8105 if (total_track_num <= 0) {
8106 result = MM_ERROR_PLAYER_NO_OP;
8107 LOGD("Language list is not available");
8111 if ((index < 0) || (index >= total_track_num)) {
8112 result = MM_ERROR_INVALID_ARGUMENT;
8113 LOGD("Not a proper index : %d", index);
8117 /*To get the new pad from the selector*/
8118 change_pad_name = g_strdup_printf("sink_%u", index);
8119 if (change_pad_name == NULL) {
8120 result = MM_ERROR_PLAYER_INTERNAL;
8121 LOGD("Pad does not exists");
8125 LOGD("new active pad name: %s", change_pad_name);
8127 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8128 if (sinkpad == NULL) {
8129 LOGD("sinkpad is NULL");
8130 result = MM_ERROR_PLAYER_INTERNAL;
8134 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8135 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8137 caps = gst_pad_get_current_caps(sinkpad);
8138 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8141 gst_object_unref(sinkpad);
8143 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8144 __mmplayer_set_audio_attrs(player, caps);
8147 MMPLAYER_FREEIF(change_pad_name);
8152 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8154 int result = MM_ERROR_NONE;
8155 mmplayer_t *player = NULL;
8156 mmplayer_gst_element_t *mainbin = NULL;
8158 gint current_active_index = 0;
8160 GstState current_state = GST_STATE_VOID_PENDING;
8161 GstEvent *event = NULL;
8166 player = (mmplayer_t *)hplayer;
8167 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8169 if (!player->pipeline) {
8170 LOGE("Track %d pre setting -> %d", type, index);
8172 player->selector[type].active_pad_index = index;
8176 mainbin = player->pipeline->mainbin;
8178 current_active_index = player->selector[type].active_pad_index;
8180 /*If index is same as running index no need to change the pad*/
8181 if (current_active_index == index)
8184 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8185 result = MM_ERROR_PLAYER_INVALID_STATE;
8189 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8190 if (current_state < GST_STATE_PAUSED) {
8191 result = MM_ERROR_PLAYER_INVALID_STATE;
8192 LOGW("Pipeline not in porper state");
8196 result = __mmplayer_change_selector_pad(player, type, index);
8197 if (result != MM_ERROR_NONE) {
8198 LOGE("change selector pad error");
8202 player->selector[type].active_pad_index = index;
8204 if (current_state == GST_STATE_PLAYING) {
8205 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8206 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8207 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8209 _mmplayer_gst_send_event_to_sink(player, event);
8211 result = MM_ERROR_PLAYER_INTERNAL;
8221 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8223 mmplayer_t *player = (mmplayer_t *)hplayer;
8227 /* check player handle */
8228 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8230 *silent = player->set_mode.subtitle_off;
8232 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8236 return MM_ERROR_NONE;
8240 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8242 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8243 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8245 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8246 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8250 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8251 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8252 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8253 mmplayer_dump_t *dump_s;
8254 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8255 if (dump_s == NULL) {
8256 LOGE("malloc fail");
8260 dump_s->dump_element_file = NULL;
8261 dump_s->dump_pad = NULL;
8262 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8264 if (dump_s->dump_pad) {
8265 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8266 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]);
8267 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8268 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);
8269 /* add list for removed buffer probe and close FILE */
8270 player->dump_list = g_list_append(player->dump_list, dump_s);
8271 LOGD("%s sink pad added buffer probe for dump", factory_name);
8274 MMPLAYER_FREEIF(dump_s);
8275 LOGE("failed to get %s sink pad added", factory_name);
8282 static GstPadProbeReturn
8283 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8285 FILE *dump_data = (FILE *)u_data;
8287 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8288 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8290 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8292 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8294 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8296 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8298 gst_buffer_unmap(buffer, &probe_info);
8300 return GST_PAD_PROBE_OK;
8304 __mmplayer_release_dump_list(GList *dump_list)
8306 GList *d_list = dump_list;
8311 for (; d_list; d_list = g_list_next(d_list)) {
8312 mmplayer_dump_t *dump_s = d_list->data;
8313 if (dump_s->dump_pad) {
8314 if (dump_s->probe_handle_id)
8315 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8316 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8318 if (dump_s->dump_element_file) {
8319 fclose(dump_s->dump_element_file);
8320 dump_s->dump_element_file = NULL;
8322 MMPLAYER_FREEIF(dump_s);
8324 g_list_free(dump_list);
8329 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8331 mmplayer_t *player = (mmplayer_t *)hplayer;
8335 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8336 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8338 *exist = (bool)player->has_closed_caption;
8342 return MM_ERROR_NONE;
8346 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8350 // LOGD("unref internal gst buffer %p", buffer);
8351 gst_buffer_unref((GstBuffer *)buffer);
8358 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8360 mmplayer_t *player = (mmplayer_t *)hplayer;
8364 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8365 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8367 if (MMPLAYER_IS_STREAMING(player))
8368 *timeout = (int)player->ini.live_state_change_timeout;
8370 *timeout = (int)player->ini.localplayback_state_change_timeout;
8372 LOGD("timeout = %d", *timeout);
8375 return MM_ERROR_NONE;
8379 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8383 MMPLAYER_RETURN_IF_FAIL(player);
8385 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8387 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8388 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8389 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8390 player->storage_info[i].id = -1;
8391 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8393 if (path_type != MMPLAYER_PATH_MAX)
8402 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8404 int ret = MM_ERROR_NONE;
8405 mmplayer_t *player = (mmplayer_t *)hplayer;
8406 MMMessageParamType msg_param = {0, };
8409 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8411 LOGW("state changed storage %d:%d", id, state);
8413 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8414 return MM_ERROR_NONE;
8416 /* FIXME: text path should be handled seperately. */
8417 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8418 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8419 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8420 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8421 LOGW("external storage is removed");
8423 if (player->msg_posted == FALSE) {
8424 memset(&msg_param, 0, sizeof(MMMessageParamType));
8425 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8426 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8427 player->msg_posted = TRUE;
8430 /* unrealize the player */
8431 ret = _mmplayer_unrealize(hplayer);
8432 if (ret != MM_ERROR_NONE)
8433 LOGE("failed to unrealize");
8441 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8443 int ret = MM_ERROR_NONE;
8444 mmplayer_t *player = (mmplayer_t *)hplayer;
8445 int idx = 0, total = 0;
8446 gchar *result = NULL, *tmp = NULL;
8449 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8450 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8452 total = *num = g_list_length(player->adaptive_info.var_list);
8454 LOGW("There is no stream variant info.");
8458 result = g_strdup("");
8459 for (idx = 0 ; idx < total ; idx++) {
8460 stream_variant_t *v_data = NULL;
8461 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8464 gchar data[64] = {0};
8465 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8467 tmp = g_strconcat(result, data, NULL);
8471 LOGW("There is no variant data in %d", idx);
8476 *var_info = (char *)result;
8478 LOGD("variant info %d:%s", *num, *var_info);
8484 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8486 int ret = MM_ERROR_NONE;
8487 mmplayer_t *player = (mmplayer_t *)hplayer;
8490 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8492 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8494 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8495 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8496 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8498 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8499 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8500 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8501 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8503 /* FIXME: seek to current position for applying new variant limitation */
8512 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8514 int ret = MM_ERROR_NONE;
8515 mmplayer_t *player = (mmplayer_t *)hplayer;
8518 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8519 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8521 *bandwidth = player->adaptive_info.limit.bandwidth;
8522 *width = player->adaptive_info.limit.width;
8523 *height = player->adaptive_info.limit.height;
8525 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8532 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8534 int ret = MM_ERROR_NONE;
8535 mmplayer_t *player = (mmplayer_t *)hplayer;
8538 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8539 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8540 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8542 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8544 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8545 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8546 else /* live case */
8547 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8549 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8556 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8558 #define IDX_FIRST_SW_CODEC 0
8559 mmplayer_t *player = (mmplayer_t *)hplayer;
8560 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8561 MMHandleType attrs = 0;
8564 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8566 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8567 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8568 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8570 switch (stream_type) {
8571 case MM_PLAYER_STREAM_TYPE_AUDIO:
8572 /* to support audio codec selection, codec info have to be added in ini file as below.
8573 audio codec element hw = xxxx
8574 audio codec element sw = avdec */
8575 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8576 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8577 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8578 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8579 LOGE("There is no audio codec info for codec_type %d", codec_type);
8580 return MM_ERROR_PLAYER_NO_OP;
8583 case MM_PLAYER_STREAM_TYPE_VIDEO:
8584 /* to support video codec selection, codec info have to be added in ini file as below.
8585 video codec element hw = omx
8586 video codec element sw = avdec */
8587 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8588 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8589 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8590 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8591 LOGE("There is no video codec info for codec_type %d", codec_type);
8592 return MM_ERROR_PLAYER_NO_OP;
8596 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8597 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8601 LOGD("update %s codec_type to %d", attr_name, codec_type);
8603 attrs = MMPLAYER_GET_ATTRS(player);
8604 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8606 if (mm_attrs_commit_all(player->attrs)) {
8607 LOGE("failed to commit codec_type attributes");
8608 return MM_ERROR_PLAYER_INTERNAL;
8612 return MM_ERROR_NONE;
8616 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8618 mmplayer_t *player = (mmplayer_t *)hplayer;
8619 GstElement *rg_vol_element = NULL;
8623 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8625 player->sound.rg_enable = enabled;
8627 /* just hold rgvolume enable value if pipeline is not ready */
8628 if (!player->pipeline || !player->pipeline->audiobin) {
8629 LOGD("pipeline is not ready. holding rgvolume enable value");
8630 return MM_ERROR_NONE;
8633 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8635 if (!rg_vol_element) {
8636 LOGD("rgvolume element is not created");
8637 return MM_ERROR_PLAYER_INTERNAL;
8641 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8643 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8647 return MM_ERROR_NONE;
8651 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8653 mmplayer_t *player = (mmplayer_t *)hplayer;
8654 GstElement *rg_vol_element = NULL;
8655 gboolean enable = FALSE;
8659 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8660 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8662 /* just hold enable_rg value if pipeline is not ready */
8663 if (!player->pipeline || !player->pipeline->audiobin) {
8664 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8665 *enabled = player->sound.rg_enable;
8666 return MM_ERROR_NONE;
8669 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8671 if (!rg_vol_element) {
8672 LOGD("rgvolume element is not created");
8673 return MM_ERROR_PLAYER_INTERNAL;
8676 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8677 *enabled = (bool)enable;
8681 return MM_ERROR_NONE;
8685 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8687 mmplayer_t *player = (mmplayer_t *)hplayer;
8688 MMHandleType attrs = 0;
8689 void *handle = NULL;
8690 int ret = MM_ERROR_NONE;
8694 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8696 attrs = MMPLAYER_GET_ATTRS(player);
8697 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8699 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8701 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8702 return MM_ERROR_PLAYER_INTERNAL;
8705 player->video_roi.scale_x = scale_x;
8706 player->video_roi.scale_y = scale_y;
8707 player->video_roi.scale_width = scale_width;
8708 player->video_roi.scale_height = scale_height;
8710 /* check video sinkbin is created */
8711 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8712 return MM_ERROR_NONE;
8714 if (!gst_video_overlay_set_video_roi_area(
8715 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8716 scale_x, scale_y, scale_width, scale_height))
8717 ret = MM_ERROR_PLAYER_INTERNAL;
8719 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8720 scale_x, scale_y, scale_width, scale_height);
8728 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8730 mmplayer_t *player = (mmplayer_t *)hplayer;
8731 int ret = MM_ERROR_NONE;
8735 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8736 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8738 *scale_x = player->video_roi.scale_x;
8739 *scale_y = player->video_roi.scale_y;
8740 *scale_width = player->video_roi.scale_width;
8741 *scale_height = player->video_roi.scale_height;
8743 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8744 *scale_x, *scale_y, *scale_width, *scale_height);
8750 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8752 mmplayer_t* player = (mmplayer_t*)hplayer;
8756 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8758 player->client_pid = pid;
8760 LOGD("client pid[%d] %p", pid, player);
8764 return MM_ERROR_NONE;
8768 __mmplayer_update_duration_value(mmplayer_t *player)
8770 gboolean ret = FALSE;
8771 gint64 dur_nsec = 0;
8772 LOGD("try to update duration");
8774 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8775 player->duration = dur_nsec;
8776 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8780 if (player->duration < 0) {
8781 LOGW("duration is Non-Initialized !!!");
8782 player->duration = 0;
8785 /* update streaming service type */
8786 player->streaming_type = _mmplayer_get_stream_service_type(player);
8788 /* check duration is OK */
8789 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8790 /* FIXIT : find another way to get duration here. */
8791 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8797 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8799 /* update audio params
8800 NOTE : We need original audio params and it can be only obtained from src pad of audio
8801 decoder. Below code only valid when we are not using 'resampler' just before
8802 'audioconverter'. */
8803 GstCaps *caps_a = NULL;
8805 gint samplerate = 0, channels = 0;
8806 GstStructure *p = NULL;
8807 GstElement *aconv = NULL;
8809 LOGD("try to update audio attrs");
8811 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8813 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8814 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8815 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8816 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8818 LOGE("there is no audio converter");
8822 pad = gst_element_get_static_pad(aconv, "sink");
8825 LOGW("failed to get pad from audio converter");
8829 caps_a = gst_pad_get_current_caps(pad);
8831 LOGW("not ready to get audio caps");
8832 gst_object_unref(pad);
8836 p = gst_caps_get_structure(caps_a, 0);
8838 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8840 gst_structure_get_int(p, "rate", &samplerate);
8841 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8843 gst_structure_get_int(p, "channels", &channels);
8844 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8846 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8848 gst_caps_unref(caps_a);
8849 gst_object_unref(pad);
8855 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8857 LOGD("try to update video attrs");
8859 GstCaps *caps_v = NULL;
8863 GstStructure *p = NULL;
8865 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8866 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8868 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8870 LOGD("no videosink sink pad");
8874 caps_v = gst_pad_get_current_caps(pad);
8875 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8876 if (!caps_v && player->v_stream_caps) {
8877 caps_v = player->v_stream_caps;
8878 gst_caps_ref(caps_v);
8882 LOGD("no negitiated caps from videosink");
8883 gst_object_unref(pad);
8887 p = gst_caps_get_structure(caps_v, 0);
8888 gst_structure_get_int(p, "width", &width);
8889 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8891 gst_structure_get_int(p, "height", &height);
8892 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8894 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8896 SECURE_LOGD("width : %d height : %d", width, height);
8898 gst_caps_unref(caps_v);
8899 gst_object_unref(pad);
8902 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8903 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8910 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8912 gboolean ret = FALSE;
8913 guint64 data_size = 0;
8917 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8918 if (!player->duration)
8921 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8922 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8923 if (stat(path, &sb) == 0)
8924 data_size = (guint64)sb.st_size;
8926 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8927 data_size = player->http_content_size;
8930 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8933 guint64 bitrate = 0;
8934 guint64 msec_dur = 0;
8936 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8938 bitrate = data_size * 8 * 1000 / msec_dur;
8939 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8940 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8944 LOGD("player duration is less than 0");
8948 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8949 if (player->total_bitrate) {
8950 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8959 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8961 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8962 data->uri_type = uri_type;
8966 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8968 int ret = MM_ERROR_PLAYER_INVALID_URI;
8970 char *buffer = NULL;
8971 char *seperator = strchr(path, ',');
8972 char ext[100] = {0,}, size[100] = {0,};
8975 if ((buffer = strstr(path, "ext="))) {
8976 buffer += strlen("ext=");
8978 if (strlen(buffer)) {
8979 strncpy(ext, buffer, 99);
8981 if ((seperator = strchr(ext, ','))
8982 || (seperator = strchr(ext, ' '))
8983 || (seperator = strchr(ext, '\0'))) {
8984 seperator[0] = '\0';
8989 if ((buffer = strstr(path, "size="))) {
8990 buffer += strlen("size=");
8992 if (strlen(buffer) > 0) {
8993 strncpy(size, buffer, 99);
8995 if ((seperator = strchr(size, ','))
8996 || (seperator = strchr(size, ' '))
8997 || (seperator = strchr(size, '\0'))) {
8998 seperator[0] = '\0';
9001 mem_size = atoi(size);
9006 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9008 if (mem_size && param) {
9009 if (data->input_mem.buf)
9010 free(data->input_mem.buf);
9011 data->input_mem.buf = malloc(mem_size);
9013 if (data->input_mem.buf) {
9014 memcpy(data->input_mem.buf, param, mem_size);
9015 data->input_mem.len = mem_size;
9016 ret = MM_ERROR_NONE;
9018 LOGE("failed to alloc mem %d", mem_size);
9019 ret = MM_ERROR_PLAYER_INTERNAL;
9022 data->input_mem.offset = 0;
9023 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9030 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9032 gchar *location = NULL;
9035 int ret = MM_ERROR_NONE;
9037 if ((path = strstr(uri, "file://"))) {
9038 location = g_filename_from_uri(uri, NULL, &err);
9039 if (!location || (err != NULL)) {
9040 LOGE("Invalid URI '%s' for filesrc: %s", path,
9041 (err != NULL) ? err->message : "unknown error");
9045 MMPLAYER_FREEIF(location);
9047 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9048 return MM_ERROR_PLAYER_INVALID_URI;
9050 LOGD("path from uri: %s", location);
9053 path = (location != NULL) ? (location) : ((char *)uri);
9056 ret = _mmplayer_exist_file_path(path);
9058 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9059 if (ret == MM_ERROR_NONE) {
9060 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9061 if (_mmplayer_is_sdp_file(path)) {
9062 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9063 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9065 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9067 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9068 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9070 LOGE("invalid uri, could not play..");
9071 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9074 MMPLAYER_FREEIF(location);
9079 static mmplayer_video_decoded_data_info_t *
9080 __mmplayer_create_stream_from_pad(GstPad *pad)
9082 GstCaps *caps = NULL;
9083 GstStructure *structure = NULL;
9084 unsigned int fourcc = 0;
9085 const gchar *string_format = NULL;
9086 mmplayer_video_decoded_data_info_t *stream = NULL;
9088 MMPixelFormatType format;
9091 caps = gst_pad_get_current_caps(pad);
9093 LOGE("Caps is NULL.");
9097 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9098 structure = gst_caps_get_structure(caps, 0);
9099 gst_structure_get_int(structure, "width", &width);
9100 gst_structure_get_int(structure, "height", &height);
9101 string_format = gst_structure_get_string(structure, "format");
9104 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9105 format = _mmplayer_get_pixtype(fourcc);
9106 gst_video_info_from_caps(&info, caps);
9107 gst_caps_unref(caps);
9110 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9111 LOGE("Wrong condition!!");
9115 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9117 LOGE("failed to alloc mem for video data");
9121 stream->width = width;
9122 stream->height = height;
9123 stream->format = format;
9124 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9130 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9132 unsigned int pitch = 0;
9133 unsigned int size = 0;
9135 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9138 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9139 bo = gst_tizen_memory_get_bos(mem, index);
9141 stream->bo[index] = tbm_bo_ref(bo);
9143 LOGE("failed to get bo for index %d", index);
9146 for (index = 0; index < stream->plane_num; index++) {
9147 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9148 stream->stride[index] = pitch;
9150 stream->elevation[index] = size / pitch;
9152 stream->elevation[index] = stream->height;
9157 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9159 if (stream->format == MM_PIXEL_FORMAT_I420) {
9160 int ret = TBM_SURFACE_ERROR_NONE;
9161 tbm_surface_h surface;
9162 tbm_surface_info_s info;
9164 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9166 ret = tbm_surface_get_info(surface, &info);
9167 if (ret != TBM_SURFACE_ERROR_NONE) {
9168 tbm_surface_destroy(surface);
9172 tbm_surface_destroy(surface);
9173 stream->stride[0] = info.planes[0].stride;
9174 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9175 stream->stride[1] = info.planes[1].stride;
9176 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9177 stream->stride[2] = info.planes[2].stride;
9178 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9179 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9180 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9181 stream->stride[0] = stream->width * 4;
9182 stream->elevation[0] = stream->height;
9183 stream->bo_size = stream->stride[0] * stream->height;
9185 LOGE("Not support format %d", stream->format);
9193 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9195 tbm_bo_handle thandle;
9197 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9198 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9199 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9203 unsigned char *src = NULL;
9204 unsigned char *dest = NULL;
9205 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9207 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9209 LOGE("fail to gst_memory_map");
9213 if (!mapinfo.data) {
9214 LOGE("data pointer is wrong");
9218 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9219 if (!stream->bo[0]) {
9220 LOGE("Fail to tbm_bo_alloc!!");
9224 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9226 LOGE("thandle pointer is wrong");
9230 if (stream->format == MM_PIXEL_FORMAT_I420) {
9231 src_stride[0] = GST_ROUND_UP_4(stream->width);
9232 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9233 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9234 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9237 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9238 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9240 for (i = 0; i < 3; i++) {
9241 src = mapinfo.data + src_offset[i];
9242 dest = thandle.ptr + dest_offset[i];
9247 for (j = 0; j < stream->height >> k; j++) {
9248 memcpy(dest, src, stream->width>>k);
9249 src += src_stride[i];
9250 dest += stream->stride[i];
9253 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9254 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9256 LOGE("Not support format %d", stream->format);
9260 tbm_bo_unmap(stream->bo[0]);
9261 gst_memory_unmap(mem, &mapinfo);
9267 tbm_bo_unmap(stream->bo[0]);
9270 gst_memory_unmap(mem, &mapinfo);
9276 __mmplayer_set_pause_state(mmplayer_t *player)
9278 if (player->sent_bos)
9281 /* rtsp case, get content attrs by GstMessage */
9282 if (MMPLAYER_IS_RTSP_STREAMING(player))
9285 /* it's first time to update all content attrs. */
9286 _mmplayer_update_content_attrs(player, ATTR_ALL);
9290 __mmplayer_set_playing_state(mmplayer_t *player)
9292 gchar *audio_codec = NULL;
9294 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9295 /* initialize because auto resume is done well. */
9296 player->resumed_by_rewind = FALSE;
9297 player->playback_rate = 1.0;
9300 if (player->sent_bos)
9303 /* try to get content metadata */
9305 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9306 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9307 * legacy mmfw-player api
9309 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9311 if ((player->cmd == MMPLAYER_COMMAND_START)
9312 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9313 __mmplayer_handle_missed_plugin(player);
9316 /* check audio codec field is set or not
9317 * we can get it from typefinder or codec's caps.
9319 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9321 /* The codec format can't be sent for audio only case like amr, mid etc.
9322 * Because, parser don't make related TAG.
9323 * So, if it's not set yet, fill it with found data.
9326 if (g_strrstr(player->type, "audio/midi"))
9327 audio_codec = "MIDI";
9328 else if (g_strrstr(player->type, "audio/x-amr"))
9329 audio_codec = "AMR";
9330 else if (g_strrstr(player->type, "audio/mpeg")
9331 && !g_strrstr(player->type, "mpegversion=(int)1"))
9332 audio_codec = "AAC";
9334 audio_codec = "unknown";
9336 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9338 if (mm_attrs_commit_all(player->attrs))
9339 LOGE("failed to update attributes");
9341 LOGD("set audio codec type with caps");