4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
214 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
218 count = gst_tag_list_get_tag_size(list, tag);
220 LOGD("count = %d", count);
222 for (i = 0; i < count; i++) {
225 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
226 if (!gst_tag_list_get_string_index(list, tag, i, &str))
227 g_assert_not_reached();
229 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
233 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
235 g_print(" : %s", str);
242 /* This function should be called after the pipeline goes PAUSED or higher
245 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
247 static gboolean has_duration = FALSE;
248 static gboolean has_video_attrs = FALSE;
249 static gboolean has_audio_attrs = FALSE;
250 static gboolean has_bitrate = FALSE;
251 gboolean missing_only = FALSE;
252 gboolean all = FALSE;
253 MMHandleType attrs = 0;
257 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
259 /* check player state here */
260 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
261 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
262 /* give warning now only */
263 LOGW("be careful. content attributes may not available in this state ");
266 /* get content attribute first */
267 attrs = MMPLAYER_GET_ATTRS(player);
269 LOGE("cannot get content attribute");
273 /* get update flag */
275 if (flag & ATTR_MISSING_ONLY) {
277 LOGD("updating missed attr only");
280 if (flag & ATTR_ALL) {
282 has_duration = FALSE;
283 has_video_attrs = FALSE;
284 has_audio_attrs = FALSE;
287 LOGD("updating all attrs");
290 if (missing_only && all) {
291 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
292 missing_only = FALSE;
295 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
296 has_duration = __mmplayer_update_duration_value(player);
298 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
299 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
301 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
302 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
304 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
305 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
308 if (mm_attrs_commit_all(attrs)) {
309 LOGE("failed to update attributes");
319 _mmplayer_get_stream_service_type(mmplayer_t *player)
321 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
325 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
327 player->pipeline->mainbin &&
328 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
329 STREAMING_SERVICE_NONE);
331 /* streaming service type if streaming */
332 if (!MMPLAYER_IS_STREAMING(player))
333 return STREAMING_SERVICE_NONE;
335 streaming_type = (player->duration == 0) ?
336 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
338 switch (streaming_type) {
339 case STREAMING_SERVICE_LIVE:
340 LOGD("it's live streaming");
342 case STREAMING_SERVICE_VOD:
343 LOGD("it's vod streaming");
346 LOGE("should not get here");
352 return streaming_type;
355 /* this function sets the player state and also report
356 * it to applicaton by calling callback function
359 _mmplayer_set_state(mmplayer_t *player, int state)
361 MMMessageParamType msg = {0, };
363 MMPLAYER_RETURN_IF_FAIL(player);
365 if (MMPLAYER_CURRENT_STATE(player) == state) {
366 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
367 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
371 /* update player states */
372 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
373 MMPLAYER_CURRENT_STATE(player) = state;
375 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
376 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
379 MMPLAYER_PRINT_STATE(player);
381 switch (MMPLAYER_CURRENT_STATE(player)) {
382 case MM_PLAYER_STATE_NULL:
383 case MM_PLAYER_STATE_READY:
385 case MM_PLAYER_STATE_PAUSED:
386 __mmplayer_set_pause_state(player);
388 case MM_PLAYER_STATE_PLAYING:
389 __mmplayer_set_playing_state(player);
391 case MM_PLAYER_STATE_NONE:
393 LOGW("invalid target state, there is nothing to do.");
398 /* post message to application */
399 if (MMPLAYER_TARGET_STATE(player) == state) {
400 /* fill the message with state of player */
401 msg.union_type = MM_MSG_UNION_STATE;
402 msg.state.previous = MMPLAYER_PREV_STATE(player);
403 msg.state.current = MMPLAYER_CURRENT_STATE(player);
405 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
407 /* state changed by resource callback */
408 if (player->interrupted_by_resource)
409 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
410 else /* state changed by usecase */
411 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
414 LOGD("intermediate state, do nothing.");
415 MMPLAYER_PRINT_STATE(player);
419 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
420 && !player->sent_bos) {
421 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
422 player->sent_bos = TRUE;
429 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
431 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
432 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
434 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
436 //LOGD("incomming command : %d ", command);
438 current_state = MMPLAYER_CURRENT_STATE(player);
439 pending_state = MMPLAYER_PENDING_STATE(player);
441 MMPLAYER_PRINT_STATE(player);
444 case MMPLAYER_COMMAND_CREATE:
446 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
448 if (current_state == MM_PLAYER_STATE_NULL ||
449 current_state == MM_PLAYER_STATE_READY ||
450 current_state == MM_PLAYER_STATE_PAUSED ||
451 current_state == MM_PLAYER_STATE_PLAYING)
456 case MMPLAYER_COMMAND_DESTROY:
458 /* destroy can called anytime */
460 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
464 case MMPLAYER_COMMAND_REALIZE:
466 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
468 if (pending_state != MM_PLAYER_STATE_NONE) {
471 /* need ready state to realize */
472 if (current_state == MM_PLAYER_STATE_READY)
475 if (current_state != MM_PLAYER_STATE_NULL)
481 case MMPLAYER_COMMAND_UNREALIZE:
483 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
485 if (current_state == MM_PLAYER_STATE_NULL)
490 case MMPLAYER_COMMAND_START:
492 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
494 if (pending_state == MM_PLAYER_STATE_NONE) {
495 if (current_state == MM_PLAYER_STATE_PLAYING)
497 else if (current_state != MM_PLAYER_STATE_READY &&
498 current_state != MM_PLAYER_STATE_PAUSED)
500 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
502 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
503 LOGD("player is going to paused state, just change the pending state as playing");
510 case MMPLAYER_COMMAND_STOP:
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
514 if (current_state == MM_PLAYER_STATE_READY)
517 /* need playing/paused state to stop */
518 if (current_state != MM_PLAYER_STATE_PLAYING &&
519 current_state != MM_PLAYER_STATE_PAUSED)
524 case MMPLAYER_COMMAND_PAUSE:
526 if (MMPLAYER_IS_LIVE_STREAMING(player))
529 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
530 goto NOT_COMPLETED_SEEK;
532 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
534 if (pending_state == MM_PLAYER_STATE_NONE) {
535 if (current_state == MM_PLAYER_STATE_PAUSED)
537 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
539 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
541 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
542 if (current_state == MM_PLAYER_STATE_PAUSED)
543 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
550 case MMPLAYER_COMMAND_RESUME:
552 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
553 goto NOT_COMPLETED_SEEK;
555 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
557 if (pending_state == MM_PLAYER_STATE_NONE) {
558 if (current_state == MM_PLAYER_STATE_PLAYING)
560 else if (current_state != MM_PLAYER_STATE_PAUSED)
562 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
564 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
565 LOGD("player is going to paused state, just change the pending state as playing");
575 player->cmd = command;
577 return MM_ERROR_NONE;
580 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
581 MMPLAYER_STATE_GET_NAME(current_state), command);
582 return MM_ERROR_PLAYER_INVALID_STATE;
585 LOGW("not completed seek");
586 return MM_ERROR_PLAYER_DOING_SEEK;
589 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
590 return MM_ERROR_PLAYER_NO_OP;
593 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
594 return MM_ERROR_PLAYER_NO_OP;
597 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
599 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
600 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
603 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
604 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
606 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
607 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
609 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
610 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
613 LOGE("invalid mmplayer resource type %d", type);
614 return MM_ERROR_PLAYER_INTERNAL;
617 if (player->hw_resource[type] != NULL) {
618 LOGD("[%d type] resource was already acquired", type);
619 return MM_ERROR_NONE;
622 LOGD("mark for acquire [%d type] resource", type);
623 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
624 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
625 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
626 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
627 return MM_ERROR_PLAYER_INTERNAL;
630 rm_ret = mm_resource_manager_commit(player->resource_manager);
631 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
632 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
633 return MM_ERROR_PLAYER_INTERNAL;
637 return MM_ERROR_NONE;
640 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
642 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
646 if (player->hw_resource[type] == NULL) {
647 LOGD("there is no acquired [%d type] resource", type);
648 return MM_ERROR_NONE;
651 LOGD("mark for release [%d type] resource", type);
652 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
653 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
654 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
655 return MM_ERROR_PLAYER_INTERNAL;
658 player->hw_resource[type] = NULL;
660 rm_ret = mm_resource_manager_commit(player->resource_manager);
661 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
662 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
663 return MM_ERROR_PLAYER_INTERNAL;
667 return MM_ERROR_NONE;
671 __mmplayer_initialize_gapless_play(mmplayer_t *player)
677 player->smooth_streaming = FALSE;
678 player->videodec_linked = 0;
679 player->audiodec_linked = 0;
680 player->textsink_linked = 0;
681 player->is_external_subtitle_present = FALSE;
682 player->is_external_subtitle_added_now = FALSE;
683 player->not_supported_codec = MISSING_PLUGIN_NONE;
684 player->can_support_codec = FOUND_PLUGIN_NONE;
685 player->pending_seek.is_pending = false;
686 player->pending_seek.pos = 0;
687 player->msg_posted = FALSE;
688 player->has_many_types = FALSE;
689 player->no_more_pad = FALSE;
690 player->not_found_demuxer = 0;
691 player->seek_state = MMPLAYER_SEEK_NONE;
692 player->is_subtitle_force_drop = FALSE;
693 player->play_subtitle = FALSE;
694 player->adjust_subtitle_pos = 0;
696 player->total_bitrate = 0;
697 player->total_maximum_bitrate = 0;
699 _mmplayer_track_initialize(player);
700 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
702 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
703 player->bitrate[i] = 0;
704 player->maximum_bitrate[i] = 0;
707 if (player->v_stream_caps) {
708 gst_caps_unref(player->v_stream_caps);
709 player->v_stream_caps = NULL;
712 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
714 /* clean found audio decoders */
715 if (player->audio_decoders) {
716 GList *a_dec = player->audio_decoders;
717 for (; a_dec; a_dec = g_list_next(a_dec)) {
718 gchar *name = a_dec->data;
719 MMPLAYER_FREEIF(name);
721 g_list_free(player->audio_decoders);
722 player->audio_decoders = NULL;
725 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
731 __mmplayer_gapless_play_thread(gpointer data)
733 mmplayer_t *player = (mmplayer_t *)data;
734 mmplayer_gst_element_t *mainbin = NULL;
736 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
738 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
739 while (!player->gapless_play_thread_exit) {
740 LOGD("gapless play thread started. waiting for signal.");
741 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
743 LOGD("reconfigure pipeline for gapless play.");
745 if (player->gapless_play_thread_exit) {
746 if (player->gapless.reconfigure) {
747 player->gapless.reconfigure = false;
748 MMPLAYER_PLAYBACK_UNLOCK(player);
750 LOGD("exiting gapless play thread");
754 mainbin = player->pipeline->mainbin;
756 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
757 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
758 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
759 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
760 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
762 /* Initialize Player values */
763 __mmplayer_initialize_gapless_play(player);
765 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
767 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
773 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
775 GSource *source = NULL;
779 source = g_main_context_find_source_by_id(context, source_id);
780 if (source != NULL) {
781 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
782 g_source_destroy(source);
789 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
791 mmplayer_t *player = (mmplayer_t *)hplayer;
792 GstMessage *msg = NULL;
793 GQueue *queue = NULL;
796 MMPLAYER_RETURN_IF_FAIL(player);
798 /* disconnecting bus watch */
799 if (player->bus_watcher)
800 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
801 player->bus_watcher = 0;
803 /* destroy the gst bus msg thread */
804 if (player->bus_msg_thread) {
805 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
806 player->bus_msg_thread_exit = TRUE;
807 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
808 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
810 LOGD("gst bus msg thread exit.");
811 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
812 player->bus_msg_thread = NULL;
814 g_mutex_clear(&player->bus_msg_thread_mutex);
815 g_cond_clear(&player->bus_msg_thread_cond);
818 g_mutex_lock(&player->bus_msg_q_lock);
819 queue = player->bus_msg_q;
820 while (!g_queue_is_empty(queue)) {
821 msg = (GstMessage *)g_queue_pop_head(queue);
826 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
827 gst_message_unref(msg);
829 g_mutex_unlock(&player->bus_msg_q_lock);
835 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
837 GstElement *parent = NULL;
839 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
840 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
843 MMPLAYER_FSINK_LOCK(player);
845 /* get parent of fakesink */
846 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
848 LOGD("fakesink already removed");
852 gst_element_set_locked_state(fakesink->gst, TRUE);
854 /* setting the state to NULL never returns async
855 * so no need to wait for completion of state transiton
857 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
858 LOGE("fakesink state change failure!");
859 /* FIXIT : should I return here? or try to proceed to next? */
862 /* remove fakesink from it's parent */
863 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
864 LOGE("failed to remove fakesink");
866 gst_object_unref(parent);
871 gst_object_unref(parent);
873 LOGD("state-holder removed");
875 gst_element_set_locked_state(fakesink->gst, FALSE);
877 MMPLAYER_FSINK_UNLOCK(player);
882 gst_element_set_locked_state(fakesink->gst, FALSE);
884 MMPLAYER_FSINK_UNLOCK(player);
888 static GstPadProbeReturn
889 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
891 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
892 return GST_PAD_PROBE_OK;
896 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
898 gint64 stop_running_time = 0;
899 gint64 position_running_time = 0;
903 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
904 if ((player->gapless.update_segment[idx] == TRUE) ||
905 !(player->selector[idx].event_probe_id)) {
906 /* LOGW("[%d] skip", idx); */
910 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
912 gst_segment_to_running_time(&player->gapless.segment[idx],
913 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
914 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
916 gst_segment_to_running_time(&player->gapless.segment[idx],
917 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
919 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
921 gst_segment_to_running_time(&player->gapless.segment[idx],
922 GST_FORMAT_TIME, player->duration);
925 position_running_time =
926 gst_segment_to_running_time(&player->gapless.segment[idx],
927 GST_FORMAT_TIME, player->gapless.segment[idx].position);
929 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
930 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
932 GST_TIME_ARGS(stop_running_time),
933 GST_TIME_ARGS(position_running_time),
934 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
935 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
937 position_running_time = MAX(position_running_time, stop_running_time);
938 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
939 GST_FORMAT_TIME, player->gapless.segment[idx].start);
940 position_running_time = MAX(0, position_running_time);
941 position = MAX(position, position_running_time);
945 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
946 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
947 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
949 player->gapless.start_time[stream_type] += position;
955 static GstPadProbeReturn
956 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
958 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
959 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
960 mmplayer_t *player = (mmplayer_t *)data;
961 GstCaps *caps = NULL;
962 GstStructure *str = NULL;
963 const gchar *name = NULL;
964 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
965 gboolean caps_ret = TRUE;
967 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
968 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
969 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
970 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
971 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
974 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
978 if (strstr(name, "audio")) {
979 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
980 } else if (strstr(name, "video")) {
981 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
983 /* text track is not supportable */
984 LOGE("invalid name %s", name);
988 switch (GST_EVENT_TYPE(event)) {
991 /* in case of gapless, drop eos event not to send it to sink */
992 if (player->gapless.reconfigure && !player->msg_posted) {
993 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
994 ret = GST_PAD_PROBE_DROP;
998 case GST_EVENT_STREAM_START:
1000 __mmplayer_gst_selector_update_start_time(player, stream_type);
1003 case GST_EVENT_FLUSH_STOP:
1005 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1006 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1007 player->gapless.start_time[stream_type] = 0;
1010 case GST_EVENT_SEGMENT:
1015 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1016 gst_event_copy_segment(event, &segment);
1018 if (segment.format != GST_FORMAT_TIME)
1021 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1022 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1023 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1024 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1025 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1026 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1028 /* keep the all the segment ev to cover the seeking */
1029 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1030 player->gapless.update_segment[stream_type] = TRUE;
1032 if (!player->gapless.running)
1035 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1037 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1039 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1040 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1041 gst_event_unref(event);
1042 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1048 gdouble proportion = 0.0;
1049 GstClockTimeDiff diff = 0;
1050 GstClockTime timestamp = 0;
1051 gint64 running_time_diff = -1;
1052 GstQOSType type = 0;
1053 GstEvent *tmpev = NULL;
1055 running_time_diff = player->gapless.segment[stream_type].base;
1057 if (running_time_diff <= 0) /* don't need to adjust */
1060 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1061 gst_event_unref(event);
1063 if (timestamp < running_time_diff) {
1064 LOGW("QOS event from previous group");
1065 ret = GST_PAD_PROBE_DROP;
1069 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1070 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1071 stream_type, GST_TIME_ARGS(timestamp),
1072 GST_TIME_ARGS(running_time_diff),
1073 GST_TIME_ARGS(timestamp - running_time_diff));
1075 timestamp -= running_time_diff;
1077 /* That case is invalid for QoS events */
1078 if (diff < 0 && -diff > timestamp) {
1079 LOGW("QOS event from previous group");
1080 ret = GST_PAD_PROBE_DROP;
1084 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1085 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1095 gst_caps_unref(caps);
1099 /* create fakesink for audio or video path witout audiobin or videobin */
1101 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1103 GstElement *pipeline = NULL;
1104 GstElement *fakesink = NULL;
1105 GstPad *sinkpad = NULL;
1108 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1110 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1113 fakesink = gst_element_factory_make("fakesink", NULL);
1114 if (fakesink == NULL) {
1115 LOGE("failed to create fakesink");
1119 /* store it as it's sink element */
1120 __mmplayer_add_sink(player, fakesink);
1122 gst_bin_add(GST_BIN(pipeline), fakesink);
1125 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1127 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1129 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1130 LOGE("failed to link fakesink");
1131 gst_object_unref(GST_OBJECT(fakesink));
1135 if (strstr(name, "video")) {
1136 if (player->v_stream_caps) {
1137 gst_caps_unref(player->v_stream_caps);
1138 player->v_stream_caps = NULL;
1140 if (player->ini.set_dump_element_flag)
1141 __mmplayer_add_dump_buffer_probe(player, fakesink);
1144 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1145 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1149 gst_object_unref(GST_OBJECT(sinkpad));
1156 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1158 GstElement *pipeline = NULL;
1159 GstElement *selector = NULL;
1160 GstPad *srcpad = NULL;
1163 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1165 selector = gst_element_factory_make("input-selector", NULL);
1167 LOGE("failed to create input-selector");
1170 g_object_set(selector, "sync-streams", TRUE, NULL);
1172 player->pipeline->mainbin[elem_idx].id = elem_idx;
1173 player->pipeline->mainbin[elem_idx].gst = selector;
1175 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1177 srcpad = gst_element_get_static_pad(selector, "src");
1179 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1180 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1181 __mmplayer_gst_selector_blocked, NULL, NULL);
1182 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1183 __mmplayer_gst_selector_event_probe, player, NULL);
1185 gst_element_set_state(selector, GST_STATE_PAUSED);
1187 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1188 gst_bin_add(GST_BIN(pipeline), selector);
1190 gst_object_unref(GST_OBJECT(srcpad));
1197 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1199 mmplayer_t *player = (mmplayer_t *)data;
1200 GstElement *selector = NULL;
1201 GstCaps *caps = NULL;
1202 GstStructure *str = NULL;
1203 const gchar *name = NULL;
1204 GstPad *sinkpad = NULL;
1205 gboolean first_track = FALSE;
1206 gboolean caps_ret = TRUE;
1208 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1209 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1212 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1213 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1215 LOGD("pad-added signal handling");
1217 /* get mimetype from caps */
1218 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1222 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1223 /* LOGD("detected mimetype : %s", name); */
1225 if (strstr(name, "video")) {
1227 gchar *caps_str = NULL;
1229 caps_str = gst_caps_to_string(caps);
1230 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1231 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1232 player->set_mode.video_zc = true;
1234 MMPLAYER_FREEIF(caps_str);
1236 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1237 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1239 LOGD("surface type : %d", stype);
1241 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1242 __mmplayer_gst_create_sinkbin(elem, pad, player);
1246 /* in case of exporting video frame, it requires the 360 video filter.
1247 * it will be handled in _no_more_pads(). */
1248 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1249 __mmplayer_gst_make_fakesink(player, pad, name);
1253 LOGD("video selector is required");
1254 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1255 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1256 } else if (strstr(name, "audio")) {
1257 gint samplerate = 0;
1260 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1261 if (player->build_audio_offload)
1262 player->no_more_pad = TRUE; /* remove state holder */
1263 __mmplayer_gst_create_sinkbin(elem, pad, player);
1267 gst_structure_get_int(str, "rate", &samplerate);
1268 gst_structure_get_int(str, "channels", &channels);
1270 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1271 __mmplayer_gst_make_fakesink(player, pad, name);
1275 LOGD("audio selector is required");
1276 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1277 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1279 } else if (strstr(name, "text")) {
1280 LOGD("text selector is required");
1281 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1282 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1284 LOGE("invalid caps info");
1288 /* check selector and create it */
1289 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1290 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1295 LOGD("input-selector is already created.");
1299 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1301 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1303 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1304 LOGE("failed to link selector");
1305 gst_object_unref(GST_OBJECT(selector));
1310 LOGD("this track will be activated");
1311 g_object_set(selector, "active-pad", sinkpad, NULL);
1314 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1320 gst_caps_unref(caps);
1323 gst_object_unref(GST_OBJECT(sinkpad));
1331 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1333 GstPad *srcpad = NULL;
1336 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1338 LOGD("type %d", type);
1341 LOGD("there is no %d track", type);
1345 srcpad = gst_element_get_static_pad(selector, "src");
1347 LOGE("failed to get srcpad from selector");
1351 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1353 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1355 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1356 if (player->selector[type].block_id) {
1357 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1358 player->selector[type].block_id = 0;
1362 gst_object_unref(GST_OBJECT(srcpad));
1371 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1373 MMHandleType attrs = 0;
1374 gint active_index = 0;
1377 MMPLAYER_RETURN_IF_FAIL(player);
1379 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1381 /* change track to active pad */
1382 active_index = player->selector[type].active_pad_index;
1383 if ((active_index != DEFAULT_TRACK) &&
1384 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1385 LOGW("failed to change %d type track to %d", type, active_index);
1386 player->selector[type].active_pad_index = DEFAULT_TRACK;
1390 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1391 attrs = MMPLAYER_GET_ATTRS(player);
1393 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1394 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1396 if (mm_attrs_commit_all(attrs))
1397 LOGW("failed to commit attrs.");
1399 LOGW("cannot get content attribute");
1408 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1411 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1413 if (!audio_selector) {
1414 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1416 /* in case the source is changed, output can be changed. */
1417 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1418 LOGD("remove previous audiobin if it exist");
1420 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1421 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1423 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1424 MMPLAYER_FREEIF(player->pipeline->audiobin);
1427 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1428 __mmplayer_pipeline_complete(NULL, player);
1433 /* apply the audio track information */
1434 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1436 /* create audio sink path */
1437 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1438 LOGE("failed to create audio sink path");
1447 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1450 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1452 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1453 LOGD("text path is not supproted");
1457 /* apply the text track information */
1458 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1460 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1461 player->has_closed_caption = TRUE;
1463 /* create text decode path */
1464 player->no_more_pad = TRUE;
1466 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1467 LOGE("failed to create text sink path");
1476 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1478 gint64 dur_bytes = 0L;
1481 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1482 player->pipeline->mainbin && player->streamer, FALSE);
1484 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1485 LOGE("fail to get duration.");
1487 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1488 * use file information was already set on Q2 when it was created. */
1489 _mm_player_streaming_set_queue2(player->streamer,
1490 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1491 TRUE, /* use_buffering */
1492 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1493 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1500 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1502 mmplayer_t *player = NULL;
1503 GstElement *video_selector = NULL;
1504 GstElement *audio_selector = NULL;
1505 GstElement *text_selector = NULL;
1508 player = (mmplayer_t *)data;
1510 LOGD("no-more-pad signal handling");
1512 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1513 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1514 LOGW("player is shutting down");
1518 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1519 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1520 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1521 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1522 LOGE("failed to set queue2 buffering");
1527 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1528 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1529 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1531 if (!video_selector && !audio_selector && !text_selector) {
1532 LOGW("there is no selector");
1533 player->no_more_pad = TRUE;
1537 /* create video path followed by video-select */
1538 if (video_selector && !audio_selector && !text_selector)
1539 player->no_more_pad = TRUE;
1541 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1544 /* create audio path followed by audio-select */
1545 if (audio_selector && !text_selector)
1546 player->no_more_pad = TRUE;
1548 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1551 /* create text path followed by text-select */
1552 __mmplayer_create_text_sink_path(player, text_selector);
1555 if (player->gapless.reconfigure) {
1556 player->gapless.reconfigure = FALSE;
1557 MMPLAYER_PLAYBACK_UNLOCK(player);
1564 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1566 gboolean ret = FALSE;
1567 GstElement *pipeline = NULL;
1568 GstPad *sinkpad = NULL;
1571 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1572 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1574 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1576 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1578 LOGE("failed to get pad from sinkbin");
1584 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1585 LOGE("failed to link sinkbin for reusing");
1586 goto EXIT; /* exit either pass or fail */
1590 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1591 LOGE("failed to set state(READY) to sinkbin");
1596 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1597 LOGE("failed to add sinkbin to pipeline");
1602 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1603 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1608 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1609 LOGE("failed to set state(PAUSED) to sinkbin");
1618 gst_object_unref(GST_OBJECT(sinkpad));
1626 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1628 mmplayer_t *player = NULL;
1629 GstCaps *caps = NULL;
1630 gchar *caps_str = NULL;
1631 GstStructure *str = NULL;
1632 const gchar *name = NULL;
1633 GstElement *sinkbin = NULL;
1634 gboolean reusing = FALSE;
1635 gboolean caps_ret = TRUE;
1636 gchar *sink_pad_name = "sink";
1639 player = (mmplayer_t *)data;
1642 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1643 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1645 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1649 caps_str = gst_caps_to_string(caps);
1651 /* LOGD("detected mimetype : %s", name); */
1652 if (strstr(name, "audio")) {
1653 if (player->pipeline->audiobin == NULL) {
1654 const gchar *audio_format = gst_structure_get_string(str, "format");
1656 LOGD("original audio format %s", audio_format);
1657 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1660 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1661 LOGE("failed to create audiobin. continuing without audio");
1665 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1666 LOGD("creating audiobin success");
1669 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1670 LOGD("reusing audiobin");
1671 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1673 } else if (strstr(name, "video")) {
1674 /* 1. zero copy is updated at _decode_pad_added()
1675 * 2. NULL surface type is handled in _decode_pad_added() */
1676 LOGD("zero copy %d", player->set_mode.video_zc);
1677 if (player->pipeline->videobin == NULL) {
1678 int surface_type = 0;
1679 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1680 LOGD("display_surface_type (%d)", surface_type);
1682 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1683 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1684 LOGE("failed to acquire video overlay resource");
1688 player->interrupted_by_resource = FALSE;
1690 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1691 LOGE("failed to create videobin. continuing without video");
1695 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1696 LOGD("creating videosink bin success");
1699 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1700 LOGD("re-using videobin");
1701 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1703 } else if (strstr(name, "text")) {
1704 if (player->pipeline->textbin == NULL) {
1705 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1706 LOGE("failed to create text sink bin. continuing without text");
1710 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1711 player->textsink_linked = 1;
1712 LOGD("creating textsink bin success");
1714 if (!player->textsink_linked) {
1715 LOGD("re-using textbin");
1717 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1718 player->textsink_linked = 1;
1720 /* linked textbin exist which means that the external subtitle path exist already */
1721 LOGW("ignoring internal subtutle since external subtitle is available");
1724 sink_pad_name = "text_sink";
1726 LOGW("unknown mime type %s, ignoring it", name);
1730 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1733 LOGD("[handle: %p] success to create and link sink bin", player);
1735 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1736 * streaming task. if the task blocked, then buffer will not flow to the next element
1737 *(autoplugging element). so this is special hack for streaming. please try to remove it
1739 /* dec stream count. we can remove fakesink if it's zero */
1740 if (player->num_dynamic_pad)
1741 player->num_dynamic_pad--;
1743 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1745 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1746 __mmplayer_pipeline_complete(NULL, player);
1750 MMPLAYER_FREEIF(caps_str);
1753 gst_caps_unref(caps);
1759 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1761 int required_angle = 0; /* Angle required for straight view */
1762 int rotation_angle = 0;
1764 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1765 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1767 /* Counter clockwise */
1768 switch (orientation) {
1773 required_angle = 270;
1776 required_angle = 180;
1779 required_angle = 90;
1783 rotation_angle = display_angle + required_angle;
1784 if (rotation_angle >= 360)
1785 rotation_angle -= 360;
1787 /* chech if supported or not */
1788 if (rotation_angle % 90) {
1789 LOGD("not supported rotation angle = %d", rotation_angle);
1793 switch (rotation_angle) {
1795 *value = MM_DISPLAY_ROTATION_NONE;
1798 *value = MM_DISPLAY_ROTATION_90;
1801 *value = MM_DISPLAY_ROTATION_180;
1804 *value = MM_DISPLAY_ROTATION_270;
1808 LOGD("setting rotation property value : %d", *value);
1814 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1816 /* check video sinkbin is created */
1817 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1819 player->pipeline->videobin &&
1820 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1821 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1822 MM_ERROR_PLAYER_NOT_INITIALIZED);
1824 return MM_ERROR_NONE;
1828 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1830 int display_rotation = 0;
1831 gchar *org_orient = NULL;
1832 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1835 LOGE("cannot get content attribute");
1836 return MM_ERROR_PLAYER_INTERNAL;
1839 if (display_angle) {
1840 /* update user roation */
1841 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1843 /* Counter clockwise */
1844 switch (display_rotation) {
1845 case MM_DISPLAY_ROTATION_NONE:
1848 case MM_DISPLAY_ROTATION_90:
1849 *display_angle = 90;
1851 case MM_DISPLAY_ROTATION_180:
1852 *display_angle = 180;
1854 case MM_DISPLAY_ROTATION_270:
1855 *display_angle = 270;
1858 LOGW("wrong angle type : %d", display_rotation);
1861 LOGD("check user angle: %d", *display_angle);
1865 /* Counter clockwise */
1866 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1869 if (!strcmp(org_orient, "rotate-90"))
1871 else if (!strcmp(org_orient, "rotate-180"))
1873 else if (!strcmp(org_orient, "rotate-270"))
1876 LOGD("original rotation is %s", org_orient);
1878 LOGD("content_video_orientation get fail");
1881 LOGD("check orientation: %d", *orientation);
1884 return MM_ERROR_NONE;
1888 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1890 int rotation_value = 0;
1891 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1892 int display_angle = 0;
1895 /* check video sinkbin is created */
1896 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1899 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1901 /* get rotation value to set */
1902 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1903 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1904 LOGD("set video param : rotate %d", rotation_value);
1908 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1910 MMHandleType attrs = 0;
1914 /* check video sinkbin is created */
1915 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1918 attrs = MMPLAYER_GET_ATTRS(player);
1919 MMPLAYER_RETURN_IF_FAIL(attrs);
1921 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1922 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1923 LOGD("set video param : visible %d", visible);
1927 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1929 MMHandleType attrs = 0;
1930 int display_method = 0;
1933 /* check video sinkbin is created */
1934 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1937 attrs = MMPLAYER_GET_ATTRS(player);
1938 MMPLAYER_RETURN_IF_FAIL(attrs);
1940 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1941 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1942 LOGD("set video param : method %d", display_method);
1946 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1948 MMHandleType attrs = 0;
1949 void *handle = NULL;
1952 /* check video sinkbin is created */
1953 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1954 LOGW("There is no video sink");
1958 attrs = MMPLAYER_GET_ATTRS(player);
1959 MMPLAYER_RETURN_IF_FAIL(attrs);
1960 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1962 gst_video_overlay_set_video_roi_area(
1963 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1964 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1965 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1966 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1971 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1973 MMHandleType attrs = 0;
1974 void *handle = NULL;
1978 int win_roi_width = 0;
1979 int win_roi_height = 0;
1982 /* check video sinkbin is created */
1983 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1984 LOGW("There is no video sink");
1988 attrs = MMPLAYER_GET_ATTRS(player);
1989 MMPLAYER_RETURN_IF_FAIL(attrs);
1991 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1994 /* It should be set after setting window */
1995 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1996 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1997 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1998 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
2000 /* After setting window handle, set display roi area */
2001 gst_video_overlay_set_display_roi_area(
2002 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2003 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2004 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2005 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2010 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2012 MMHandleType attrs = 0;
2013 void *handle = NULL;
2015 /* check video sinkbin is created */
2016 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2019 attrs = MMPLAYER_GET_ATTRS(player);
2020 MMPLAYER_RETURN_IF_FAIL(attrs);
2022 /* common case if using overlay surface */
2023 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2026 /* default is using wl_surface_id */
2027 unsigned int wl_surface_id = 0;
2028 wl_surface_id = *(int *)handle;
2029 LOGD("set video param : wl_surface_id %d", wl_surface_id);
2030 gst_video_overlay_set_wl_window_wl_surface_id(
2031 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2034 /* FIXIT : is it error case? */
2035 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2040 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2042 gboolean update_all_param = FALSE;
2045 /* check video sinkbin is created */
2046 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2047 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2049 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2050 LOGE("can not find tizenwlsink");
2051 return MM_ERROR_PLAYER_INTERNAL;
2054 LOGD("param_name : %s", param_name);
2055 if (!g_strcmp0(param_name, "update_all_param"))
2056 update_all_param = TRUE;
2058 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2059 __mmplayer_video_param_set_display_overlay(player);
2060 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2061 __mmplayer_video_param_set_display_method(player);
2062 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2063 __mmplayer_video_param_set_display_visible(player);
2064 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2065 __mmplayer_video_param_set_display_rotation(player);
2066 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2067 __mmplayer_video_param_set_roi_area(player);
2068 if (update_all_param)
2069 __mmplayer_video_param_set_video_roi_area(player);
2071 return MM_ERROR_NONE;
2075 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2077 MMHandleType attrs = 0;
2078 int surface_type = 0;
2079 int ret = MM_ERROR_NONE;
2083 /* check video sinkbin is created */
2084 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2085 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2087 attrs = MMPLAYER_GET_ATTRS(player);
2089 LOGE("cannot get content attribute");
2090 return MM_ERROR_PLAYER_INTERNAL;
2092 LOGD("param_name : %s", param_name);
2094 /* update display surface */
2095 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2096 LOGD("check display surface type attribute: %d", surface_type);
2098 /* configuring display */
2099 switch (surface_type) {
2100 case MM_DISPLAY_SURFACE_OVERLAY:
2102 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2103 if (ret != MM_ERROR_NONE)
2111 return MM_ERROR_NONE;
2115 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2117 gboolean disable_overlay = FALSE;
2118 mmplayer_t *player = (mmplayer_t *)hplayer;
2121 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2122 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2123 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2124 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2126 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2127 LOGW("Display control is not supported");
2128 return MM_ERROR_PLAYER_INTERNAL;
2131 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2133 if (audio_only == (bool)disable_overlay) {
2134 LOGE("It's the same with current setting: (%d)", audio_only);
2135 return MM_ERROR_NONE;
2139 LOGE("disable overlay");
2140 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2142 /* release overlay resource */
2143 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2144 LOGE("failed to release overlay resource");
2148 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2149 LOGE("failed to acquire video overlay resource");
2152 player->interrupted_by_resource = FALSE;
2154 LOGD("enable overlay");
2155 __mmplayer_video_param_set_display_overlay(player);
2156 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2161 return MM_ERROR_NONE;
2165 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2167 mmplayer_t *player = (mmplayer_t *)hplayer;
2168 gboolean disable_overlay = FALSE;
2172 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2173 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2174 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2175 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2176 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2178 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2179 LOGW("Display control is not supported");
2180 return MM_ERROR_PLAYER_INTERNAL;
2183 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2185 *paudio_only = (bool)disable_overlay;
2187 LOGD("audio_only : %d", *paudio_only);
2191 return MM_ERROR_NONE;
2195 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2197 GList *bucket = element_bucket;
2198 mmplayer_gst_element_t *element = NULL;
2199 mmplayer_gst_element_t *prv_element = NULL;
2200 GstElement *tee_element = NULL;
2201 gint successful_link_count = 0;
2205 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2207 prv_element = (mmplayer_gst_element_t *)bucket->data;
2208 bucket = bucket->next;
2210 for (; bucket; bucket = bucket->next) {
2211 element = (mmplayer_gst_element_t *)bucket->data;
2213 if (element && element->gst) {
2214 if (prv_element && prv_element->gst) {
2215 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2217 prv_element->gst = tee_element;
2219 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2220 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2221 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2225 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2226 LOGD("linking [%s] to [%s] success",
2227 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2228 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2229 successful_link_count++;
2230 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2231 LOGD("keep audio-tee element for next audio pipeline branch");
2232 tee_element = prv_element->gst;
2235 LOGD("linking [%s] to [%s] failed",
2236 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2237 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2243 prv_element = element;
2248 return successful_link_count;
2252 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2254 GList *bucket = element_bucket;
2255 mmplayer_gst_element_t *element = NULL;
2256 int successful_add_count = 0;
2260 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2261 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2263 for (; bucket; bucket = bucket->next) {
2264 element = (mmplayer_gst_element_t *)bucket->data;
2266 if (element && element->gst) {
2267 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2268 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2269 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2270 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2273 successful_add_count++;
2279 return successful_add_count;
2283 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2285 mmplayer_t *player = (mmplayer_t *)data;
2286 GstCaps *caps = NULL;
2287 GstStructure *str = NULL;
2289 gboolean caps_ret = TRUE;
2293 MMPLAYER_RETURN_IF_FAIL(pad);
2294 MMPLAYER_RETURN_IF_FAIL(unused);
2295 MMPLAYER_RETURN_IF_FAIL(data);
2297 caps = gst_pad_get_current_caps(pad);
2301 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2305 LOGD("name = %s", name);
2307 if (strstr(name, "audio")) {
2308 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2310 if (player->audio_stream_changed_cb) {
2311 LOGE("call the audio stream changed cb");
2312 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2314 } else if (strstr(name, "video")) {
2315 if ((name = gst_structure_get_string(str, "format")))
2316 player->set_mode.video_zc = name[0] == 'S';
2318 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2319 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2321 LOGW("invalid caps info");
2326 gst_caps_unref(caps);
2334 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2339 MMPLAYER_RETURN_IF_FAIL(player);
2341 if (player->audio_stream_buff_list) {
2342 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2343 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2346 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2347 __mmplayer_audio_stream_send_data(player, tmp);
2349 MMPLAYER_FREEIF(tmp->pcm_data);
2350 MMPLAYER_FREEIF(tmp);
2353 g_list_free(player->audio_stream_buff_list);
2354 player->audio_stream_buff_list = NULL;
2361 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2363 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2366 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2368 audio_stream.bitrate = a_buffer->bitrate;
2369 audio_stream.channel = a_buffer->channel;
2370 audio_stream.depth = a_buffer->depth;
2371 audio_stream.is_little_endian = a_buffer->is_little_endian;
2372 audio_stream.channel_mask = a_buffer->channel_mask;
2373 audio_stream.data_size = a_buffer->data_size;
2374 audio_stream.data = a_buffer->pcm_data;
2375 audio_stream.pcm_format = a_buffer->pcm_format;
2377 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2378 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2384 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2386 mmplayer_t *player = (mmplayer_t *)data;
2387 const gchar *pcm_format = NULL;
2391 gint endianness = 0;
2392 guint64 channel_mask = 0;
2393 void *a_data = NULL;
2395 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2396 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2400 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2402 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2403 a_data = mapinfo.data;
2404 a_size = mapinfo.size;
2406 GstCaps *caps = gst_pad_get_current_caps(pad);
2407 GstStructure *structure = gst_caps_get_structure(caps, 0);
2409 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2410 pcm_format = gst_structure_get_string(structure, "format");
2411 gst_structure_get_int(structure, "rate", &rate);
2412 gst_structure_get_int(structure, "channels", &channel);
2413 gst_structure_get_int(structure, "depth", &depth);
2414 gst_structure_get_int(structure, "endianness", &endianness);
2415 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2416 gst_caps_unref(GST_CAPS(caps));
2418 /* In case of the sync is false, use buffer list. *
2419 * The num of buffer list depends on the num of audio channels */
2420 if (player->audio_stream_buff_list) {
2421 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2422 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2424 if (channel_mask == tmp->channel_mask) {
2425 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2426 if (tmp->data_size + a_size < tmp->buff_size) {
2427 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2428 tmp->data_size += a_size;
2430 /* send data to client */
2431 __mmplayer_audio_stream_send_data(player, tmp);
2433 if (a_size > tmp->buff_size) {
2434 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2435 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2436 if (tmp->pcm_data == NULL) {
2437 LOGE("failed to realloc data.");
2440 tmp->buff_size = a_size;
2442 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2443 memcpy(tmp->pcm_data, a_data, a_size);
2444 tmp->data_size = a_size;
2449 LOGE("data is empty in list.");
2455 /* create new audio stream data for newly found audio channel */
2456 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2457 if (a_buffer == NULL) {
2458 LOGE("failed to alloc data.");
2461 a_buffer->bitrate = rate;
2462 a_buffer->channel = channel;
2463 a_buffer->depth = depth;
2464 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2465 a_buffer->channel_mask = channel_mask;
2466 a_buffer->data_size = a_size;
2467 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2469 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2470 /* If sync is FALSE, use buffer list to reduce the IPC. */
2471 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2472 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2473 if (a_buffer->pcm_data == NULL) {
2474 LOGE("failed to alloc data.");
2475 MMPLAYER_FREEIF(a_buffer);
2478 memcpy(a_buffer->pcm_data, a_data, a_size);
2479 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2480 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2482 /* If sync is TRUE, send data directly. */
2483 a_buffer->pcm_data = a_data;
2484 __mmplayer_audio_stream_send_data(player, a_buffer);
2485 MMPLAYER_FREEIF(a_buffer);
2489 gst_buffer_unmap(buffer, &mapinfo);
2494 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2496 mmplayer_t *player = (mmplayer_t *)data;
2497 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2498 GstPad *sinkpad = NULL;
2499 GstElement *queue = NULL, *sink = NULL;
2502 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2504 queue = gst_element_factory_make("queue", NULL);
2505 if (queue == NULL) {
2506 LOGD("fail make queue");
2510 sink = gst_element_factory_make("fakesink", NULL);
2512 LOGD("fail make fakesink");
2516 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2518 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2519 LOGW("failed to link queue & sink");
2523 sinkpad = gst_element_get_static_pad(queue, "sink");
2525 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2526 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2530 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2532 gst_object_unref(sinkpad);
2533 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2534 g_object_set(sink, "sync", TRUE, NULL);
2535 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2537 /* keep the first sink reference only */
2538 if (!audiobin[MMPLAYER_A_SINK].gst) {
2539 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2540 audiobin[MMPLAYER_A_SINK].gst = sink;
2543 gst_element_set_state(sink, GST_STATE_PAUSED);
2544 gst_element_set_state(queue, GST_STATE_PAUSED);
2546 _mmplayer_add_signal_connection(player,
2548 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2550 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2553 __mmplayer_add_sink(player, sink);
2559 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2561 gst_object_unref(GST_OBJECT(queue));
2565 gst_object_unref(GST_OBJECT(sink));
2569 gst_object_unref(GST_OBJECT(sinkpad));
2577 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2579 #define MAX_PROPS_LEN 128
2580 mmplayer_gst_element_t *audiobin = NULL;
2581 gint latency_mode = 0;
2582 gchar *stream_type = NULL;
2583 gchar *latency = NULL;
2585 gchar stream_props[MAX_PROPS_LEN] = {0,};
2586 GstStructure *props = NULL;
2589 * It should be set after player creation through attribute.
2590 * But, it can not be changed during playing.
2593 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2595 audiobin = player->pipeline->audiobin;
2597 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2598 if (player->sound.mute) {
2599 LOGD("mute enabled");
2600 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2603 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2604 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2607 snprintf(stream_props, sizeof(stream_props) - 1, "props,application.process.id.origin=%d", player->client_pid);
2609 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2610 stream_type, stream_id, player->client_pid);
2612 props = gst_structure_from_string(stream_props, NULL);
2613 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2614 LOGI("props result[%s].", stream_props);
2615 gst_structure_free(props);
2617 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2619 switch (latency_mode) {
2620 case AUDIO_LATENCY_MODE_LOW:
2621 latency = g_strndup("low", 3);
2623 case AUDIO_LATENCY_MODE_MID:
2624 latency = g_strndup("mid", 3);
2626 case AUDIO_LATENCY_MODE_HIGH:
2627 latency = g_strndup("high", 4);
2631 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2633 LOGD("audiosink property - latency=%s", latency);
2635 MMPLAYER_FREEIF(latency);
2641 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2643 mmplayer_gst_element_t *audiobin = NULL;
2646 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2648 audiobin = player->pipeline->audiobin;
2650 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2651 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2652 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2654 if (player->video360_yaw_radians <= M_PI &&
2655 player->video360_yaw_radians >= -M_PI &&
2656 player->video360_pitch_radians <= M_PI_2 &&
2657 player->video360_pitch_radians >= -M_PI_2) {
2658 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2659 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2660 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2661 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2662 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2663 "source-orientation-y", player->video360_metadata.init_view_heading,
2664 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2671 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2673 mmplayer_gst_element_t *audiobin = NULL;
2674 GstPad *sink_pad = NULL;
2675 GstCaps *acaps = NULL;
2677 int pitch_control = 0;
2678 double pitch_value = 1.0;
2681 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2682 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2684 audiobin = player->pipeline->audiobin;
2686 LOGD("make element for normal audio playback");
2688 /* audio bin structure for playback. {} means optional.
2689 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2691 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2692 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2695 /* for pitch control */
2696 mm_attrs_multiple_get(player->attrs, NULL,
2697 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2698 MM_PLAYER_PITCH_VALUE, &pitch_value,
2701 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2702 if (pitch_control && (player->videodec_linked == 0)) {
2703 GstElementFactory *factory;
2705 factory = gst_element_factory_find("pitch");
2707 gst_object_unref(factory);
2710 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2713 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2714 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2716 LOGW("there is no pitch element");
2721 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2723 /* replaygain volume */
2724 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2725 if (player->sound.rg_enable)
2726 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2728 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2731 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2733 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2734 /* currently, only openalsink uses volume element */
2735 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2736 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2738 if (player->sound.mute) {
2739 LOGD("mute enabled");
2740 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2744 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2746 /* audio effect element. if audio effect is enabled */
2747 if ((strcmp(player->ini.audioeffect_element, ""))
2749 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2750 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2752 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2754 if ((!player->bypass_audio_effect)
2755 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2756 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2757 if (!_mmplayer_audio_effect_custom_apply(player))
2758 LOGI("apply audio effect(custom) setting success");
2762 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2763 && (player->set_mode.rich_audio)) {
2764 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2768 /* create audio sink */
2769 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2770 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2771 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2773 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2774 if (player->is_360_feature_enabled &&
2775 player->is_content_spherical &&
2777 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2778 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2779 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2781 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2783 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2785 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2786 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2787 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2788 gst_caps_unref(acaps);
2790 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2792 player->is_openal_plugin_used = TRUE;
2794 if (player->is_360_feature_enabled && player->is_content_spherical)
2795 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2796 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2799 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2800 (player->videodec_linked && player->ini.use_system_clock)) {
2801 LOGD("system clock will be used.");
2802 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2805 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2806 __mmplayer_gst_set_pulsesink_property(player);
2807 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2808 __mmplayer_gst_set_openalsink_property(player);
2811 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2812 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2814 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2815 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2816 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2817 gst_object_unref(GST_OBJECT(sink_pad));
2819 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2822 return MM_ERROR_NONE;
2824 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2826 return MM_ERROR_PLAYER_INTERNAL;
2830 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2832 mmplayer_gst_element_t *audiobin = NULL;
2833 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2835 gchar *dst_format = NULL;
2837 int dst_samplerate = 0;
2838 int dst_channels = 0;
2839 GstCaps *caps = NULL;
2840 char *caps_str = NULL;
2843 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2844 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2846 audiobin = player->pipeline->audiobin;
2848 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2850 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2852 [case 1] extract interleave audio pcm without playback
2853 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2854 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2856 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2858 [case 2] deinterleave for each channel without playback
2859 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2860 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2862 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2863 - fakesink (sync or not)
2866 [case 3] [case 1(sync only)] + playback
2867 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2869 * src - ... - tee - queue1 - playback path
2870 - queue2 - [case1 pipeline with sync]
2872 [case 4] [case 2(sync only)] + playback
2873 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2875 * src - ... - tee - queue1 - playback path
2876 - queue2 - [case2 pipeline with sync]
2880 /* 1. create tee and playback path
2881 'tee' should be added at first to copy the decoded stream
2883 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2884 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2885 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2887 /* tee - path 1 : for playback path */
2888 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2889 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2891 /* tee - path 2 : for extract path */
2892 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2893 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2896 /* if there is tee, 'tee - path 2' is linked here */
2898 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2901 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2903 /* 2. decide the extract pcm format */
2904 mm_attrs_multiple_get(player->attrs, NULL,
2905 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2906 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2907 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2910 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2911 dst_format, dst_len, dst_samplerate, dst_channels);
2913 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2914 mm_attrs_multiple_get(player->attrs, NULL,
2915 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2916 "content_audio_samplerate", &dst_samplerate,
2917 "content_audio_channels", &dst_channels,
2920 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2921 dst_format, dst_len, dst_samplerate, dst_channels);
2923 /* If there is no enough information, set it to platform default value. */
2924 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2925 LOGD("set platform default format");
2926 dst_format = DEFAULT_PCM_OUT_FORMAT;
2928 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2929 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2932 /* 3. create capsfilter */
2933 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2934 caps = gst_caps_new_simple("audio/x-raw",
2935 "format", G_TYPE_STRING, dst_format,
2936 "rate", G_TYPE_INT, dst_samplerate,
2937 "channels", G_TYPE_INT, dst_channels,
2940 caps_str = gst_caps_to_string(caps);
2941 LOGD("new caps : %s", caps_str);
2943 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2946 gst_caps_unref(caps);
2947 MMPLAYER_FREEIF(caps_str);
2949 /* 4-1. create deinterleave to extract pcm for each channel */
2950 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2951 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2952 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2954 /* audiosink will be added after getting signal for each channel */
2955 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2956 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2958 /* 4-2. create fakesink to extract interlevaed pcm */
2959 LOGD("add audio fakesink for interleaved audio");
2960 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2961 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2962 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2963 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2965 _mmplayer_add_signal_connection(player,
2966 G_OBJECT(audiobin[extract_sink_id].gst),
2967 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2969 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2972 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2976 return MM_ERROR_NONE;
2978 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2980 return MM_ERROR_PLAYER_INTERNAL;
2984 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2986 int ret = MM_ERROR_NONE;
2987 mmplayer_gst_element_t *audiobin = NULL;
2988 GList *element_bucket = NULL;
2991 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2992 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2994 audiobin = player->pipeline->audiobin;
2996 if (player->build_audio_offload) { /* skip all the audio filters */
2997 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2999 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3000 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3001 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3003 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3007 /* FIXME: need to mention the supportable condition at API reference */
3008 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3009 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3011 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3013 if (ret != MM_ERROR_NONE)
3016 LOGD("success to make audio bin element");
3017 *bucket = element_bucket;
3020 return MM_ERROR_NONE;
3023 LOGE("failed to make audio bin element");
3024 g_list_free(element_bucket);
3028 return MM_ERROR_PLAYER_INTERNAL;
3032 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3034 mmplayer_gst_element_t *first_element = NULL;
3035 mmplayer_gst_element_t *audiobin = NULL;
3037 GstPad *ghostpad = NULL;
3038 GList *element_bucket = NULL;
3042 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3045 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3047 LOGE("failed to allocate memory for audiobin");
3048 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3052 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3053 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3054 if (!audiobin[MMPLAYER_A_BIN].gst) {
3055 LOGE("failed to create audiobin");
3060 player->pipeline->audiobin = audiobin;
3062 /* create audio filters and audiosink */
3063 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3066 /* adding created elements to bin */
3067 LOGD("adding created elements to bin");
3068 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3071 /* linking elements in the bucket by added order. */
3072 LOGD("Linking elements in the bucket by added order.");
3073 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3076 /* get first element's sinkpad for creating ghostpad */
3077 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3078 if (!first_element) {
3079 LOGE("failed to get first elem");
3083 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3085 LOGE("failed to get pad from first element of audiobin");
3089 ghostpad = gst_ghost_pad_new("sink", pad);
3091 LOGE("failed to create ghostpad");
3095 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3096 LOGE("failed to add ghostpad to audiobin");
3100 gst_object_unref(pad);
3102 g_list_free(element_bucket);
3105 return MM_ERROR_NONE;
3108 LOGD("ERROR : releasing audiobin");
3111 gst_object_unref(GST_OBJECT(pad));
3114 gst_object_unref(GST_OBJECT(ghostpad));
3117 g_list_free(element_bucket);
3119 /* release element which are not added to bin */
3120 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3121 /* NOTE : skip bin */
3122 if (audiobin[i].gst) {
3123 GstObject *parent = NULL;
3124 parent = gst_element_get_parent(audiobin[i].gst);
3127 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3128 audiobin[i].gst = NULL;
3130 gst_object_unref(GST_OBJECT(parent));
3134 /* release audiobin with it's childs */
3135 if (audiobin[MMPLAYER_A_BIN].gst)
3136 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3138 MMPLAYER_FREEIF(audiobin);
3140 player->pipeline->audiobin = NULL;
3142 return MM_ERROR_PLAYER_INTERNAL;
3146 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3148 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3152 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3154 int ret = MM_ERROR_NONE;
3156 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3157 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3159 MMPLAYER_VIDEO_BO_LOCK(player);
3161 if (player->video_bo_list) {
3162 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3163 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3164 if (tmp && tmp->bo == bo) {
3166 LOGD("release bo %p", bo);
3167 tbm_bo_unref(tmp->bo);
3168 MMPLAYER_VIDEO_BO_UNLOCK(player);
3169 MMPLAYER_VIDEO_BO_SIGNAL(player);
3174 /* hw codec is running or the list was reset for DRC. */
3175 LOGW("there is no bo list.");
3177 MMPLAYER_VIDEO_BO_UNLOCK(player);
3179 LOGW("failed to find bo %p", bo);
3184 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3189 MMPLAYER_RETURN_IF_FAIL(player);
3191 MMPLAYER_VIDEO_BO_LOCK(player);
3192 if (player->video_bo_list) {
3193 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3194 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3195 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3198 tbm_bo_unref(tmp->bo);
3202 g_list_free(player->video_bo_list);
3203 player->video_bo_list = NULL;
3205 player->video_bo_size = 0;
3206 MMPLAYER_VIDEO_BO_UNLOCK(player);
3213 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3216 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3217 gboolean ret = TRUE;
3219 /* check DRC, if it is, destroy the prev bo list to create again */
3220 if (player->video_bo_size != size) {
3221 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3222 __mmplayer_video_stream_destroy_bo_list(player);
3223 player->video_bo_size = size;
3226 MMPLAYER_VIDEO_BO_LOCK(player);
3228 if ((!player->video_bo_list) ||
3229 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3231 /* create bo list */
3233 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3235 if (player->video_bo_list) {
3236 /* if bo list did not created all, try it again. */
3237 idx = g_list_length(player->video_bo_list);
3238 LOGD("bo list exist(len: %d)", idx);
3241 for (; idx < player->ini.num_of_video_bo; idx++) {
3242 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3244 LOGE("Fail to alloc bo_info.");
3247 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3249 LOGE("Fail to tbm_bo_alloc.");
3250 MMPLAYER_FREEIF(bo_info);
3253 bo_info->used = FALSE;
3254 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3257 /* update video num buffers */
3258 LOGD("video_num_buffers : %d", idx);
3259 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3260 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3263 MMPLAYER_VIDEO_BO_UNLOCK(player);
3269 /* get bo from list*/
3270 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3271 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3272 if (tmp && (tmp->used == FALSE)) {
3273 LOGD("found bo %p to use", tmp->bo);
3275 MMPLAYER_VIDEO_BO_UNLOCK(player);
3276 return tbm_bo_ref(tmp->bo);
3280 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3281 MMPLAYER_VIDEO_BO_UNLOCK(player);
3285 if (player->ini.video_bo_timeout <= 0) {
3286 MMPLAYER_VIDEO_BO_WAIT(player);
3288 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3289 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3296 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3298 mmplayer_t *player = (mmplayer_t *)data;
3300 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3302 /* send prerolled pkt */
3303 player->video_stream_prerolled = false;
3305 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3307 /* not to send prerolled pkt again */
3308 player->video_stream_prerolled = true;
3312 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3314 mmplayer_t *player = (mmplayer_t *)data;
3315 mmplayer_video_decoded_data_info_t *stream = NULL;
3316 GstMemory *mem = NULL;
3319 MMPLAYER_RETURN_IF_FAIL(player);
3320 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3322 if (player->video_stream_prerolled) {
3323 player->video_stream_prerolled = false;
3324 LOGD("skip the prerolled pkt not to send it again");
3328 /* clear stream data structure */
3329 stream = __mmplayer_create_stream_from_pad(pad);
3331 LOGE("failed to alloc stream");
3335 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3337 /* set size and timestamp */
3338 mem = gst_buffer_peek_memory(buffer, 0);
3339 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3340 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3342 /* check zero-copy */
3343 if (player->set_mode.video_zc &&
3344 player->set_mode.video_export &&
3345 gst_is_tizen_memory(mem)) {
3346 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3347 stream->internal_buffer = gst_buffer_ref(buffer);
3348 } else { /* sw codec */
3349 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3352 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3356 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3357 LOGE("failed to send video decoded data.");
3364 LOGE("release video stream resource.");
3365 if (gst_is_tizen_memory(mem)) {
3367 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3369 tbm_bo_unref(stream->bo[i]);
3372 /* unref gst buffer */
3373 if (stream->internal_buffer)
3374 gst_buffer_unref(stream->internal_buffer);
3377 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3379 MMPLAYER_FREEIF(stream);
3384 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3386 mmplayer_gst_element_t *videobin = NULL;
3389 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3391 videobin = player->pipeline->videobin;
3393 /* Set spatial media metadata and/or user settings to the element.
3395 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3396 "projection-type", player->video360_metadata.projection_type, NULL);
3398 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3399 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3401 if (player->video360_metadata.full_pano_width_pixels &&
3402 player->video360_metadata.full_pano_height_pixels &&
3403 player->video360_metadata.cropped_area_image_width &&
3404 player->video360_metadata.cropped_area_image_height) {
3405 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3406 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3407 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3408 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3409 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3410 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3411 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3415 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3416 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3417 "horizontal-fov", player->video360_horizontal_fov,
3418 "vertical-fov", player->video360_vertical_fov, NULL);
3421 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3422 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3423 "zoom", 1.0f / player->video360_zoom, NULL);
3426 if (player->video360_yaw_radians <= M_PI &&
3427 player->video360_yaw_radians >= -M_PI &&
3428 player->video360_pitch_radians <= M_PI_2 &&
3429 player->video360_pitch_radians >= -M_PI_2) {
3430 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3431 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3432 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3433 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3434 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3435 "pose-yaw", player->video360_metadata.init_view_heading,
3436 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3439 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3440 "passthrough", !player->is_video360_enabled, NULL);
3447 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3449 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3450 GList *element_bucket = NULL;
3453 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3455 /* create video360 filter */
3456 if (player->is_360_feature_enabled && player->is_content_spherical) {
3457 LOGD("create video360 element");
3458 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3459 __mmplayer_gst_set_video360_property(player);
3463 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3464 LOGD("skip creating the videoconv and rotator");
3465 return MM_ERROR_NONE;
3468 /* in case of sw codec & overlay surface type, except 360 playback.
3469 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3470 LOGD("create video converter: %s", video_csc);
3471 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3474 *bucket = element_bucket;
3476 return MM_ERROR_NONE;
3478 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3479 g_list_free(element_bucket);
3483 return MM_ERROR_PLAYER_INTERNAL;
3487 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3489 gchar *factory_name = NULL;
3491 switch (surface_type) {
3492 case MM_DISPLAY_SURFACE_OVERLAY:
3493 if (strlen(player->ini.videosink_element_overlay) > 0)
3494 factory_name = player->ini.videosink_element_overlay;
3496 case MM_DISPLAY_SURFACE_REMOTE:
3497 case MM_DISPLAY_SURFACE_NULL:
3498 if (strlen(player->ini.videosink_element_fake) > 0)
3499 factory_name = player->ini.videosink_element_fake;
3502 LOGE("unidentified surface type");
3506 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3507 return factory_name;
3511 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3513 gchar *factory_name = NULL;
3514 mmplayer_gst_element_t *videobin = NULL;
3519 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3521 videobin = player->pipeline->videobin;
3522 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3524 attrs = MMPLAYER_GET_ATTRS(player);
3526 LOGE("cannot get content attribute");
3527 return MM_ERROR_PLAYER_INTERNAL;
3530 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3531 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3532 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3534 /* support shard memory with S/W codec on HawkP */
3535 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3536 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3537 "use-tbm", use_tbm, NULL);
3541 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3542 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3545 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3547 LOGD("disable last-sample");
3548 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3551 if (player->set_mode.video_export) {
3553 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3554 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3555 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3557 _mmplayer_add_signal_connection(player,
3558 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3559 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3561 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3564 _mmplayer_add_signal_connection(player,
3565 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3566 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3568 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3572 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3573 return MM_ERROR_PLAYER_INTERNAL;
3575 if (videobin[MMPLAYER_V_SINK].gst) {
3576 GstPad *sink_pad = NULL;
3577 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3579 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3580 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3581 gst_object_unref(GST_OBJECT(sink_pad));
3583 LOGE("failed to get sink pad from videosink");
3587 return MM_ERROR_NONE;
3592 * - video overlay surface(arm/x86) : tizenwlsink
3595 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3598 GList *element_bucket = NULL;
3599 mmplayer_gst_element_t *first_element = NULL;
3600 mmplayer_gst_element_t *videobin = NULL;
3601 gchar *videosink_factory_name = NULL;
3604 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3607 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3609 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3611 player->pipeline->videobin = videobin;
3614 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3615 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3616 if (!videobin[MMPLAYER_V_BIN].gst) {
3617 LOGE("failed to create videobin");
3621 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3624 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3625 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3627 /* additional setting for sink plug-in */
3628 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3629 LOGE("failed to set video property");
3633 /* store it as it's sink element */
3634 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3636 /* adding created elements to bin */
3637 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3638 LOGE("failed to add elements");
3642 /* Linking elements in the bucket by added order */
3643 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3644 LOGE("failed to link elements");
3648 /* get first element's sinkpad for creating ghostpad */
3649 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3650 if (!first_element) {
3651 LOGE("failed to get first element from bucket");
3655 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3657 LOGE("failed to get pad from first element");
3661 /* create ghostpad */
3662 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3663 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3664 LOGE("failed to add ghostpad to videobin");
3667 gst_object_unref(pad);
3669 /* done. free allocated variables */
3670 g_list_free(element_bucket);
3674 return MM_ERROR_NONE;
3677 LOGE("ERROR : releasing videobin");
3678 g_list_free(element_bucket);
3681 gst_object_unref(GST_OBJECT(pad));
3683 /* release videobin with it's childs */
3684 if (videobin[MMPLAYER_V_BIN].gst)
3685 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3687 MMPLAYER_FREEIF(videobin);
3688 player->pipeline->videobin = NULL;
3690 return MM_ERROR_PLAYER_INTERNAL;
3694 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3696 GList *element_bucket = NULL;
3697 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3699 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3700 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3701 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3702 "signal-handoffs", FALSE,
3705 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3706 _mmplayer_add_signal_connection(player,
3707 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3708 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3710 G_CALLBACK(__mmplayer_update_subtitle),
3713 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3714 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3716 if (!player->play_subtitle) {
3717 LOGD("add textbin sink as sink element of whole pipeline.");
3718 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3721 /* adding created elements to bin */
3722 LOGD("adding created elements to bin");
3723 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3724 LOGE("failed to add elements");
3728 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3729 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3730 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3732 /* linking elements in the bucket by added order. */
3733 LOGD("Linking elements in the bucket by added order.");
3734 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3735 LOGE("failed to link elements");
3739 /* done. free allocated variables */
3740 g_list_free(element_bucket);
3742 if (textbin[MMPLAYER_T_QUEUE].gst) {
3744 GstPad *ghostpad = NULL;
3746 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3748 LOGE("failed to get sink pad of text queue");
3752 ghostpad = gst_ghost_pad_new("text_sink", pad);
3753 gst_object_unref(pad);
3756 LOGE("failed to create ghostpad of textbin");
3760 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3761 LOGE("failed to add ghostpad to textbin");
3762 gst_object_unref(ghostpad);
3767 return MM_ERROR_NONE;
3770 g_list_free(element_bucket);
3772 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3773 LOGE("remove textbin sink from sink list");
3774 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3777 /* release element at __mmplayer_gst_create_text_sink_bin */
3778 return MM_ERROR_PLAYER_INTERNAL;
3782 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3784 mmplayer_gst_element_t *textbin = NULL;
3785 GList *element_bucket = NULL;
3786 int surface_type = 0;
3791 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3794 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3796 LOGE("failed to allocate memory for textbin");
3797 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3801 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3802 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3803 if (!textbin[MMPLAYER_T_BIN].gst) {
3804 LOGE("failed to create textbin");
3809 player->pipeline->textbin = textbin;
3812 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3813 LOGD("surface type for subtitle : %d", surface_type);
3814 switch (surface_type) {
3815 case MM_DISPLAY_SURFACE_OVERLAY:
3816 case MM_DISPLAY_SURFACE_NULL:
3817 case MM_DISPLAY_SURFACE_REMOTE:
3818 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3819 LOGE("failed to make plain text elements");
3830 return MM_ERROR_NONE;
3834 LOGD("ERROR : releasing textbin");
3836 g_list_free(element_bucket);
3838 /* release signal */
3839 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3841 /* release element which are not added to bin */
3842 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3843 /* NOTE : skip bin */
3844 if (textbin[i].gst) {
3845 GstObject *parent = NULL;
3846 parent = gst_element_get_parent(textbin[i].gst);
3849 gst_object_unref(GST_OBJECT(textbin[i].gst));
3850 textbin[i].gst = NULL;
3852 gst_object_unref(GST_OBJECT(parent));
3857 /* release textbin with it's childs */
3858 if (textbin[MMPLAYER_T_BIN].gst)
3859 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3861 MMPLAYER_FREEIF(player->pipeline->textbin);
3862 player->pipeline->textbin = NULL;
3865 return MM_ERROR_PLAYER_INTERNAL;
3869 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3871 mmplayer_gst_element_t *mainbin = NULL;
3872 mmplayer_gst_element_t *textbin = NULL;
3873 MMHandleType attrs = 0;
3874 GstElement *subsrc = NULL;
3875 GstElement *subparse = NULL;
3876 gchar *subtitle_uri = NULL;
3877 const gchar *charset = NULL;
3883 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3885 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3887 mainbin = player->pipeline->mainbin;
3889 attrs = MMPLAYER_GET_ATTRS(player);
3891 LOGE("cannot get content attribute");
3892 return MM_ERROR_PLAYER_INTERNAL;
3895 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3896 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3897 LOGE("subtitle uri is not proper filepath.");
3898 return MM_ERROR_PLAYER_INVALID_URI;
3901 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3902 LOGE("failed to get storage info of subtitle path");
3903 return MM_ERROR_PLAYER_INVALID_URI;
3906 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3908 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3909 player->subtitle_language_list = NULL;
3910 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3912 /* create the subtitle source */
3913 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3915 LOGE("failed to create filesrc element");
3918 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3920 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3921 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3923 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3924 LOGW("failed to add queue");
3925 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3926 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3927 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3932 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3934 LOGE("failed to create subparse element");
3938 charset = _mmplayer_get_charset(subtitle_uri);
3940 LOGD("detected charset is %s", charset);
3941 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3944 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3945 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3947 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3948 LOGW("failed to add subparse");
3949 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3950 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3951 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3955 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3956 LOGW("failed to link subsrc and subparse");
3960 player->play_subtitle = TRUE;
3961 player->adjust_subtitle_pos = 0;
3963 LOGD("play subtitle using subtitle file");
3965 if (player->pipeline->textbin == NULL) {
3966 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3967 LOGE("failed to create text sink bin. continuing without text");
3971 textbin = player->pipeline->textbin;
3973 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3974 LOGW("failed to add textbin");
3976 /* release signal */
3977 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3979 /* release textbin with it's childs */
3980 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3981 MMPLAYER_FREEIF(player->pipeline->textbin);
3982 player->pipeline->textbin = textbin = NULL;
3986 LOGD("link text input selector and textbin ghost pad");
3988 player->textsink_linked = 1;
3989 player->external_text_idx = 0;
3990 LOGI("textsink is linked");
3992 textbin = player->pipeline->textbin;
3993 LOGD("text bin has been created. reuse it.");
3994 player->external_text_idx = 1;
3997 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3998 LOGW("failed to link subparse and textbin");
4002 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4004 LOGE("failed to get sink pad from textsink to probe data");
4008 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4009 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4011 gst_object_unref(pad);
4014 /* create dot. for debugging */
4015 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4018 return MM_ERROR_NONE;
4021 /* release text pipeline resource */
4022 player->textsink_linked = 0;
4024 /* release signal */
4025 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4027 if (player->pipeline->textbin) {
4028 LOGE("remove textbin");
4030 /* release textbin with it's childs */
4031 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4032 MMPLAYER_FREEIF(player->pipeline->textbin);
4033 player->pipeline->textbin = NULL;
4037 /* release subtitle elem */
4038 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4039 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4041 return MM_ERROR_PLAYER_INTERNAL;
4045 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4047 mmplayer_t *player = (mmplayer_t *)data;
4048 MMMessageParamType msg = {0, };
4049 GstClockTime duration = 0;
4050 gpointer text = NULL;
4051 guint text_size = 0;
4052 gboolean ret = TRUE;
4053 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4057 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4058 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4060 if (player->is_subtitle_force_drop) {
4061 LOGW("subtitle is dropped forcedly.");
4065 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4066 text = mapinfo.data;
4067 text_size = mapinfo.size;
4069 if (player->set_mode.subtitle_off) {
4070 LOGD("subtitle is OFF.");
4074 if (!text || (text_size == 0)) {
4075 LOGD("There is no subtitle to be displayed.");
4079 msg.data = (void *)text;
4081 duration = GST_BUFFER_DURATION(buffer);
4083 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4084 if (player->duration > GST_BUFFER_PTS(buffer))
4085 duration = player->duration - GST_BUFFER_PTS(buffer);
4088 LOGI("subtitle duration is invalid, subtitle duration change "
4089 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4091 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4093 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4095 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4096 gst_buffer_unmap(buffer, &mapinfo);
4103 static GstPadProbeReturn
4104 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4106 mmplayer_t *player = (mmplayer_t *)u_data;
4107 GstClockTime cur_timestamp = 0;
4108 gint64 adjusted_timestamp = 0;
4109 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4111 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4113 if (player->set_mode.subtitle_off) {
4114 LOGD("subtitle is OFF.");
4118 if (player->adjust_subtitle_pos == 0) {
4119 LOGD("nothing to do");
4123 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4124 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4126 if (adjusted_timestamp < 0) {
4127 LOGD("adjusted_timestamp under zero");
4132 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4133 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4134 GST_TIME_ARGS(cur_timestamp),
4135 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4137 return GST_PAD_PROBE_OK;
4141 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4145 /* check player and subtitlebin are created */
4146 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4147 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4149 if (position == 0) {
4150 LOGD("nothing to do");
4152 return MM_ERROR_NONE;
4155 /* check current postion */
4156 player->adjust_subtitle_pos = position;
4158 LOGD("save adjust_subtitle_pos in player");
4162 return MM_ERROR_NONE;
4166 * This function is to create audio or video pipeline for playing.
4168 * @param player [in] handle of player
4170 * @return This function returns zero on success.
4175 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4177 int ret = MM_ERROR_NONE;
4178 mmplayer_gst_element_t *mainbin = NULL;
4179 MMHandleType attrs = 0;
4182 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4184 /* get profile attribute */
4185 attrs = MMPLAYER_GET_ATTRS(player);
4187 LOGE("failed to get content attribute");
4191 /* create pipeline handles */
4192 if (player->pipeline) {
4193 LOGE("pipeline should be released before create new one");
4197 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4198 if (player->pipeline == NULL)
4201 /* create mainbin */
4202 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4203 if (mainbin == NULL)
4206 /* create pipeline */
4207 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4208 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4209 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4210 LOGE("failed to create pipeline");
4215 player->pipeline->mainbin = mainbin;
4217 /* create the source and decoder elements */
4218 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4219 ret = _mmplayer_gst_build_es_pipeline(player);
4221 ret = _mmplayer_gst_build_pipeline(player);
4223 if (ret != MM_ERROR_NONE) {
4224 LOGE("failed to create some elements");
4228 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4229 if (__mmplayer_check_subtitle(player)
4230 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4231 LOGE("failed to create text pipeline");
4234 ret = _mmplayer_gst_add_bus_watch(player);
4235 if (ret != MM_ERROR_NONE) {
4236 LOGE("failed to add bus watch");
4241 return MM_ERROR_NONE;
4244 __mmplayer_gst_destroy_pipeline(player);
4245 return MM_ERROR_PLAYER_INTERNAL;
4249 __mmplayer_reset_gapless_state(mmplayer_t *player)
4252 MMPLAYER_RETURN_IF_FAIL(player
4254 && player->pipeline->audiobin
4255 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4257 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4264 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4267 int ret = MM_ERROR_NONE;
4271 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4273 /* cleanup stuffs */
4274 MMPLAYER_FREEIF(player->type);
4275 player->no_more_pad = FALSE;
4276 player->num_dynamic_pad = 0;
4277 player->demux_pad_index = 0;
4279 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4280 player->subtitle_language_list = NULL;
4281 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4283 __mmplayer_reset_gapless_state(player);
4285 if (player->streamer) {
4286 _mm_player_streaming_initialize(player->streamer, FALSE);
4287 _mm_player_streaming_destroy(player->streamer);
4288 player->streamer = NULL;
4291 /* cleanup unlinked mime type */
4292 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4293 MMPLAYER_FREEIF(player->unlinked_video_mime);
4294 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4296 /* cleanup running stuffs */
4297 _mmplayer_cancel_eos_timer(player);
4299 /* cleanup gst stuffs */
4300 if (player->pipeline) {
4301 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4302 GstTagList *tag_list = player->pipeline->tag_list;
4304 /* first we need to disconnect all signal hander */
4305 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4308 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4309 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4310 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4311 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4312 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4313 gst_object_unref(bus);
4315 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4316 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4317 if (ret != MM_ERROR_NONE) {
4318 LOGE("fail to change state to NULL");
4319 return MM_ERROR_PLAYER_INTERNAL;
4322 LOGW("succeeded in changing state to NULL");
4324 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4327 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4328 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4330 /* free avsysaudiosink
4331 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4332 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4334 MMPLAYER_FREEIF(audiobin);
4335 MMPLAYER_FREEIF(videobin);
4336 MMPLAYER_FREEIF(textbin);
4337 MMPLAYER_FREEIF(mainbin);
4341 gst_tag_list_unref(tag_list);
4343 MMPLAYER_FREEIF(player->pipeline);
4345 MMPLAYER_FREEIF(player->album_art);
4347 if (player->v_stream_caps) {
4348 gst_caps_unref(player->v_stream_caps);
4349 player->v_stream_caps = NULL;
4352 if (player->a_stream_caps) {
4353 gst_caps_unref(player->a_stream_caps);
4354 player->a_stream_caps = NULL;
4357 if (player->s_stream_caps) {
4358 gst_caps_unref(player->s_stream_caps);
4359 player->s_stream_caps = NULL;
4361 _mmplayer_track_destroy(player);
4363 if (player->sink_elements)
4364 g_list_free(player->sink_elements);
4365 player->sink_elements = NULL;
4367 if (player->bufmgr) {
4368 tbm_bufmgr_deinit(player->bufmgr);
4369 player->bufmgr = NULL;
4372 LOGW("finished destroy pipeline");
4380 __mmplayer_gst_realize(mmplayer_t *player)
4383 int ret = MM_ERROR_NONE;
4387 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4389 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4391 ret = __mmplayer_gst_create_pipeline(player);
4393 LOGE("failed to create pipeline");
4397 /* set pipeline state to READY */
4398 /* NOTE : state change to READY must be performed sync. */
4399 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4400 ret = _mmplayer_gst_set_state(player,
4401 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4403 if (ret != MM_ERROR_NONE) {
4404 /* return error if failed to set state */
4405 LOGE("failed to set READY state");
4409 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4411 /* create dot before error-return. for debugging */
4412 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4420 __mmplayer_gst_unrealize(mmplayer_t *player)
4422 int ret = MM_ERROR_NONE;
4426 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4428 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4429 MMPLAYER_PRINT_STATE(player);
4431 /* release miscellaneous information */
4432 __mmplayer_release_misc(player);
4434 /* destroy pipeline */
4435 ret = __mmplayer_gst_destroy_pipeline(player);
4436 if (ret != MM_ERROR_NONE) {
4437 LOGE("failed to destory pipeline");
4441 /* release miscellaneous information.
4442 these info needs to be released after pipeline is destroyed. */
4443 __mmplayer_release_misc_post(player);
4445 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4453 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4458 LOGW("set_message_callback is called with invalid player handle");
4459 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4462 player->msg_cb = callback;
4463 player->msg_cb_param = user_param;
4465 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4469 return MM_ERROR_NONE;
4473 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4475 int ret = MM_ERROR_NONE;
4480 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4481 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4482 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4484 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4486 if (strstr(uri, "es_buff://")) {
4487 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4488 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4489 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4490 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4492 tmp = g_ascii_strdown(uri, strlen(uri));
4493 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4494 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4496 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4498 } else if (strstr(uri, "mms://")) {
4499 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4500 } else if ((path = strstr(uri, "mem://"))) {
4501 ret = __mmplayer_set_mem_uri(data, path, param);
4503 ret = __mmplayer_set_file_uri(data, uri);
4506 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4507 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4508 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4509 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4511 /* dump parse result */
4512 SECURE_LOGW("incoming uri : %s", uri);
4513 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4514 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4522 __mmplayer_can_do_interrupt(mmplayer_t *player)
4524 if (!player || !player->pipeline || !player->attrs) {
4525 LOGW("not initialized");
4529 if (player->audio_decoded_cb) {
4530 LOGW("not support in pcm extraction mode");
4534 /* check if seeking */
4535 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4536 MMMessageParamType msg_param;
4537 memset(&msg_param, 0, sizeof(MMMessageParamType));
4538 msg_param.code = MM_ERROR_PLAYER_SEEK;
4539 player->seek_state = MMPLAYER_SEEK_NONE;
4540 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4544 /* check other thread */
4545 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4546 LOGW("locked already, cmd state : %d", player->cmd);
4548 /* check application command */
4549 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4550 LOGW("playing.. should wait cmd lock then, will be interrupted");
4552 /* lock will be released at mrp_resource_release_cb() */
4553 MMPLAYER_CMD_LOCK(player);
4556 LOGW("nothing to do");
4559 LOGW("can interrupt immediately");
4563 FAILED: /* with CMD UNLOCKED */
4566 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4571 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4574 mmplayer_t *player = NULL;
4575 MMMessageParamType msg = {0, };
4577 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4582 LOGE("user_data is null");
4585 player = (mmplayer_t *)user_data;
4587 if (!__mmplayer_can_do_interrupt(player)) {
4588 LOGW("no need to interrupt, so leave");
4589 /* FIXME: there is no way to avoid releasing resource. */
4593 player->interrupted_by_resource = TRUE;
4595 /* get last play position */
4596 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4597 msg.union_type = MM_MSG_UNION_TIME;
4598 msg.time.elapsed = pos;
4599 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4601 LOGW("failed to get play position.");
4604 LOGD("video resource conflict so, resource will be freed by unrealizing");
4605 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4606 LOGE("failed to unrealize");
4608 /* lock is called in __mmplayer_can_do_interrupt() */
4609 MMPLAYER_CMD_UNLOCK(player);
4611 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4612 player->hw_resource[res_idx] = NULL;
4616 return TRUE; /* release all the resources */
4620 __mmplayer_initialize_video_roi(mmplayer_t *player)
4622 player->video_roi.scale_x = 0.0;
4623 player->video_roi.scale_y = 0.0;
4624 player->video_roi.scale_width = 1.0;
4625 player->video_roi.scale_height = 1.0;
4629 _mmplayer_create_player(MMHandleType handle)
4631 int ret = MM_ERROR_PLAYER_INTERNAL;
4632 bool enabled = false;
4634 mmplayer_t *player = MM_PLAYER_CAST(handle);
4638 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4640 /* initialize player state */
4641 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4642 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4643 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4644 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4646 /* check current state */
4647 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4649 /* construct attributes */
4650 player->attrs = _mmplayer_construct_attribute(handle);
4652 if (!player->attrs) {
4653 LOGE("Failed to construct attributes");
4657 /* initialize gstreamer with configured parameter */
4658 if (!__mmplayer_init_gstreamer(player)) {
4659 LOGE("Initializing gstreamer failed");
4660 _mmplayer_deconstruct_attribute(handle);
4664 /* create lock. note that g_tread_init() has already called in gst_init() */
4665 g_mutex_init(&player->fsink_lock);
4667 /* create update tag lock */
4668 g_mutex_init(&player->update_tag_lock);
4670 /* create gapless play mutex */
4671 g_mutex_init(&player->gapless_play_thread_mutex);
4673 /* create gapless play cond */
4674 g_cond_init(&player->gapless_play_thread_cond);
4676 /* create gapless play thread */
4677 player->gapless_play_thread =
4678 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4679 if (!player->gapless_play_thread) {
4680 LOGE("failed to create gapless play thread");
4681 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4682 g_mutex_clear(&player->gapless_play_thread_mutex);
4683 g_cond_clear(&player->gapless_play_thread_cond);
4687 player->bus_msg_q = g_queue_new();
4688 if (!player->bus_msg_q) {
4689 LOGE("failed to create queue for bus_msg");
4690 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4694 ret = _mmplayer_initialize_video_capture(player);
4695 if (ret != MM_ERROR_NONE) {
4696 LOGE("failed to initialize video capture");
4700 /* initialize resource manager */
4701 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4702 __resource_release_cb, player, &player->resource_manager)
4703 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4704 LOGE("failed to initialize resource manager");
4705 ret = MM_ERROR_PLAYER_INTERNAL;
4709 /* create video bo lock and cond */
4710 g_mutex_init(&player->video_bo_mutex);
4711 g_cond_init(&player->video_bo_cond);
4713 /* create subtitle info lock and cond */
4714 g_mutex_init(&player->subtitle_info_mutex);
4715 g_cond_init(&player->subtitle_info_cond);
4717 player->streaming_type = STREAMING_SERVICE_NONE;
4719 /* give default value of audio effect setting */
4720 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4721 player->sound.rg_enable = false;
4722 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4724 player->play_subtitle = FALSE;
4725 player->has_closed_caption = FALSE;
4726 player->pending_resume = FALSE;
4727 if (player->ini.dump_element_keyword[0][0] == '\0')
4728 player->ini.set_dump_element_flag = FALSE;
4730 player->ini.set_dump_element_flag = TRUE;
4732 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4733 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4734 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4736 /* Set video360 settings to their defaults for just-created player.
4739 player->is_360_feature_enabled = FALSE;
4740 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4741 LOGI("spherical feature info: %d", enabled);
4743 player->is_360_feature_enabled = TRUE;
4745 LOGE("failed to get spherical feature info");
4748 player->is_content_spherical = FALSE;
4749 player->is_video360_enabled = TRUE;
4750 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4751 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4752 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4753 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4754 player->video360_zoom = 1.0f;
4755 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4756 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4758 __mmplayer_initialize_video_roi(player);
4760 /* set player state to null */
4761 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4762 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4766 return MM_ERROR_NONE;
4770 g_mutex_clear(&player->fsink_lock);
4771 /* free update tag lock */
4772 g_mutex_clear(&player->update_tag_lock);
4773 g_queue_free(player->bus_msg_q);
4774 player->bus_msg_q = NULL;
4775 /* free gapless play thread */
4776 if (player->gapless_play_thread) {
4777 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4778 player->gapless_play_thread_exit = TRUE;
4779 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4780 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4782 g_thread_join(player->gapless_play_thread);
4783 player->gapless_play_thread = NULL;
4785 g_mutex_clear(&player->gapless_play_thread_mutex);
4786 g_cond_clear(&player->gapless_play_thread_cond);
4789 /* release attributes */
4790 _mmplayer_deconstruct_attribute(handle);
4798 __mmplayer_init_gstreamer(mmplayer_t *player)
4800 static gboolean initialized = FALSE;
4801 static const int max_argc = 50;
4803 gchar **argv = NULL;
4804 gchar **argv2 = NULL;
4810 LOGD("gstreamer already initialized.");
4815 argc = malloc(sizeof(int));
4816 argv = malloc(sizeof(gchar *) * max_argc);
4817 argv2 = malloc(sizeof(gchar *) * max_argc);
4819 if (!argc || !argv || !argv2)
4822 memset(argv, 0, sizeof(gchar *) * max_argc);
4823 memset(argv2, 0, sizeof(gchar *) * max_argc);
4827 argv[0] = g_strdup("mmplayer");
4830 for (i = 0; i < 5; i++) {
4831 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4832 if (strlen(player->ini.gst_param[i]) > 0) {
4833 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4838 /* we would not do fork for scanning plugins */
4839 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4842 /* check disable registry scan */
4843 if (player->ini.skip_rescan) {
4844 argv[*argc] = g_strdup("--gst-disable-registry-update");
4848 /* check disable segtrap */
4849 if (player->ini.disable_segtrap) {
4850 argv[*argc] = g_strdup("--gst-disable-segtrap");
4854 LOGD("initializing gstreamer with following parameter");
4855 LOGD("argc : %d", *argc);
4858 for (i = 0; i < arg_count; i++) {
4860 LOGD("argv[%d] : %s", i, argv2[i]);
4863 /* initializing gstreamer */
4864 if (!gst_init_check(argc, &argv, &err)) {
4865 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4872 for (i = 0; i < arg_count; i++) {
4873 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4874 MMPLAYER_FREEIF(argv2[i]);
4877 MMPLAYER_FREEIF(argv);
4878 MMPLAYER_FREEIF(argv2);
4879 MMPLAYER_FREEIF(argc);
4889 for (i = 0; i < arg_count; i++) {
4890 LOGD("free[%d] : %s", i, argv2[i]);
4891 MMPLAYER_FREEIF(argv2[i]);
4894 MMPLAYER_FREEIF(argv);
4895 MMPLAYER_FREEIF(argv2);
4896 MMPLAYER_FREEIF(argc);
4902 __mmplayer_check_async_state_transition(mmplayer_t *player)
4904 GstState element_state = GST_STATE_VOID_PENDING;
4905 GstState element_pending_state = GST_STATE_VOID_PENDING;
4906 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4907 GstElement *element = NULL;
4908 gboolean async = FALSE;
4910 /* check player handle */
4911 MMPLAYER_RETURN_IF_FAIL(player &&
4913 player->pipeline->mainbin &&
4914 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4917 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4919 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4920 LOGD("don't need to check the pipeline state");
4924 MMPLAYER_PRINT_STATE(player);
4926 /* wait for state transition */
4927 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4928 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4930 if (ret == GST_STATE_CHANGE_FAILURE) {
4931 LOGE(" [%s] state : %s pending : %s",
4932 GST_ELEMENT_NAME(element),
4933 gst_element_state_get_name(element_state),
4934 gst_element_state_get_name(element_pending_state));
4936 /* dump state of all element */
4937 _mmplayer_dump_pipeline_state(player);
4942 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4947 _mmplayer_destroy(MMHandleType handle)
4949 mmplayer_t *player = MM_PLAYER_CAST(handle);
4953 /* check player handle */
4954 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4956 /* destroy can called at anytime */
4957 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4959 /* check async state transition */
4960 __mmplayer_check_async_state_transition(player);
4962 /* release gapless play thread */
4963 if (player->gapless_play_thread) {
4964 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4965 player->gapless_play_thread_exit = TRUE;
4966 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4967 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4969 LOGD("waitting for gapless play thread exit");
4970 g_thread_join(player->gapless_play_thread);
4971 g_mutex_clear(&player->gapless_play_thread_mutex);
4972 g_cond_clear(&player->gapless_play_thread_cond);
4973 LOGD("gapless play thread released");
4976 _mmplayer_release_video_capture(player);
4978 /* de-initialize resource manager */
4979 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4980 player->resource_manager))
4981 LOGE("failed to deinitialize resource manager");
4983 /* release pipeline */
4984 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4985 LOGE("failed to destory pipeline");
4986 return MM_ERROR_PLAYER_INTERNAL;
4989 g_queue_free(player->bus_msg_q);
4991 /* release subtitle info lock and cond */
4992 g_mutex_clear(&player->subtitle_info_mutex);
4993 g_cond_clear(&player->subtitle_info_cond);
4995 __mmplayer_release_dump_list(player->dump_list);
4997 /* release miscellaneous information */
4998 __mmplayer_release_misc(player);
5000 /* release miscellaneous information.
5001 these info needs to be released after pipeline is destroyed. */
5002 __mmplayer_release_misc_post(player);
5004 /* release attributes */
5005 _mmplayer_deconstruct_attribute(handle);
5008 g_mutex_clear(&player->fsink_lock);
5011 g_mutex_clear(&player->update_tag_lock);
5013 /* release video bo lock and cond */
5014 g_mutex_clear(&player->video_bo_mutex);
5015 g_cond_clear(&player->video_bo_cond);
5019 return MM_ERROR_NONE;
5023 _mmplayer_realize(MMHandleType hplayer)
5025 mmplayer_t *player = (mmplayer_t *)hplayer;
5028 MMHandleType attrs = 0;
5029 int ret = MM_ERROR_NONE;
5033 /* check player handle */
5034 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5036 /* check current state */
5037 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5039 attrs = MMPLAYER_GET_ATTRS(player);
5041 LOGE("fail to get attributes.");
5042 return MM_ERROR_PLAYER_INTERNAL;
5044 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5045 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5047 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5048 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5050 if (ret != MM_ERROR_NONE) {
5051 LOGE("failed to parse profile");
5056 if (uri && (strstr(uri, "es_buff://"))) {
5057 if (strstr(uri, "es_buff://push_mode"))
5058 player->es_player_push_mode = TRUE;
5060 player->es_player_push_mode = FALSE;
5063 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5064 LOGW("mms protocol is not supported format.");
5065 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5068 if (MMPLAYER_IS_STREAMING(player))
5069 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5071 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5073 player->smooth_streaming = FALSE;
5074 player->videodec_linked = 0;
5075 player->audiodec_linked = 0;
5076 player->textsink_linked = 0;
5077 player->is_external_subtitle_present = FALSE;
5078 player->is_external_subtitle_added_now = FALSE;
5079 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5080 player->video360_metadata.is_spherical = -1;
5081 player->is_openal_plugin_used = FALSE;
5082 player->demux_pad_index = 0;
5083 player->subtitle_language_list = NULL;
5084 player->is_subtitle_force_drop = FALSE;
5086 _mmplayer_track_initialize(player);
5087 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5089 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5090 gint prebuffer_ms = 0, rebuffer_ms = 0;
5092 player->streamer = _mm_player_streaming_create();
5093 _mm_player_streaming_initialize(player->streamer, TRUE);
5095 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5096 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5098 if (prebuffer_ms > 0) {
5099 prebuffer_ms = MAX(prebuffer_ms, 1000);
5100 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5103 if (rebuffer_ms > 0) {
5104 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5105 rebuffer_ms = MAX(rebuffer_ms, 1000);
5106 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5109 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5110 player->streamer->buffering_req.rebuffer_time);
5113 /* realize pipeline */
5114 ret = __mmplayer_gst_realize(player);
5115 if (ret != MM_ERROR_NONE)
5116 LOGE("fail to realize the player.");
5118 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5126 _mmplayer_unrealize(MMHandleType hplayer)
5128 mmplayer_t *player = (mmplayer_t *)hplayer;
5129 int ret = MM_ERROR_NONE;
5133 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5135 MMPLAYER_CMD_UNLOCK(player);
5136 /* destroy the gst bus msg thread which is created during realize.
5137 this funct have to be called before getting cmd lock. */
5138 _mmplayer_bus_msg_thread_destroy(player);
5139 MMPLAYER_CMD_LOCK(player);
5141 /* check current state */
5142 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5144 /* check async state transition */
5145 __mmplayer_check_async_state_transition(player);
5147 /* unrealize pipeline */
5148 ret = __mmplayer_gst_unrealize(player);
5150 if (!player->interrupted_by_resource) {
5151 int rm_ret = MM_ERROR_NONE;
5152 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5154 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5155 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5156 if (rm_ret != MM_ERROR_NONE)
5157 LOGE("failed to release [%d] resources", res_idx);
5166 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5168 mmplayer_t *player = (mmplayer_t *)hplayer;
5170 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5172 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5176 _mmplayer_get_state(MMHandleType hplayer, int *state)
5178 mmplayer_t *player = (mmplayer_t *)hplayer;
5180 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5182 *state = MMPLAYER_CURRENT_STATE(player);
5184 return MM_ERROR_NONE;
5188 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5190 GstElement *vol_element = NULL;
5191 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5194 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5195 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5197 /* check pipeline handle */
5198 if (!player->pipeline || !player->pipeline->audiobin) {
5199 LOGD("'%s' will be applied when audiobin is created", prop_name);
5201 /* NOTE : stored value will be used in create_audiobin
5202 * returning MM_ERROR_NONE here makes application to able to
5203 * set audio volume or mute at anytime.
5205 return MM_ERROR_NONE;
5208 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5209 volume_elem_id = MMPLAYER_A_SINK;
5211 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5213 LOGE("failed to get vol element %d", volume_elem_id);
5214 return MM_ERROR_PLAYER_INTERNAL;
5217 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5219 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5220 LOGE("there is no '%s' property", prop_name);
5221 return MM_ERROR_PLAYER_INTERNAL;
5224 if (!strcmp(prop_name, "volume")) {
5225 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5226 } else if (!strcmp(prop_name, "mute")) {
5227 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5229 LOGE("invalid property %s", prop_name);
5230 return MM_ERROR_PLAYER_INTERNAL;
5233 return MM_ERROR_NONE;
5237 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5239 int ret = MM_ERROR_NONE;
5240 mmplayer_t *player = (mmplayer_t *)hplayer;
5243 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5245 LOGD("volume = %f", volume);
5247 /* invalid factor range or not */
5248 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5249 LOGE("Invalid volume value");
5250 return MM_ERROR_INVALID_ARGUMENT;
5253 player->sound.volume = volume;
5255 ret = __mmplayer_gst_set_volume_property(player, "volume");
5262 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5264 mmplayer_t *player = (mmplayer_t *)hplayer;
5268 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5269 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5271 *volume = player->sound.volume;
5273 LOGD("current vol = %f", *volume);
5276 return MM_ERROR_NONE;
5280 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5282 int ret = MM_ERROR_NONE;
5283 mmplayer_t *player = (mmplayer_t *)hplayer;
5286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5288 LOGD("mute = %d", mute);
5290 player->sound.mute = mute;
5292 ret = __mmplayer_gst_set_volume_property(player, "mute");
5299 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5301 mmplayer_t *player = (mmplayer_t *)hplayer;
5305 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5306 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5308 *mute = player->sound.mute;
5310 LOGD("current mute = %d", *mute);
5314 return MM_ERROR_NONE;
5318 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5320 mmplayer_t *player = (mmplayer_t *)hplayer;
5324 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5326 player->audio_stream_changed_cb = callback;
5327 player->audio_stream_changed_cb_user_param = user_param;
5328 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5332 return MM_ERROR_NONE;
5336 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5338 mmplayer_t *player = (mmplayer_t *)hplayer;
5342 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5344 player->audio_decoded_cb = callback;
5345 player->audio_decoded_cb_user_param = user_param;
5346 player->audio_extract_opt = opt;
5347 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5351 return MM_ERROR_NONE;
5355 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5357 mmplayer_t *player = (mmplayer_t *)hplayer;
5361 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5363 if (callback && !player->bufmgr)
5364 player->bufmgr = tbm_bufmgr_init(-1);
5366 player->set_mode.video_export = (callback) ? true : false;
5367 player->video_decoded_cb = callback;
5368 player->video_decoded_cb_user_param = user_param;
5370 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5374 return MM_ERROR_NONE;
5378 _mmplayer_start(MMHandleType hplayer)
5380 mmplayer_t *player = (mmplayer_t *)hplayer;
5381 gint ret = MM_ERROR_NONE;
5385 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5387 /* check current state */
5388 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5390 /* start pipeline */
5391 ret = _mmplayer_gst_start(player);
5392 if (ret != MM_ERROR_NONE)
5393 LOGE("failed to start player.");
5395 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5396 LOGD("force playing start even during buffering");
5397 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5405 /* NOTE: post "not supported codec message" to application
5406 * when one codec is not found during AUTOPLUGGING in MSL.
5407 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5408 * And, if any codec is not found, don't send message here.
5409 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5412 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5414 MMMessageParamType msg_param;
5415 memset(&msg_param, 0, sizeof(MMMessageParamType));
5416 gboolean post_msg_direct = FALSE;
5420 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5422 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5423 player->not_supported_codec, player->can_support_codec);
5425 if (player->not_found_demuxer) {
5426 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5427 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5429 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5430 MMPLAYER_FREEIF(msg_param.data);
5432 return MM_ERROR_NONE;
5435 if (player->not_supported_codec) {
5436 if (player->can_support_codec) {
5437 // There is one codec to play
5438 post_msg_direct = TRUE;
5440 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5441 post_msg_direct = TRUE;
5444 if (post_msg_direct) {
5445 MMMessageParamType msg_param;
5446 memset(&msg_param, 0, sizeof(MMMessageParamType));
5448 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5449 LOGW("not found AUDIO codec, posting error code to application.");
5451 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5452 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5453 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5454 LOGW("not found VIDEO codec, posting error code to application.");
5456 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5457 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5460 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5462 MMPLAYER_FREEIF(msg_param.data);
5464 return MM_ERROR_NONE;
5466 // no any supported codec case
5467 LOGW("not found any codec, posting error code to application.");
5469 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5470 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5471 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5473 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5474 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5477 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5479 MMPLAYER_FREEIF(msg_param.data);
5485 return MM_ERROR_NONE;
5489 __mmplayer_check_pipeline(mmplayer_t *player)
5491 GstState element_state = GST_STATE_VOID_PENDING;
5492 GstState element_pending_state = GST_STATE_VOID_PENDING;
5494 int ret = MM_ERROR_NONE;
5496 if (!player->gapless.reconfigure)
5499 LOGW("pipeline is under construction.");
5501 MMPLAYER_PLAYBACK_LOCK(player);
5502 MMPLAYER_PLAYBACK_UNLOCK(player);
5504 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5506 /* wait for state transition */
5507 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5508 if (ret == GST_STATE_CHANGE_FAILURE)
5509 LOGE("failed to change pipeline state within %d sec", timeout);
5512 /* NOTE : it should be able to call 'stop' anytime*/
5514 _mmplayer_stop(MMHandleType hplayer)
5516 mmplayer_t *player = (mmplayer_t *)hplayer;
5517 int ret = MM_ERROR_NONE;
5521 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5523 /* check current state */
5524 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5526 /* check pipline building state */
5527 __mmplayer_check_pipeline(player);
5528 __mmplayer_reset_gapless_state(player);
5530 /* NOTE : application should not wait for EOS after calling STOP */
5531 _mmplayer_cancel_eos_timer(player);
5534 player->seek_state = MMPLAYER_SEEK_NONE;
5537 ret = _mmplayer_gst_stop(player);
5539 if (ret != MM_ERROR_NONE)
5540 LOGE("failed to stop player.");
5548 _mmplayer_pause(MMHandleType hplayer)
5550 mmplayer_t *player = (mmplayer_t *)hplayer;
5551 gint64 pos_nsec = 0;
5552 gboolean async = FALSE;
5553 gint ret = MM_ERROR_NONE;
5557 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5559 /* check current state */
5560 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5562 /* check pipline building state */
5563 __mmplayer_check_pipeline(player);
5565 switch (MMPLAYER_CURRENT_STATE(player)) {
5566 case MM_PLAYER_STATE_READY:
5568 /* check prepare async or not.
5569 * In the case of streaming playback, it's recommned to avoid blocking wait.
5571 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5572 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5574 /* Changing back sync of rtspsrc to async */
5575 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5576 LOGD("async prepare working mode for rtsp");
5582 case MM_PLAYER_STATE_PLAYING:
5584 /* NOTE : store current point to overcome some bad operation
5585 *(returning zero when getting current position in paused state) of some
5588 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5589 LOGW("getting current position failed in paused");
5591 player->last_position = pos_nsec;
5593 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5594 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5595 This causes problem is position calculation during normal pause resume scenarios also.
5596 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5597 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5598 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5599 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5605 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5606 LOGD("doing async pause in case of ms buff src");
5610 /* pause pipeline */
5611 ret = _mmplayer_gst_pause(player, async);
5613 if (ret != MM_ERROR_NONE)
5614 LOGE("failed to pause player. ret : 0x%x", ret);
5616 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5617 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5618 LOGE("failed to update display_rotation");
5626 /* in case of streaming, pause could take long time.*/
5628 _mmplayer_abort_pause(MMHandleType hplayer)
5630 mmplayer_t *player = (mmplayer_t *)hplayer;
5631 int ret = MM_ERROR_NONE;
5635 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5637 player->pipeline->mainbin,
5638 MM_ERROR_PLAYER_NOT_INITIALIZED);
5640 LOGD("set the pipeline state to READY");
5642 /* set state to READY */
5643 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5644 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5645 if (ret != MM_ERROR_NONE) {
5646 LOGE("fail to change state to READY");
5647 return MM_ERROR_PLAYER_INTERNAL;
5650 LOGD("succeeded in changing state to READY");
5655 _mmplayer_resume(MMHandleType hplayer)
5657 mmplayer_t *player = (mmplayer_t *)hplayer;
5658 int ret = MM_ERROR_NONE;
5659 gboolean async = FALSE;
5663 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5665 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5666 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5667 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5671 /* Changing back sync mode rtspsrc to async */
5672 LOGD("async resume for rtsp case");
5676 /* check current state */
5677 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5679 ret = _mmplayer_gst_resume(player, async);
5680 if (ret != MM_ERROR_NONE)
5681 LOGE("failed to resume player.");
5683 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5684 LOGD("force resume even during buffering");
5685 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5694 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5696 mmplayer_t *player = (mmplayer_t *)hplayer;
5697 gint64 pos_nsec = 0;
5698 int ret = MM_ERROR_NONE;
5700 signed long long start = 0, stop = 0;
5701 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5704 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5705 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5707 /* The sound of video is not supported under 0.0 and over 2.0. */
5708 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5709 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5712 _mmplayer_set_mute(hplayer, mute);
5714 if (player->playback_rate == rate)
5715 return MM_ERROR_NONE;
5717 /* If the position is reached at start potion during fast backward, EOS is posted.
5718 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5720 player->playback_rate = rate;
5722 current_state = MMPLAYER_CURRENT_STATE(player);
5724 if (current_state != MM_PLAYER_STATE_PAUSED)
5725 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5727 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5729 if ((current_state == MM_PLAYER_STATE_PAUSED)
5730 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5731 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5732 pos_nsec = player->last_position;
5737 stop = GST_CLOCK_TIME_NONE;
5739 start = GST_CLOCK_TIME_NONE;
5743 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5744 player->playback_rate,
5746 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5747 GST_SEEK_TYPE_SET, start,
5748 GST_SEEK_TYPE_SET, stop)) {
5749 LOGE("failed to set speed playback");
5750 return MM_ERROR_PLAYER_SEEK;
5753 LOGD("succeeded to set speed playback as %0.1f", rate);
5757 return MM_ERROR_NONE;;
5761 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5763 mmplayer_t *player = (mmplayer_t *)hplayer;
5764 int ret = MM_ERROR_NONE;
5768 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5770 /* check pipline building state */
5771 __mmplayer_check_pipeline(player);
5773 ret = _mmplayer_gst_set_position(player, position, FALSE);
5781 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5783 mmplayer_t *player = (mmplayer_t *)hplayer;
5784 int ret = MM_ERROR_NONE;
5786 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5787 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5789 if (g_strrstr(player->type, "video/mpegts"))
5790 __mmplayer_update_duration_value(player);
5792 *duration = player->duration;
5797 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5799 mmplayer_t *player = (mmplayer_t *)hplayer;
5800 int ret = MM_ERROR_NONE;
5802 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5804 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5810 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5812 mmplayer_t *player = (mmplayer_t *)hplayer;
5813 int ret = MM_ERROR_NONE;
5817 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5819 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5827 __mmplayer_is_midi_type(gchar *str_caps)
5829 if ((g_strrstr(str_caps, "audio/midi")) ||
5830 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5831 (g_strrstr(str_caps, "application/x-smaf")) ||
5832 (g_strrstr(str_caps, "audio/x-imelody")) ||
5833 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5834 (g_strrstr(str_caps, "audio/xmf")) ||
5835 (g_strrstr(str_caps, "audio/mxmf"))) {
5844 __mmplayer_is_only_mp3_type(gchar *str_caps)
5846 if (g_strrstr(str_caps, "application/x-id3") ||
5847 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5853 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5855 GstStructure *caps_structure = NULL;
5856 gint samplerate = 0;
5860 MMPLAYER_RETURN_IF_FAIL(player && caps);
5862 caps_structure = gst_caps_get_structure(caps, 0);
5864 /* set stream information */
5865 gst_structure_get_int(caps_structure, "rate", &samplerate);
5866 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5868 gst_structure_get_int(caps_structure, "channels", &channels);
5869 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5871 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5875 __mmplayer_update_content_type_info(mmplayer_t *player)
5878 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5880 if (__mmplayer_is_midi_type(player->type)) {
5881 player->bypass_audio_effect = TRUE;
5885 if (!player->streamer) {
5886 LOGD("no need to check streaming type");
5890 if (g_strrstr(player->type, "application/x-hls")) {
5891 /* If it can't know exact type when it parses uri because of redirection case,
5892 * it will be fixed by typefinder or when doing autoplugging.
5894 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5895 player->streamer->is_adaptive_streaming = TRUE;
5896 } else if (g_strrstr(player->type, "application/dash+xml")) {
5897 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5898 player->streamer->is_adaptive_streaming = TRUE;
5901 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5902 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5903 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5905 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5906 if (player->streamer->is_adaptive_streaming)
5907 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5909 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5913 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5918 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5919 GstCaps *caps, gpointer data)
5921 mmplayer_t *player = (mmplayer_t *)data;
5926 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5928 /* store type string */
5929 MMPLAYER_FREEIF(player->type);
5930 player->type = gst_caps_to_string(caps);
5932 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5933 player, player->type, probability, gst_caps_get_size(caps));
5935 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5936 (g_strrstr(player->type, "audio/x-raw-int"))) {
5937 LOGE("not support media format");
5939 if (player->msg_posted == FALSE) {
5940 MMMessageParamType msg_param;
5941 memset(&msg_param, 0, sizeof(MMMessageParamType));
5943 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5944 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5946 /* don't post more if one was sent already */
5947 player->msg_posted = TRUE;
5952 __mmplayer_update_content_type_info(player);
5954 pad = gst_element_get_static_pad(tf, "src");
5956 LOGE("fail to get typefind src pad.");
5960 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5961 gboolean async = FALSE;
5962 LOGE("failed to autoplug %s", player->type);
5964 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5966 if (async && player->msg_posted == FALSE)
5967 __mmplayer_handle_missed_plugin(player);
5971 gst_object_unref(GST_OBJECT(pad));
5979 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5981 GstElement *decodebin = NULL;
5985 /* create decodebin */
5986 decodebin = gst_element_factory_make("decodebin", NULL);
5989 LOGE("fail to create decodebin");
5993 /* raw pad handling signal */
5994 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5995 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5997 /* no-more-pad pad handling signal */
5998 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5999 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
6001 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6002 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
6004 /* This signal is emitted when a pad for which there is no further possible
6005 decoding is added to the decodebin.*/
6006 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6007 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
6009 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6010 before looking for any elements that can handle that stream.*/
6011 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6012 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6014 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6015 before looking for any elements that can handle that stream.*/
6016 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6017 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6019 /* This signal is emitted once decodebin has finished decoding all the data.*/
6020 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6021 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
6023 /* This signal is emitted when a element is added to the bin.*/
6024 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6025 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6032 __mmplayer_gst_make_queue2(mmplayer_t *player)
6034 GstElement *queue2 = NULL;
6035 gint64 dur_bytes = 0L;
6036 mmplayer_gst_element_t *mainbin = NULL;
6037 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6040 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6042 mainbin = player->pipeline->mainbin;
6044 queue2 = gst_element_factory_make("queue2", "queue2");
6046 LOGE("failed to create buffering queue element");
6050 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6051 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6053 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6055 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6056 * skip the pull mode(file or ring buffering) setting. */
6057 if (dur_bytes > 0) {
6058 if (!g_strrstr(player->type, "video/mpegts")) {
6059 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6060 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6066 _mm_player_streaming_set_queue2(player->streamer,
6070 (guint64)dur_bytes); /* no meaning at the moment */
6076 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6078 mmplayer_gst_element_t *mainbin = NULL;
6079 GstElement *decodebin = NULL;
6080 GstElement *queue2 = NULL;
6081 GstPad *sinkpad = NULL;
6082 GstPad *qsrcpad = NULL;
6085 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6087 mainbin = player->pipeline->mainbin;
6089 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6091 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6092 LOGW("need to check: muxed buffer is not null");
6095 queue2 = __mmplayer_gst_make_queue2(player);
6097 LOGE("failed to make queue2");
6101 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6102 LOGE("failed to add buffering queue");
6106 sinkpad = gst_element_get_static_pad(queue2, "sink");
6107 qsrcpad = gst_element_get_static_pad(queue2, "src");
6109 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6110 LOGE("failed to link [%s:%s]-[%s:%s]",
6111 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6115 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6116 LOGE("failed to sync queue2 state with parent");
6120 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6121 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6125 gst_object_unref(GST_OBJECT(sinkpad));
6129 /* create decodebin */
6130 decodebin = _mmplayer_gst_make_decodebin(player);
6132 LOGE("failed to make decodebin");
6136 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6137 LOGE("failed to add decodebin");
6141 /* to force caps on the decodebin element and avoid reparsing stuff by
6142 * typefind. It also avoids a deadlock in the way typefind activates pads in
6143 * the state change */
6144 g_object_set(decodebin, "sink-caps", caps, NULL);
6146 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6148 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6149 LOGE("failed to link [%s:%s]-[%s:%s]",
6150 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6154 gst_object_unref(GST_OBJECT(sinkpad));
6156 gst_object_unref(GST_OBJECT(qsrcpad));
6159 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6160 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6162 /* set decodebin property about buffer in streaming playback. *
6163 * in case of HLS/DASH, it does not need to have big buffer *
6164 * because it is kind of adaptive streaming. */
6165 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6166 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6167 gint high_percent = 0;
6169 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6170 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6172 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6174 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6176 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6177 "high-percent", high_percent,
6178 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6179 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6180 "max-size-buffers", 0, NULL); // disable or automatic
6183 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6184 LOGE("failed to sync decodebin state with parent");
6195 gst_object_unref(GST_OBJECT(sinkpad));
6198 gst_object_unref(GST_OBJECT(qsrcpad));
6201 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6202 * You need to explicitly set elements to the NULL state before
6203 * dropping the final reference, to allow them to clean up.
6205 gst_element_set_state(queue2, GST_STATE_NULL);
6207 /* And, it still has a parent "player".
6208 * You need to let the parent manage the object instead of unreffing the object directly.
6210 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6211 gst_object_unref(queue2);
6216 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6217 * You need to explicitly set elements to the NULL state before
6218 * dropping the final reference, to allow them to clean up.
6220 gst_element_set_state(decodebin, GST_STATE_NULL);
6222 /* And, it still has a parent "player".
6223 * You need to let the parent manage the object instead of unreffing the object directly.
6226 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6227 gst_object_unref(decodebin);
6235 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6239 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6240 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6242 LOGD("class : %s, mime : %s", factory_class, mime);
6244 /* add missing plugin */
6245 /* NOTE : msl should check missing plugin for image mime type.
6246 * Some motion jpeg clips can have playable audio track.
6247 * So, msl have to play audio after displaying popup written video format not supported.
6249 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6250 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6251 LOGD("not found demuxer");
6252 player->not_found_demuxer = TRUE;
6253 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6259 if (!g_strrstr(factory_class, "Demuxer")) {
6260 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6261 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6262 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6264 /* check that clip have multi tracks or not */
6265 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6266 LOGD("video plugin is already linked");
6268 LOGW("add VIDEO to missing plugin");
6269 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6270 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6272 } else if (g_str_has_prefix(mime, "audio")) {
6273 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6274 LOGD("audio plugin is already linked");
6276 LOGW("add AUDIO to missing plugin");
6277 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6278 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6286 return MM_ERROR_NONE;
6290 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6292 mmplayer_t *player = (mmplayer_t *)data;
6296 MMPLAYER_RETURN_IF_FAIL(player);
6298 /* remove fakesink. */
6299 if (!_mmplayer_gst_remove_fakesink(player,
6300 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6301 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6302 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6303 * source element are not same. To overcome this situation, this function will called
6304 * several places and several times. Therefore, this is not an error case.
6309 LOGD("[handle: %p] pipeline has completely constructed", player);
6311 if ((player->ini.async_start) &&
6312 (player->msg_posted == FALSE) &&
6313 (player->cmd >= MMPLAYER_COMMAND_START))
6314 __mmplayer_handle_missed_plugin(player);
6316 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6320 __mmplayer_check_profile(void)
6323 static int profile_tv = -1;
6325 if (__builtin_expect(profile_tv != -1, 1))
6328 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6329 switch (*profileName) {
6344 __mmplayer_get_next_uri(mmplayer_t *player)
6346 mmplayer_parse_profile_t profile;
6348 guint num_of_list = 0;
6351 num_of_list = g_list_length(player->uri_info.uri_list);
6352 uri_idx = player->uri_info.uri_idx;
6354 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6355 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6356 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6358 LOGW("next uri does not exist");
6362 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6363 LOGE("failed to parse profile");
6367 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6368 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6369 LOGW("uri type is not supported(%d)", profile.uri_type);
6373 LOGD("success to find next uri %d", uri_idx);
6377 if (uri_idx == num_of_list) {
6378 LOGE("failed to find next uri");
6382 player->uri_info.uri_idx = uri_idx;
6383 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6385 if (mm_attrs_commit_all(player->attrs)) {
6386 LOGE("failed to commit");
6390 SECURE_LOGD("next playback uri: %s", uri);
6395 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6397 #define REPEAT_COUNT_INFINITE -1
6398 #define REPEAT_COUNT_MIN 2
6399 #define ORIGINAL_URI_ONLY 1
6401 MMHandleType attrs = 0;
6405 guint num_of_uri = 0;
6406 int profile_tv = -1;
6410 LOGD("checking for gapless play option");
6412 if (player->build_audio_offload) {
6413 LOGE("offload path is not supportable.");
6417 if (player->pipeline->textbin) {
6418 LOGE("subtitle path is enabled. gapless play is not supported.");
6422 attrs = MMPLAYER_GET_ATTRS(player);
6424 LOGE("fail to get attributes.");
6428 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6430 /* gapless playback is not supported in case of video at TV profile. */
6431 profile_tv = __mmplayer_check_profile();
6432 if (profile_tv && video) {
6433 LOGW("not support video gapless playback");
6437 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6438 LOGE("failed to get play count");
6440 if (mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless) != MM_ERROR_NONE)
6441 LOGE("failed to get gapless mode");
6443 /* check repeat count in case of audio */
6445 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6446 LOGW("gapless is disabled");
6450 num_of_uri = g_list_length(player->uri_info.uri_list);
6452 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6454 if (num_of_uri == ORIGINAL_URI_ONLY) {
6455 /* audio looping path */
6456 if (count >= REPEAT_COUNT_MIN) {
6457 /* decrease play count */
6458 /* we succeeded to rewind. update play count and then wait for next EOS */
6460 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6461 /* commit attribute */
6462 if (mm_attrs_commit_all(attrs))
6463 LOGE("failed to commit attribute");
6465 } else if (count != REPEAT_COUNT_INFINITE) {
6466 LOGD("there is no next uri and no repeat");
6469 LOGD("looping cnt %d", count);
6471 /* gapless playback path */
6472 if (!__mmplayer_get_next_uri(player)) {
6473 LOGE("failed to get next uri");
6480 LOGE("unable to play gapless path. EOS will be posted soon");
6485 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6487 mmplayer_selector_t *selector = &player->selector[type];
6488 mmplayer_gst_element_t *sinkbin = NULL;
6489 main_element_id_e selectorId = MMPLAYER_M_NUM;
6490 main_element_id_e sinkId = MMPLAYER_M_NUM;
6491 GstPad *srcpad = NULL;
6492 GstPad *sinkpad = NULL;
6493 gboolean send_notice = FALSE;
6496 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6498 LOGD("type %d", type);
6501 case MM_PLAYER_TRACK_TYPE_AUDIO:
6502 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6503 sinkId = MMPLAYER_A_BIN;
6504 sinkbin = player->pipeline->audiobin;
6506 case MM_PLAYER_TRACK_TYPE_VIDEO:
6507 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6508 sinkId = MMPLAYER_V_BIN;
6509 sinkbin = player->pipeline->videobin;
6512 case MM_PLAYER_TRACK_TYPE_TEXT:
6513 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6514 sinkId = MMPLAYER_T_BIN;
6515 sinkbin = player->pipeline->textbin;
6518 LOGE("requested type is not supportable");
6523 if (player->pipeline->mainbin[selectorId].gst) {
6526 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6528 if (selector->event_probe_id != 0)
6529 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6530 selector->event_probe_id = 0;
6532 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6533 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6535 if (srcpad && sinkpad) {
6536 /* after getting drained signal there is no data flows, so no need to do pad_block */
6537 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6538 gst_pad_unlink(srcpad, sinkpad);
6540 /* send custom event to sink pad to handle it at video sink */
6542 LOGD("send custom event to sinkpad");
6543 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6544 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6545 gst_pad_send_event(sinkpad, event);
6549 gst_object_unref(sinkpad);
6552 gst_object_unref(srcpad);
6555 LOGD("selector release");
6557 /* release and unref requests pad from the selector */
6558 for (n = 0; n < selector->channels->len; n++) {
6559 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6560 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6562 g_ptr_array_set_size(selector->channels, 0);
6564 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6565 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6567 player->pipeline->mainbin[selectorId].gst = NULL;
6575 __mmplayer_deactivate_old_path(mmplayer_t *player)
6578 MMPLAYER_RETURN_IF_FAIL(player);
6580 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6581 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6582 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6583 LOGE("deactivate selector error");
6587 _mmplayer_track_destroy(player);
6588 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6590 if (player->streamer) {
6591 _mm_player_streaming_initialize(player->streamer, FALSE);
6592 _mm_player_streaming_destroy(player->streamer);
6593 player->streamer = NULL;
6596 MMPLAYER_PLAYBACK_LOCK(player);
6597 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6604 if (!player->msg_posted) {
6605 MMMessageParamType msg = {0,};
6608 msg.code = MM_ERROR_PLAYER_INTERNAL;
6609 LOGE("gapless_uri_play> deactivate error");
6611 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6612 player->msg_posted = TRUE;
6618 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6620 int result = MM_ERROR_NONE;
6621 mmplayer_t *player = (mmplayer_t *)hplayer;
6624 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6626 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6627 if (mm_attrs_commit_all(player->attrs)) {
6628 LOGE("failed to commit the original uri.");
6629 result = MM_ERROR_PLAYER_INTERNAL;
6631 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6632 LOGE("failed to add the original uri in the uri list.");
6640 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6642 mmplayer_t *player = (mmplayer_t *)hplayer;
6643 guint num_of_list = 0;
6647 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6648 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6650 if (player->pipeline && player->pipeline->textbin) {
6651 LOGE("subtitle path is enabled.");
6652 return MM_ERROR_PLAYER_INVALID_STATE;
6655 num_of_list = g_list_length(player->uri_info.uri_list);
6657 if (is_first_path) {
6658 if (num_of_list == 0) {
6659 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6660 SECURE_LOGD("add original path : %s", uri);
6662 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6663 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6665 SECURE_LOGD("change original path : %s", uri);
6668 MMHandleType attrs = 0;
6669 attrs = MMPLAYER_GET_ATTRS(player);
6671 if (num_of_list == 0) {
6672 char *original_uri = NULL;
6675 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6677 if (!original_uri) {
6678 LOGE("there is no original uri.");
6679 return MM_ERROR_PLAYER_INVALID_STATE;
6682 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6683 player->uri_info.uri_idx = 0;
6685 SECURE_LOGD("add original path at first : %s", original_uri);
6689 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6690 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6694 return MM_ERROR_NONE;
6698 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6700 mmplayer_t *player = (mmplayer_t *)hplayer;
6701 char *next_uri = NULL;
6702 guint num_of_list = 0;
6705 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6707 num_of_list = g_list_length(player->uri_info.uri_list);
6709 if (num_of_list > 0) {
6710 gint uri_idx = player->uri_info.uri_idx;
6712 if (uri_idx < num_of_list-1)
6717 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6718 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6720 *uri = g_strdup(next_uri);
6724 return MM_ERROR_NONE;
6728 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6729 GstCaps *caps, gpointer data)
6731 mmplayer_t *player = (mmplayer_t *)data;
6732 const gchar *klass = NULL;
6733 const gchar *mime = NULL;
6734 gchar *caps_str = NULL;
6736 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6737 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6738 caps_str = gst_caps_to_string(caps);
6740 LOGW("unknown type of caps : %s from %s",
6741 caps_str, GST_ELEMENT_NAME(elem));
6743 MMPLAYER_FREEIF(caps_str);
6745 /* There is no available codec. */
6746 __mmplayer_check_not_supported_codec(player, klass, mime);
6750 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6751 GstCaps *caps, gpointer data)
6753 mmplayer_t *player = (mmplayer_t *)data;
6754 const char *mime = NULL;
6755 gboolean ret = TRUE;
6757 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6758 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6760 if (g_str_has_prefix(mime, "audio")) {
6761 GstStructure *caps_structure = NULL;
6762 gint samplerate = 0;
6764 gchar *caps_str = NULL;
6766 caps_structure = gst_caps_get_structure(caps, 0);
6767 gst_structure_get_int(caps_structure, "rate", &samplerate);
6768 gst_structure_get_int(caps_structure, "channels", &channels);
6770 if ((channels > 0 && samplerate == 0)) {
6771 LOGD("exclude audio...");
6775 caps_str = gst_caps_to_string(caps);
6776 /* set it directly because not sent by TAG */
6777 if (g_strrstr(caps_str, "mobile-xmf"))
6778 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6779 MMPLAYER_FREEIF(caps_str);
6780 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6781 MMMessageParamType msg_param;
6782 memset(&msg_param, 0, sizeof(MMMessageParamType));
6783 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6784 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6785 LOGD("video file is not supported on this device");
6787 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6788 LOGD("already video linked");
6791 LOGD("found new stream");
6798 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6800 gboolean ret = TRUE;
6801 GDBusConnection *conn = NULL;
6803 GVariant *result = NULL;
6804 const gchar *dbus_device_type = NULL;
6805 const gchar *dbus_ret = NULL;
6808 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6810 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6816 result = g_dbus_connection_call_sync(conn,
6817 "org.pulseaudio.Server",
6818 "/org/pulseaudio/StreamManager",
6819 "org.pulseaudio.StreamManager",
6820 "GetCurrentMediaRoutingPath",
6821 g_variant_new("(s)", "out"),
6822 G_VARIANT_TYPE("(ss)"),
6823 G_DBUS_CALL_FLAGS_NONE,
6827 if (!result || err) {
6828 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6834 /* device type is listed in stream-map.json at mmfw-sysconf */
6835 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6837 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6838 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6843 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6844 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6845 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6846 LOGD("audio offload is supportable");
6852 LOGD("audio offload is not supportable");
6856 g_variant_unref(result);
6857 g_object_unref(conn);
6862 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6864 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6865 gint64 position = 0;
6867 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6868 player->pipeline && player->pipeline->mainbin);
6870 MMPLAYER_CMD_LOCK(player);
6871 current_state = MMPLAYER_CURRENT_STATE(player);
6873 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6874 LOGW("getting current position failed in paused");
6876 _mmplayer_unrealize((MMHandleType)player);
6877 _mmplayer_realize((MMHandleType)player);
6879 _mmplayer_set_position((MMHandleType)player, position);
6881 /* async not to be blocked in streaming case */
6882 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6883 if (mm_attrs_commit_all(player->attrs))
6884 LOGE("failed to commit");
6886 _mmplayer_pause((MMHandleType)player);
6888 if (current_state == MM_PLAYER_STATE_PLAYING)
6889 _mmplayer_start((MMHandleType)player);
6890 MMPLAYER_CMD_UNLOCK(player);
6892 LOGD("rebuilding audio pipeline is completed.");
6895 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6897 mmplayer_t *player = (mmplayer_t *)user_data;
6898 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6899 gboolean is_supportable = FALSE;
6901 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6902 LOGW("failed to get device type");
6904 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6906 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6907 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6908 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6909 LOGD("ignore this dev connected info");
6913 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6914 if (player->build_audio_offload == is_supportable) {
6915 LOGD("keep current pipeline without re-building");
6919 /* rebuild pipeline */
6920 LOGD("re-build pipeline - offload: %d", is_supportable);
6921 player->build_audio_offload = FALSE;
6922 __mmplayer_rebuild_audio_pipeline(player);
6928 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6930 unsigned int id = 0;
6932 if (player->audio_device_cb_id != 0) {
6933 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6937 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6938 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6939 LOGD("added device connected cb (%u)", id);
6940 player->audio_device_cb_id = id;
6942 LOGW("failed to add device connected cb");
6950 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6952 gboolean ret = FALSE;
6953 GstElementFactory *factory = NULL;
6956 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6958 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6959 if (!__mmplayer_is_only_mp3_type(player->type))
6962 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6963 LOGD("there is no audio offload sink");
6967 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6968 LOGW("there is no audio device type to support offload");
6972 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6974 LOGW("there is no installed audio offload sink element");
6977 gst_object_unref(factory);
6979 if (__mmplayer_acquire_hw_resource(player,
6980 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6981 LOGE("failed to acquire audio offload decoder resource");
6985 if (!__mmplayer_add_audio_device_connected_cb(player))
6988 if (!__mmplayer_is_audio_offload_device_type(player))
6991 LOGD("audio offload can be built");
6996 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7002 static GstAutoplugSelectResult
7003 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7005 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7007 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7008 int audio_offload = 0;
7010 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7011 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7013 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7014 LOGD("expose audio path to build offload output path");
7015 player->build_audio_offload = TRUE;
7016 /* update codec info */
7017 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7018 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7019 player->audiodec_linked = 1;
7021 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7025 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7027 LOGD("audio codec type: %d", codec_type);
7028 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7029 /* sw codec will be skipped */
7030 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7031 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7032 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7033 ret = GST_AUTOPLUG_SELECT_SKIP;
7037 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7038 /* hw codec will be skipped */
7039 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7040 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7041 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7042 ret = GST_AUTOPLUG_SELECT_SKIP;
7047 /* set stream information */
7048 if (!player->audiodec_linked)
7049 __mmplayer_set_audio_attrs(player, caps);
7051 /* update codec info */
7052 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7053 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7054 player->audiodec_linked = 1;
7056 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7058 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7060 LOGD("video codec type: %d", codec_type);
7061 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7062 /* sw codec is skipped */
7063 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7064 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7065 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7066 ret = GST_AUTOPLUG_SELECT_SKIP;
7070 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7071 /* hw codec is skipped */
7072 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7073 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7074 ret = GST_AUTOPLUG_SELECT_SKIP;
7079 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7080 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7082 /* mark video decoder for acquire */
7083 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7084 LOGW("video decoder resource is already acquired, skip it.");
7085 ret = GST_AUTOPLUG_SELECT_SKIP;
7089 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7090 LOGE("failed to acquire video decoder resource");
7091 ret = GST_AUTOPLUG_SELECT_SKIP;
7094 player->interrupted_by_resource = FALSE;
7097 /* update codec info */
7098 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7099 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7100 player->videodec_linked = 1;
7108 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7109 GstCaps *caps, GstElementFactory *factory, gpointer data)
7111 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7112 mmplayer_t *player = (mmplayer_t *)data;
7114 gchar *factory_name = NULL;
7115 gchar *caps_str = NULL;
7116 const gchar *klass = NULL;
7119 factory_name = GST_OBJECT_NAME(factory);
7120 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7121 caps_str = gst_caps_to_string(caps);
7123 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7125 /* store type string */
7126 if (player->type == NULL) {
7127 player->type = gst_caps_to_string(caps);
7128 __mmplayer_update_content_type_info(player);
7131 /* filtering exclude keyword */
7132 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7133 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7134 LOGW("skipping [%s] by exculde keyword [%s]",
7135 factory_name, player->ini.exclude_element_keyword[idx]);
7137 result = GST_AUTOPLUG_SELECT_SKIP;
7142 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7143 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7144 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7145 factory_name, player->ini.unsupported_codec_keyword[idx]);
7146 result = GST_AUTOPLUG_SELECT_SKIP;
7151 /* exclude webm format */
7152 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7153 * because webm format is not supportable.
7154 * If webm is disabled in "autoplug-continue", there is no state change
7155 * failure or error because the decodebin will expose the pad directly.
7156 * It make MSL invoke _prepare_async_callback.
7157 * So, we need to disable webm format in "autoplug-select" */
7158 if (caps_str && strstr(caps_str, "webm")) {
7159 LOGW("webm is not supported");
7160 result = GST_AUTOPLUG_SELECT_SKIP;
7164 /* check factory class for filtering */
7165 /* NOTE : msl don't need to use image plugins.
7166 * So, those plugins should be skipped for error handling.
7168 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7169 LOGD("skipping [%s] by not required", factory_name);
7170 result = GST_AUTOPLUG_SELECT_SKIP;
7174 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7175 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7176 // TO CHECK : subtitle if needed, add subparse exception.
7177 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7178 result = GST_AUTOPLUG_SELECT_SKIP;
7182 if (g_strrstr(factory_name, "mpegpsdemux")) {
7183 LOGD("skipping PS container - not support");
7184 result = GST_AUTOPLUG_SELECT_SKIP;
7188 if (g_strrstr(factory_name, "mssdemux"))
7189 player->smooth_streaming = TRUE;
7191 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7192 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7195 GstStructure *str = NULL;
7196 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7198 /* don't make video because of not required */
7199 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7200 (!player->set_mode.video_export)) {
7201 LOGD("no need video decoding, expose pad");
7202 result = GST_AUTOPLUG_SELECT_EXPOSE;
7206 /* get w/h for omx state-tune */
7207 /* FIXME: deprecated? */
7208 str = gst_caps_get_structure(caps, 0);
7209 gst_structure_get_int(str, "width", &width);
7212 if (player->v_stream_caps) {
7213 gst_caps_unref(player->v_stream_caps);
7214 player->v_stream_caps = NULL;
7217 player->v_stream_caps = gst_caps_copy(caps);
7218 LOGD("take caps for video state tune");
7219 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7223 if (g_strrstr(klass, "Codec/Decoder")) {
7224 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7225 if (result != GST_AUTOPLUG_SELECT_TRY) {
7226 LOGW("skip add decoder");
7232 MMPLAYER_FREEIF(caps_str);
7238 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7241 //mmplayer_t *player = (mmplayer_t *)data;
7242 GstCaps *caps = NULL;
7244 LOGD("[Decodebin2] pad-removed signal");
7246 caps = gst_pad_query_caps(new_pad, NULL);
7248 LOGW("query caps is NULL");
7252 gchar *caps_str = NULL;
7253 caps_str = gst_caps_to_string(caps);
7255 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7257 MMPLAYER_FREEIF(caps_str);
7258 gst_caps_unref(caps);
7262 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7264 mmplayer_t *player = (mmplayer_t *)data;
7265 GstIterator *iter = NULL;
7266 GValue item = { 0, };
7268 gboolean done = FALSE;
7269 gboolean is_all_drained = TRUE;
7272 MMPLAYER_RETURN_IF_FAIL(player);
7274 LOGD("__mmplayer_gst_decode_drained");
7276 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7277 LOGW("Fail to get cmd lock");
7281 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7282 !__mmplayer_verify_gapless_play_path(player)) {
7283 LOGD("decoding is finished.");
7284 __mmplayer_reset_gapless_state(player);
7285 MMPLAYER_CMD_UNLOCK(player);
7289 player->gapless.reconfigure = TRUE;
7291 /* check decodebin src pads whether they received EOS or not */
7292 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7295 switch (gst_iterator_next(iter, &item)) {
7296 case GST_ITERATOR_OK:
7297 pad = g_value_get_object(&item);
7298 if (pad && !GST_PAD_IS_EOS(pad)) {
7299 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7300 is_all_drained = FALSE;
7303 g_value_reset(&item);
7305 case GST_ITERATOR_RESYNC:
7306 gst_iterator_resync(iter);
7308 case GST_ITERATOR_ERROR:
7309 case GST_ITERATOR_DONE:
7314 g_value_unset(&item);
7315 gst_iterator_free(iter);
7317 if (!is_all_drained) {
7318 LOGD("Wait util the all pads get EOS.");
7319 MMPLAYER_CMD_UNLOCK(player);
7324 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7325 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7327 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7328 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7329 __mmplayer_deactivate_old_path(player);
7330 MMPLAYER_CMD_UNLOCK(player);
7336 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7338 mmplayer_t *player = (mmplayer_t *)data;
7339 const gchar *klass = NULL;
7340 gchar *factory_name = NULL;
7342 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7343 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7345 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7347 if (__mmplayer_add_dump_buffer_probe(player, element))
7348 LOGD("add buffer probe");
7350 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7351 gchar *selected = NULL;
7352 selected = g_strdup(GST_ELEMENT_NAME(element));
7353 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7356 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7357 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7358 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7360 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7361 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7363 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7364 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7365 "max-video-width", player->adaptive_info.limit.width,
7366 "max-video-height", player->adaptive_info.limit.height, NULL);
7368 } else if (g_strrstr(klass, "Demuxer")) {
7369 //LOGD("plugged element is demuxer. take it");
7370 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7371 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7374 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7375 int surface_type = 0;
7377 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7380 // to support trust-zone only
7381 if (g_strrstr(factory_name, "asfdemux")) {
7382 LOGD("set file-location %s", player->profile.uri);
7383 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7384 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7385 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7386 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7387 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7388 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7389 (__mmplayer_is_only_mp3_type(player->type))) {
7390 LOGD("[mpegaudioparse] set streaming pull mode.");
7391 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7393 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7394 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7397 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7398 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7399 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7401 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7402 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7404 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7405 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7406 (MMPLAYER_IS_DASH_STREAMING(player))) {
7407 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7408 _mm_player_streaming_set_multiqueue(player->streamer, element);
7409 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7418 __mmplayer_release_misc(mmplayer_t *player)
7421 bool cur_mode = player->set_mode.rich_audio;
7424 MMPLAYER_RETURN_IF_FAIL(player);
7426 player->video_decoded_cb = NULL;
7427 player->video_decoded_cb_user_param = NULL;
7428 player->video_stream_prerolled = false;
7430 player->audio_decoded_cb = NULL;
7431 player->audio_decoded_cb_user_param = NULL;
7432 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7434 player->audio_stream_changed_cb = NULL;
7435 player->audio_stream_changed_cb_user_param = NULL;
7437 player->sent_bos = FALSE;
7438 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7440 player->seek_state = MMPLAYER_SEEK_NONE;
7442 player->total_bitrate = 0;
7443 player->total_maximum_bitrate = 0;
7445 player->not_found_demuxer = 0;
7447 player->last_position = 0;
7448 player->duration = 0;
7449 player->http_content_size = 0;
7450 player->not_supported_codec = MISSING_PLUGIN_NONE;
7451 player->can_support_codec = FOUND_PLUGIN_NONE;
7452 player->pending_seek.is_pending = false;
7453 player->pending_seek.pos = 0;
7454 player->msg_posted = FALSE;
7455 player->has_many_types = FALSE;
7456 player->is_subtitle_force_drop = FALSE;
7457 player->play_subtitle = FALSE;
7458 player->adjust_subtitle_pos = 0;
7459 player->has_closed_caption = FALSE;
7460 player->set_mode.video_export = false;
7461 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7462 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7464 player->set_mode.rich_audio = cur_mode;
7466 if (player->audio_device_cb_id > 0 &&
7467 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7468 LOGW("failed to remove audio device_connected_callback");
7469 player->audio_device_cb_id = 0;
7471 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7472 player->bitrate[i] = 0;
7473 player->maximum_bitrate[i] = 0;
7476 /* free memory related to audio effect */
7477 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7479 if (player->adaptive_info.var_list) {
7480 g_list_free_full(player->adaptive_info.var_list, g_free);
7481 player->adaptive_info.var_list = NULL;
7484 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7485 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7486 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7488 /* Reset video360 settings to their defaults in case if the pipeline is to be
7491 player->video360_metadata.is_spherical = -1;
7492 player->is_openal_plugin_used = FALSE;
7494 player->is_content_spherical = FALSE;
7495 player->is_video360_enabled = TRUE;
7496 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7497 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7498 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7499 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7500 player->video360_zoom = 1.0f;
7501 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7502 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7504 player->sound.rg_enable = false;
7506 __mmplayer_initialize_video_roi(player);
7511 __mmplayer_release_misc_post(mmplayer_t *player)
7513 char *original_uri = NULL;
7516 /* player->pipeline is already released before. */
7518 MMPLAYER_RETURN_IF_FAIL(player);
7520 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7522 /* clean found audio decoders */
7523 if (player->audio_decoders) {
7524 GList *a_dec = player->audio_decoders;
7525 for (; a_dec; a_dec = g_list_next(a_dec)) {
7526 gchar *name = a_dec->data;
7527 MMPLAYER_FREEIF(name);
7529 g_list_free(player->audio_decoders);
7530 player->audio_decoders = NULL;
7533 /* clean the uri list except original uri */
7534 if (player->uri_info.uri_list) {
7535 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7537 if (player->attrs) {
7538 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7539 LOGD("restore original uri = %s", original_uri);
7541 if (mm_attrs_commit_all(player->attrs))
7542 LOGE("failed to commit the original uri.");
7545 GList *uri_list = player->uri_info.uri_list;
7546 for (; uri_list; uri_list = g_list_next(uri_list)) {
7547 gchar *uri = uri_list->data;
7548 MMPLAYER_FREEIF(uri);
7550 g_list_free(player->uri_info.uri_list);
7551 player->uri_info.uri_list = NULL;
7554 /* clear the audio stream buffer list */
7555 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7557 /* clear the video stream bo list */
7558 __mmplayer_video_stream_destroy_bo_list(player);
7559 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7561 if (player->profile.input_mem.buf) {
7562 free(player->profile.input_mem.buf);
7563 player->profile.input_mem.buf = NULL;
7565 player->profile.input_mem.len = 0;
7566 player->profile.input_mem.offset = 0;
7568 player->uri_info.uri_idx = 0;
7573 __mmplayer_check_subtitle(mmplayer_t *player)
7575 MMHandleType attrs = 0;
7576 char *subtitle_uri = NULL;
7580 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7582 /* get subtitle attribute */
7583 attrs = MMPLAYER_GET_ATTRS(player);
7587 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7588 if (!subtitle_uri || !strlen(subtitle_uri))
7591 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7592 player->is_external_subtitle_present = TRUE;
7600 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7602 MMPLAYER_RETURN_IF_FAIL(player);
7604 if (player->eos_timer) {
7605 LOGD("cancel eos timer");
7606 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7607 player->eos_timer = 0;
7614 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7618 MMPLAYER_RETURN_IF_FAIL(player);
7619 MMPLAYER_RETURN_IF_FAIL(sink);
7621 player->sink_elements = g_list_append(player->sink_elements, sink);
7627 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7631 MMPLAYER_RETURN_IF_FAIL(player);
7632 MMPLAYER_RETURN_IF_FAIL(sink);
7634 player->sink_elements = g_list_remove(player->sink_elements, sink);
7640 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7641 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7643 mmplayer_signal_item_t *item = NULL;
7646 MMPLAYER_RETURN_IF_FAIL(player);
7648 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7649 LOGE("invalid signal type [%d]", type);
7653 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7655 LOGE("cannot connect signal [%s]", signal);
7660 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7661 player->signals[type] = g_list_append(player->signals[type], item);
7667 /* NOTE : be careful with calling this api. please refer to below glib comment
7668 * glib comment : Note that there is a bug in GObject that makes this function much
7669 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7670 * will no longer be called, but, the signal handler is not currently disconnected.
7671 * If the instance is itself being freed at the same time than this doesn't matter,
7672 * since the signal will automatically be removed, but if instance persists,
7673 * then the signal handler will leak. You should not remove the signal yourself
7674 * because in a future versions of GObject, the handler will automatically be
7677 * It's possible to work around this problem in a way that will continue to work
7678 * with future versions of GObject by checking that the signal handler is still
7679 * connected before disconnected it:
7681 * if (g_signal_handler_is_connected(instance, id))
7682 * g_signal_handler_disconnect(instance, id);
7685 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7687 GList *sig_list = NULL;
7688 mmplayer_signal_item_t *item = NULL;
7692 MMPLAYER_RETURN_IF_FAIL(player);
7694 LOGD("release signals type : %d", type);
7696 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7697 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7698 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7699 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7700 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7701 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7705 sig_list = player->signals[type];
7707 for (; sig_list; sig_list = sig_list->next) {
7708 item = sig_list->data;
7710 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7711 if (g_signal_handler_is_connected(item->obj, item->sig))
7712 g_signal_handler_disconnect(item->obj, item->sig);
7715 MMPLAYER_FREEIF(item);
7718 g_list_free(player->signals[type]);
7719 player->signals[type] = NULL;
7727 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7729 mmplayer_t *player = 0;
7730 int prev_display_surface_type = 0;
7731 void *prev_display_overlay = NULL;
7735 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7736 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7738 player = MM_PLAYER_CAST(handle);
7740 /* check video sinkbin is created */
7741 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7742 LOGE("Videosink is already created");
7743 return MM_ERROR_NONE;
7746 LOGD("videosink element is not yet ready");
7748 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7749 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7751 return MM_ERROR_INVALID_ARGUMENT;
7754 /* load previous attributes */
7755 if (player->attrs) {
7756 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7757 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7758 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7759 if (prev_display_surface_type == surface_type) {
7760 LOGD("incoming display surface type is same as previous one, do nothing..");
7762 return MM_ERROR_NONE;
7765 LOGE("failed to load attributes");
7767 return MM_ERROR_PLAYER_INTERNAL;
7770 /* videobin is not created yet, so we just set attributes related to display surface */
7771 LOGD("store display attribute for given surface type(%d)", surface_type);
7772 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7773 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7774 if (mm_attrs_commit_all(player->attrs)) {
7775 LOGE("failed to commit attribute");
7777 return MM_ERROR_PLAYER_INTERNAL;
7781 return MM_ERROR_NONE;
7784 /* Note : if silent is true, then subtitle would not be displayed. :*/
7786 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7788 mmplayer_t *player = (mmplayer_t *)hplayer;
7792 /* check player handle */
7793 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7795 player->set_mode.subtitle_off = silent;
7797 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7801 return MM_ERROR_NONE;
7805 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7807 mmplayer_gst_element_t *mainbin = NULL;
7808 mmplayer_gst_element_t *textbin = NULL;
7809 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7810 GstState current_state = GST_STATE_VOID_PENDING;
7811 GstState element_state = GST_STATE_VOID_PENDING;
7812 GstState element_pending_state = GST_STATE_VOID_PENDING;
7814 GstEvent *event = NULL;
7815 int result = MM_ERROR_NONE;
7817 GstClock *curr_clock = NULL;
7818 GstClockTime base_time, start_time, curr_time;
7823 /* check player handle */
7824 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7826 player->pipeline->mainbin &&
7827 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7829 mainbin = player->pipeline->mainbin;
7830 textbin = player->pipeline->textbin;
7832 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7834 // sync clock with current pipeline
7835 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7836 curr_time = gst_clock_get_time(curr_clock);
7838 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7839 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7841 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7842 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7844 if (current_state > GST_STATE_READY) {
7845 // sync state with current pipeline
7846 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7847 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7848 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7850 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7851 if (GST_STATE_CHANGE_FAILURE == ret) {
7852 LOGE("fail to state change.");
7853 result = MM_ERROR_PLAYER_INTERNAL;
7857 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7858 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7861 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7862 gst_object_unref(curr_clock);
7865 // seek to current position
7866 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7867 result = MM_ERROR_PLAYER_INVALID_STATE;
7868 LOGE("gst_element_query_position failed, invalid state");
7872 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7873 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);
7875 _mmplayer_gst_send_event_to_sink(player, event);
7877 result = MM_ERROR_PLAYER_INTERNAL;
7878 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7882 /* sync state with current pipeline */
7883 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7884 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7885 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7887 return MM_ERROR_NONE;
7890 /* release text pipeline resource */
7891 player->textsink_linked = 0;
7893 /* release signal */
7894 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7896 /* release textbin with it's childs */
7897 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7898 MMPLAYER_FREEIF(player->pipeline->textbin);
7899 player->pipeline->textbin = NULL;
7901 /* release subtitle elem */
7902 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7903 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7909 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7911 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7912 GstState current_state = GST_STATE_VOID_PENDING;
7914 MMHandleType attrs = 0;
7915 mmplayer_gst_element_t *mainbin = NULL;
7916 mmplayer_gst_element_t *textbin = NULL;
7918 gchar *subtitle_uri = NULL;
7919 int result = MM_ERROR_NONE;
7920 const gchar *charset = NULL;
7924 /* check player handle */
7925 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7927 player->pipeline->mainbin &&
7928 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7929 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7931 mainbin = player->pipeline->mainbin;
7932 textbin = player->pipeline->textbin;
7934 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7935 if (current_state < GST_STATE_READY) {
7936 result = MM_ERROR_PLAYER_INVALID_STATE;
7937 LOGE("Pipeline is not in proper state");
7941 attrs = MMPLAYER_GET_ATTRS(player);
7943 LOGE("cannot get content attribute");
7944 result = MM_ERROR_PLAYER_INTERNAL;
7948 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7949 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7950 LOGE("subtitle uri is not proper filepath");
7951 result = MM_ERROR_PLAYER_INVALID_URI;
7955 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7956 LOGE("failed to get storage info of subtitle path");
7957 result = MM_ERROR_PLAYER_INVALID_URI;
7961 LOGD("old subtitle file path is [%s]", subtitle_uri);
7962 LOGD("new subtitle file path is [%s]", filepath);
7964 if (!strcmp(filepath, subtitle_uri)) {
7965 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7968 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7969 if (mm_attrs_commit_all(player->attrs)) {
7970 LOGE("failed to commit.");
7975 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7976 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7977 player->subtitle_language_list = NULL;
7978 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7980 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7981 if (ret != GST_STATE_CHANGE_SUCCESS) {
7982 LOGE("failed to change state of textbin to READY");
7983 result = MM_ERROR_PLAYER_INTERNAL;
7987 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7988 if (ret != GST_STATE_CHANGE_SUCCESS) {
7989 LOGE("failed to change state of subparse to READY");
7990 result = MM_ERROR_PLAYER_INTERNAL;
7994 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7995 if (ret != GST_STATE_CHANGE_SUCCESS) {
7996 LOGE("failed to change state of filesrc to READY");
7997 result = MM_ERROR_PLAYER_INTERNAL;
8001 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8003 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8005 charset = _mmplayer_get_charset(filepath);
8007 LOGD("detected charset is %s", charset);
8008 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8011 result = _mmplayer_sync_subtitle_pipeline(player);
8018 /* API to switch between external subtitles */
8020 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8022 int result = MM_ERROR_NONE;
8023 mmplayer_t *player = (mmplayer_t *)hplayer;
8028 /* check player handle */
8029 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8031 /* filepath can be null in idle state */
8033 /* check file path */
8034 if ((path = strstr(filepath, "file://")))
8035 result = _mmplayer_exist_file_path(path + 7);
8037 result = _mmplayer_exist_file_path(filepath);
8039 if (result != MM_ERROR_NONE) {
8040 LOGE("invalid subtitle path 0x%X", result);
8041 return result; /* file not found or permission denied */
8045 if (!player->pipeline) {
8047 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8048 if (mm_attrs_commit_all(player->attrs)) {
8049 LOGE("failed to commit"); /* subtitle path will not be created */
8050 return MM_ERROR_PLAYER_INTERNAL;
8053 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8054 /* check filepath */
8055 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8057 if (!__mmplayer_check_subtitle(player)) {
8058 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8059 if (mm_attrs_commit_all(player->attrs)) {
8060 LOGE("failed to commit");
8061 return MM_ERROR_PLAYER_INTERNAL;
8064 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8065 LOGE("fail to create text pipeline");
8066 return MM_ERROR_PLAYER_INTERNAL;
8069 result = _mmplayer_sync_subtitle_pipeline(player);
8071 result = __mmplayer_change_external_subtitle_language(player, filepath);
8074 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8075 player->is_external_subtitle_added_now = TRUE;
8077 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8078 if (!player->subtitle_language_list) {
8079 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8080 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8081 LOGW("subtitle language list is not updated yet");
8083 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8091 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8093 int result = MM_ERROR_NONE;
8094 gchar *change_pad_name = NULL;
8095 GstPad *sinkpad = NULL;
8096 mmplayer_gst_element_t *mainbin = NULL;
8097 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8098 GstCaps *caps = NULL;
8099 gint total_track_num = 0;
8103 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8104 MM_ERROR_PLAYER_NOT_INITIALIZED);
8106 LOGD("Change Track(%d) to %d", type, index);
8108 mainbin = player->pipeline->mainbin;
8110 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8111 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8112 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8113 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8115 /* Changing Video Track is not supported. */
8116 LOGE("Track Type Error");
8120 if (mainbin[elem_idx].gst == NULL) {
8121 result = MM_ERROR_PLAYER_NO_OP;
8122 LOGD("Req track doesn't exist");
8126 total_track_num = player->selector[type].total_track_num;
8127 if (total_track_num <= 0) {
8128 result = MM_ERROR_PLAYER_NO_OP;
8129 LOGD("Language list is not available");
8133 if ((index < 0) || (index >= total_track_num)) {
8134 result = MM_ERROR_INVALID_ARGUMENT;
8135 LOGD("Not a proper index : %d", index);
8139 /*To get the new pad from the selector*/
8140 change_pad_name = g_strdup_printf("sink_%u", index);
8141 if (change_pad_name == NULL) {
8142 result = MM_ERROR_PLAYER_INTERNAL;
8143 LOGD("Pad does not exists");
8147 LOGD("new active pad name: %s", change_pad_name);
8149 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8150 if (sinkpad == NULL) {
8151 LOGD("sinkpad is NULL");
8152 result = MM_ERROR_PLAYER_INTERNAL;
8156 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8157 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8159 caps = gst_pad_get_current_caps(sinkpad);
8160 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8163 gst_object_unref(sinkpad);
8165 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8166 __mmplayer_set_audio_attrs(player, caps);
8169 MMPLAYER_FREEIF(change_pad_name);
8174 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8176 int result = MM_ERROR_NONE;
8177 mmplayer_t *player = NULL;
8178 mmplayer_gst_element_t *mainbin = NULL;
8180 gint current_active_index = 0;
8182 GstState current_state = GST_STATE_VOID_PENDING;
8183 GstEvent *event = NULL;
8188 player = (mmplayer_t *)hplayer;
8189 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8191 if (!player->pipeline) {
8192 LOGE("Track %d pre setting -> %d", type, index);
8194 player->selector[type].active_pad_index = index;
8198 mainbin = player->pipeline->mainbin;
8200 current_active_index = player->selector[type].active_pad_index;
8202 /*If index is same as running index no need to change the pad*/
8203 if (current_active_index == index)
8206 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8207 result = MM_ERROR_PLAYER_INVALID_STATE;
8211 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8212 if (current_state < GST_STATE_PAUSED) {
8213 result = MM_ERROR_PLAYER_INVALID_STATE;
8214 LOGW("Pipeline not in porper state");
8218 result = __mmplayer_change_selector_pad(player, type, index);
8219 if (result != MM_ERROR_NONE) {
8220 LOGE("change selector pad error");
8224 player->selector[type].active_pad_index = index;
8226 if (current_state == GST_STATE_PLAYING) {
8227 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8228 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8229 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8231 _mmplayer_gst_send_event_to_sink(player, event);
8233 result = MM_ERROR_PLAYER_INTERNAL;
8243 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8245 mmplayer_t *player = (mmplayer_t *)hplayer;
8249 /* check player handle */
8250 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8252 *silent = player->set_mode.subtitle_off;
8254 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8258 return MM_ERROR_NONE;
8262 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8264 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8265 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8267 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8268 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8272 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8273 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8274 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8275 mmplayer_dump_t *dump_s;
8276 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8277 if (dump_s == NULL) {
8278 LOGE("malloc fail");
8282 dump_s->dump_element_file = NULL;
8283 dump_s->dump_pad = NULL;
8284 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8286 if (dump_s->dump_pad) {
8287 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8288 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]);
8289 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8290 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);
8291 /* add list for removed buffer probe and close FILE */
8292 player->dump_list = g_list_append(player->dump_list, dump_s);
8293 LOGD("%s sink pad added buffer probe for dump", factory_name);
8296 MMPLAYER_FREEIF(dump_s);
8297 LOGE("failed to get %s sink pad added", factory_name);
8304 static GstPadProbeReturn
8305 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8307 FILE *dump_data = (FILE *)u_data;
8309 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8310 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8312 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8314 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8316 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8318 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8320 gst_buffer_unmap(buffer, &probe_info);
8322 return GST_PAD_PROBE_OK;
8326 __mmplayer_release_dump_list(GList *dump_list)
8328 GList *d_list = dump_list;
8333 for (; d_list; d_list = g_list_next(d_list)) {
8334 mmplayer_dump_t *dump_s = d_list->data;
8335 if (dump_s->dump_pad) {
8336 if (dump_s->probe_handle_id)
8337 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8338 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8340 if (dump_s->dump_element_file) {
8341 fclose(dump_s->dump_element_file);
8342 dump_s->dump_element_file = NULL;
8344 MMPLAYER_FREEIF(dump_s);
8346 g_list_free(dump_list);
8351 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8353 mmplayer_t *player = (mmplayer_t *)hplayer;
8357 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8358 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8360 *exist = (bool)player->has_closed_caption;
8364 return MM_ERROR_NONE;
8368 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8372 // LOGD("unref internal gst buffer %p", buffer);
8373 gst_buffer_unref((GstBuffer *)buffer);
8380 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8382 mmplayer_t *player = (mmplayer_t *)hplayer;
8386 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8387 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8389 if (MMPLAYER_IS_STREAMING(player))
8390 *timeout = (int)player->ini.live_state_change_timeout;
8392 *timeout = (int)player->ini.localplayback_state_change_timeout;
8394 LOGD("timeout = %d", *timeout);
8397 return MM_ERROR_NONE;
8401 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8405 MMPLAYER_RETURN_IF_FAIL(player);
8407 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8409 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8410 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8411 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8412 player->storage_info[i].id = -1;
8413 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8415 if (path_type != MMPLAYER_PATH_MAX)
8424 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8426 int ret = MM_ERROR_NONE;
8427 mmplayer_t *player = (mmplayer_t *)hplayer;
8428 MMMessageParamType msg_param = {0, };
8431 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8433 LOGW("state changed storage %d:%d", id, state);
8435 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8436 return MM_ERROR_NONE;
8438 /* FIXME: text path should be handled seperately. */
8439 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8440 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8441 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8442 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8443 LOGW("external storage is removed");
8445 if (player->msg_posted == FALSE) {
8446 memset(&msg_param, 0, sizeof(MMMessageParamType));
8447 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8448 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8449 player->msg_posted = TRUE;
8452 /* unrealize the player */
8453 ret = _mmplayer_unrealize(hplayer);
8454 if (ret != MM_ERROR_NONE)
8455 LOGE("failed to unrealize");
8463 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8465 int ret = MM_ERROR_NONE;
8466 mmplayer_t *player = (mmplayer_t *)hplayer;
8467 int idx = 0, total = 0;
8468 gchar *result = NULL, *tmp = NULL;
8471 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8472 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8474 total = *num = g_list_length(player->adaptive_info.var_list);
8476 LOGW("There is no stream variant info.");
8480 result = g_strdup("");
8481 for (idx = 0 ; idx < total ; idx++) {
8482 stream_variant_t *v_data = NULL;
8483 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8486 gchar data[64] = {0};
8487 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8489 tmp = g_strconcat(result, data, NULL);
8493 LOGW("There is no variant data in %d", idx);
8498 *var_info = (char *)result;
8500 LOGD("variant info %d:%s", *num, *var_info);
8506 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8508 int ret = MM_ERROR_NONE;
8509 mmplayer_t *player = (mmplayer_t *)hplayer;
8512 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8514 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8516 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8517 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8518 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8520 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8521 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8522 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8523 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8525 /* FIXME: seek to current position for applying new variant limitation */
8534 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8536 int ret = MM_ERROR_NONE;
8537 mmplayer_t *player = (mmplayer_t *)hplayer;
8540 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8541 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8543 *bandwidth = player->adaptive_info.limit.bandwidth;
8544 *width = player->adaptive_info.limit.width;
8545 *height = player->adaptive_info.limit.height;
8547 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8554 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8556 int ret = MM_ERROR_NONE;
8557 mmplayer_t *player = (mmplayer_t *)hplayer;
8560 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8561 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8562 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8564 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8566 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8567 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8568 else /* live case */
8569 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8571 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8578 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8580 #define IDX_FIRST_SW_CODEC 0
8581 mmplayer_t *player = (mmplayer_t *)hplayer;
8582 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8583 MMHandleType attrs = 0;
8586 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8588 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8589 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8590 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8592 switch (stream_type) {
8593 case MM_PLAYER_STREAM_TYPE_AUDIO:
8594 /* to support audio codec selection, codec info have to be added in ini file as below.
8595 audio codec element hw = xxxx
8596 audio codec element sw = avdec */
8597 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8598 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8599 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8600 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8601 LOGE("There is no audio codec info for codec_type %d", codec_type);
8602 return MM_ERROR_PLAYER_NO_OP;
8605 case MM_PLAYER_STREAM_TYPE_VIDEO:
8606 /* to support video codec selection, codec info have to be added in ini file as below.
8607 video codec element hw = omx
8608 video codec element sw = avdec */
8609 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8610 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8611 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8612 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8613 LOGE("There is no video codec info for codec_type %d", codec_type);
8614 return MM_ERROR_PLAYER_NO_OP;
8618 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8619 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8623 LOGD("update %s codec_type to %d", attr_name, codec_type);
8625 attrs = MMPLAYER_GET_ATTRS(player);
8626 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8628 if (mm_attrs_commit_all(player->attrs)) {
8629 LOGE("failed to commit codec_type attributes");
8630 return MM_ERROR_PLAYER_INTERNAL;
8634 return MM_ERROR_NONE;
8638 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8640 mmplayer_t *player = (mmplayer_t *)hplayer;
8641 GstElement *rg_vol_element = NULL;
8645 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8647 player->sound.rg_enable = enabled;
8649 /* just hold rgvolume enable value if pipeline is not ready */
8650 if (!player->pipeline || !player->pipeline->audiobin) {
8651 LOGD("pipeline is not ready. holding rgvolume enable value");
8652 return MM_ERROR_NONE;
8655 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8657 if (!rg_vol_element) {
8658 LOGD("rgvolume element is not created");
8659 return MM_ERROR_PLAYER_INTERNAL;
8663 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8665 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8669 return MM_ERROR_NONE;
8673 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8675 mmplayer_t *player = (mmplayer_t *)hplayer;
8676 GstElement *rg_vol_element = NULL;
8677 gboolean enable = FALSE;
8681 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8682 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8684 /* just hold enable_rg value if pipeline is not ready */
8685 if (!player->pipeline || !player->pipeline->audiobin) {
8686 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8687 *enabled = player->sound.rg_enable;
8688 return MM_ERROR_NONE;
8691 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8693 if (!rg_vol_element) {
8694 LOGD("rgvolume element is not created");
8695 return MM_ERROR_PLAYER_INTERNAL;
8698 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8699 *enabled = (bool)enable;
8703 return MM_ERROR_NONE;
8707 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8709 mmplayer_t *player = (mmplayer_t *)hplayer;
8710 MMHandleType attrs = 0;
8711 void *handle = NULL;
8712 int ret = MM_ERROR_NONE;
8716 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8718 attrs = MMPLAYER_GET_ATTRS(player);
8719 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8721 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8723 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8724 return MM_ERROR_PLAYER_INTERNAL;
8727 player->video_roi.scale_x = scale_x;
8728 player->video_roi.scale_y = scale_y;
8729 player->video_roi.scale_width = scale_width;
8730 player->video_roi.scale_height = scale_height;
8732 /* check video sinkbin is created */
8733 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8734 return MM_ERROR_NONE;
8736 if (!gst_video_overlay_set_video_roi_area(
8737 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8738 scale_x, scale_y, scale_width, scale_height))
8739 ret = MM_ERROR_PLAYER_INTERNAL;
8741 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8742 scale_x, scale_y, scale_width, scale_height);
8750 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8752 mmplayer_t *player = (mmplayer_t *)hplayer;
8753 int ret = MM_ERROR_NONE;
8757 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8758 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8760 *scale_x = player->video_roi.scale_x;
8761 *scale_y = player->video_roi.scale_y;
8762 *scale_width = player->video_roi.scale_width;
8763 *scale_height = player->video_roi.scale_height;
8765 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8766 *scale_x, *scale_y, *scale_width, *scale_height);
8772 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8774 mmplayer_t* player = (mmplayer_t*)hplayer;
8778 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8780 player->client_pid = pid;
8782 LOGD("client pid[%d] %p", pid, player);
8786 return MM_ERROR_NONE;
8790 __mmplayer_update_duration_value(mmplayer_t *player)
8792 gboolean ret = FALSE;
8793 gint64 dur_nsec = 0;
8794 LOGD("try to update duration");
8796 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8797 player->duration = dur_nsec;
8798 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8802 if (player->duration < 0) {
8803 LOGW("duration is Non-Initialized !!!");
8804 player->duration = 0;
8807 /* update streaming service type */
8808 player->streaming_type = _mmplayer_get_stream_service_type(player);
8810 /* check duration is OK */
8811 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8812 /* FIXIT : find another way to get duration here. */
8813 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8819 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8821 /* update audio params
8822 NOTE : We need original audio params and it can be only obtained from src pad of audio
8823 decoder. Below code only valid when we are not using 'resampler' just before
8824 'audioconverter'. */
8825 GstCaps *caps_a = NULL;
8827 gint samplerate = 0, channels = 0;
8828 GstStructure *p = NULL;
8829 GstElement *aconv = NULL;
8831 LOGD("try to update audio attrs");
8833 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8835 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8836 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8837 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8838 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8840 LOGE("there is no audio converter");
8844 pad = gst_element_get_static_pad(aconv, "sink");
8847 LOGW("failed to get pad from audio converter");
8851 caps_a = gst_pad_get_current_caps(pad);
8853 LOGW("not ready to get audio caps");
8854 gst_object_unref(pad);
8858 p = gst_caps_get_structure(caps_a, 0);
8860 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8862 gst_structure_get_int(p, "rate", &samplerate);
8863 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8865 gst_structure_get_int(p, "channels", &channels);
8866 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8868 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8870 gst_caps_unref(caps_a);
8871 gst_object_unref(pad);
8877 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8879 LOGD("try to update video attrs");
8881 GstCaps *caps_v = NULL;
8885 GstStructure *p = NULL;
8887 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8888 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8890 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8892 LOGD("no videosink sink pad");
8896 caps_v = gst_pad_get_current_caps(pad);
8897 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8898 if (!caps_v && player->v_stream_caps) {
8899 caps_v = player->v_stream_caps;
8900 gst_caps_ref(caps_v);
8904 LOGD("no negitiated caps from videosink");
8905 gst_object_unref(pad);
8909 p = gst_caps_get_structure(caps_v, 0);
8910 gst_structure_get_int(p, "width", &width);
8911 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8913 gst_structure_get_int(p, "height", &height);
8914 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8916 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8918 SECURE_LOGD("width : %d height : %d", width, height);
8920 gst_caps_unref(caps_v);
8921 gst_object_unref(pad);
8924 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8925 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8932 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8934 gboolean ret = FALSE;
8935 guint64 data_size = 0;
8939 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8940 if (!player->duration)
8943 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8944 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8945 if (stat(path, &sb) == 0)
8946 data_size = (guint64)sb.st_size;
8948 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8949 data_size = player->http_content_size;
8952 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8955 guint64 bitrate = 0;
8956 guint64 msec_dur = 0;
8958 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8960 bitrate = data_size * 8 * 1000 / msec_dur;
8961 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8962 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8966 LOGD("player duration is less than 0");
8970 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8971 if (player->total_bitrate) {
8972 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8981 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8983 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8984 data->uri_type = uri_type;
8988 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8990 int ret = MM_ERROR_PLAYER_INVALID_URI;
8992 char *buffer = NULL;
8993 char *seperator = strchr(path, ',');
8994 char ext[100] = {0,}, size[100] = {0,};
8997 if ((buffer = strstr(path, "ext="))) {
8998 buffer += strlen("ext=");
9000 if (strlen(buffer)) {
9001 strncpy(ext, buffer, 99);
9003 if ((seperator = strchr(ext, ','))
9004 || (seperator = strchr(ext, ' '))
9005 || (seperator = strchr(ext, '\0'))) {
9006 seperator[0] = '\0';
9011 if ((buffer = strstr(path, "size="))) {
9012 buffer += strlen("size=");
9014 if (strlen(buffer) > 0) {
9015 strncpy(size, buffer, 99);
9017 if ((seperator = strchr(size, ','))
9018 || (seperator = strchr(size, ' '))
9019 || (seperator = strchr(size, '\0'))) {
9020 seperator[0] = '\0';
9023 mem_size = atoi(size);
9028 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9030 if (mem_size && param) {
9031 if (data->input_mem.buf)
9032 free(data->input_mem.buf);
9033 data->input_mem.buf = malloc(mem_size);
9035 if (data->input_mem.buf) {
9036 memcpy(data->input_mem.buf, param, mem_size);
9037 data->input_mem.len = mem_size;
9038 ret = MM_ERROR_NONE;
9040 LOGE("failed to alloc mem %d", mem_size);
9041 ret = MM_ERROR_PLAYER_INTERNAL;
9044 data->input_mem.offset = 0;
9045 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9052 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9054 gchar *location = NULL;
9057 int ret = MM_ERROR_NONE;
9059 if ((path = strstr(uri, "file://"))) {
9060 location = g_filename_from_uri(uri, NULL, &err);
9061 if (!location || (err != NULL)) {
9062 LOGE("Invalid URI '%s' for filesrc: %s", path,
9063 (err != NULL) ? err->message : "unknown error");
9067 MMPLAYER_FREEIF(location);
9069 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9070 return MM_ERROR_PLAYER_INVALID_URI;
9072 LOGD("path from uri: %s", location);
9075 path = (location != NULL) ? (location) : ((char *)uri);
9078 ret = _mmplayer_exist_file_path(path);
9080 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9081 if (ret == MM_ERROR_NONE) {
9082 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9083 if (_mmplayer_is_sdp_file(path)) {
9084 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9085 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9087 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9089 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9090 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9092 LOGE("invalid uri, could not play..");
9093 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9096 MMPLAYER_FREEIF(location);
9101 static mmplayer_video_decoded_data_info_t *
9102 __mmplayer_create_stream_from_pad(GstPad *pad)
9104 GstCaps *caps = NULL;
9105 GstStructure *structure = NULL;
9106 unsigned int fourcc = 0;
9107 const gchar *string_format = NULL;
9108 mmplayer_video_decoded_data_info_t *stream = NULL;
9110 MMPixelFormatType format;
9113 caps = gst_pad_get_current_caps(pad);
9115 LOGE("Caps is NULL.");
9119 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9120 structure = gst_caps_get_structure(caps, 0);
9121 gst_structure_get_int(structure, "width", &width);
9122 gst_structure_get_int(structure, "height", &height);
9123 string_format = gst_structure_get_string(structure, "format");
9126 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9127 format = _mmplayer_get_pixtype(fourcc);
9128 gst_video_info_from_caps(&info, caps);
9129 gst_caps_unref(caps);
9132 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9133 LOGE("Wrong condition!!");
9137 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9139 LOGE("failed to alloc mem for video data");
9143 stream->width = width;
9144 stream->height = height;
9145 stream->format = format;
9146 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9152 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9154 unsigned int pitch = 0;
9155 unsigned int size = 0;
9157 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9160 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9161 bo = gst_tizen_memory_get_bos(mem, index);
9163 stream->bo[index] = tbm_bo_ref(bo);
9165 LOGE("failed to get bo for index %d", index);
9168 for (index = 0; index < stream->plane_num; index++) {
9169 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9170 stream->stride[index] = pitch;
9172 stream->elevation[index] = size / pitch;
9174 stream->elevation[index] = stream->height;
9179 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9181 if (stream->format == MM_PIXEL_FORMAT_I420) {
9182 int ret = TBM_SURFACE_ERROR_NONE;
9183 tbm_surface_h surface;
9184 tbm_surface_info_s info;
9186 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9188 ret = tbm_surface_get_info(surface, &info);
9189 if (ret != TBM_SURFACE_ERROR_NONE) {
9190 tbm_surface_destroy(surface);
9194 tbm_surface_destroy(surface);
9195 stream->stride[0] = info.planes[0].stride;
9196 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9197 stream->stride[1] = info.planes[1].stride;
9198 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9199 stream->stride[2] = info.planes[2].stride;
9200 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9201 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9202 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9203 stream->stride[0] = stream->width * 4;
9204 stream->elevation[0] = stream->height;
9205 stream->bo_size = stream->stride[0] * stream->height;
9207 LOGE("Not support format %d", stream->format);
9215 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9217 tbm_bo_handle thandle;
9219 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9220 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9221 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9225 unsigned char *src = NULL;
9226 unsigned char *dest = NULL;
9227 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9229 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9231 LOGE("fail to gst_memory_map");
9235 if (!mapinfo.data) {
9236 LOGE("data pointer is wrong");
9240 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9241 if (!stream->bo[0]) {
9242 LOGE("Fail to tbm_bo_alloc!!");
9246 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9248 LOGE("thandle pointer is wrong");
9252 if (stream->format == MM_PIXEL_FORMAT_I420) {
9253 src_stride[0] = GST_ROUND_UP_4(stream->width);
9254 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9255 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9256 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9259 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9260 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9262 for (i = 0; i < 3; i++) {
9263 src = mapinfo.data + src_offset[i];
9264 dest = thandle.ptr + dest_offset[i];
9269 for (j = 0; j < stream->height >> k; j++) {
9270 memcpy(dest, src, stream->width>>k);
9271 src += src_stride[i];
9272 dest += stream->stride[i];
9275 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9276 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9278 LOGE("Not support format %d", stream->format);
9282 tbm_bo_unmap(stream->bo[0]);
9283 gst_memory_unmap(mem, &mapinfo);
9289 tbm_bo_unmap(stream->bo[0]);
9292 gst_memory_unmap(mem, &mapinfo);
9298 __mmplayer_set_pause_state(mmplayer_t *player)
9300 if (player->sent_bos)
9303 /* rtsp case, get content attrs by GstMessage */
9304 if (MMPLAYER_IS_RTSP_STREAMING(player))
9307 /* it's first time to update all content attrs. */
9308 _mmplayer_update_content_attrs(player, ATTR_ALL);
9312 __mmplayer_set_playing_state(mmplayer_t *player)
9314 gchar *audio_codec = NULL;
9316 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9317 /* initialize because auto resume is done well. */
9318 player->resumed_by_rewind = FALSE;
9319 player->playback_rate = 1.0;
9322 if (player->sent_bos)
9325 /* try to get content metadata */
9327 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9328 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9329 * legacy mmfw-player api
9331 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9333 if ((player->cmd == MMPLAYER_COMMAND_START)
9334 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9335 __mmplayer_handle_missed_plugin(player);
9338 /* check audio codec field is set or not
9339 * we can get it from typefinder or codec's caps.
9341 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9343 /* The codec format can't be sent for audio only case like amr, mid etc.
9344 * Because, parser don't make related TAG.
9345 * So, if it's not set yet, fill it with found data.
9348 if (g_strrstr(player->type, "audio/midi"))
9349 audio_codec = "MIDI";
9350 else if (g_strrstr(player->type, "audio/x-amr"))
9351 audio_codec = "AMR";
9352 else if (g_strrstr(player->type, "audio/mpeg")
9353 && !g_strrstr(player->type, "mpegversion=(int)1"))
9354 audio_codec = "AAC";
9356 audio_codec = "unknown";
9358 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9360 if (mm_attrs_commit_all(player->attrs))
9361 LOGE("failed to update attributes");
9363 LOGD("set audio codec type with caps");