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_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
146 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
147 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
150 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
151 static void __mmplayer_release_misc(mmplayer_t *player);
152 static void __mmplayer_release_misc_post(mmplayer_t *player);
153 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
154 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
155 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
156 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
157 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
159 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
160 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
161 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
162 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
163 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
164 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
165 static gpointer __mmplayer_gapless_play_thread(gpointer data);
166 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
167 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
168 static void __mmplayer_release_dump_list(GList *dump_list);
169 static int __mmplayer_gst_realize(mmplayer_t *player);
170 static int __mmplayer_gst_unrealize(mmplayer_t *player);
171 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
172 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
175 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
176 static void __mmplayer_check_pipeline(mmplayer_t *player);
177 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
178 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
179 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
180 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
181 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
182 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
183 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
184 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
185 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
187 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
189 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
190 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
191 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
193 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
194 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
195 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
196 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
198 static void __mmplayer_set_pause_state(mmplayer_t *player);
199 static void __mmplayer_set_playing_state(mmplayer_t *player);
200 /*===========================================================================================
202 | FUNCTION DEFINITIONS |
204 ========================================================================================== */
208 print_tag(const GstTagList *list, const gchar *tag, gpointer unused)
212 count = gst_tag_list_get_tag_size(list, tag);
214 LOGD("count = %d", count);
216 for (i = 0; i < count; i++) {
219 if (gst_tag_get_type(tag) == G_TYPE_STRING) {
220 if (!gst_tag_list_get_string_index(list, tag, i, &str))
221 g_assert_not_reached();
223 str = g_strdup_value_contents(gst_tag_list_get_value_index(list, tag, i));
227 g_print(" %15s: %s", gst_tag_get_nick(tag), str);
229 g_print(" : %s", str);
236 /* This function should be called after the pipeline goes PAUSED or higher
239 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
241 static gboolean has_duration = FALSE;
242 static gboolean has_video_attrs = FALSE;
243 static gboolean has_audio_attrs = FALSE;
244 static gboolean has_bitrate = FALSE;
245 gboolean missing_only = FALSE;
246 gboolean all = FALSE;
247 MMHandleType attrs = 0;
251 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
253 /* check player state here */
254 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
255 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
256 /* give warning now only */
257 LOGW("be careful. content attributes may not available in this state ");
260 /* get content attribute first */
261 attrs = MMPLAYER_GET_ATTRS(player);
263 LOGE("cannot get content attribute");
267 /* get update flag */
269 if (flag & ATTR_MISSING_ONLY) {
271 LOGD("updating missed attr only");
274 if (flag & ATTR_ALL) {
276 has_duration = FALSE;
277 has_video_attrs = FALSE;
278 has_audio_attrs = FALSE;
281 LOGD("updating all attrs");
284 if (missing_only && all) {
285 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
286 missing_only = FALSE;
289 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
290 has_duration = __mmplayer_update_duration_value(player);
292 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
293 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
295 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
296 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
298 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
299 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
302 if (mm_attrs_commit_all(attrs)) {
303 LOGE("failed to update attributes");
313 _mmplayer_get_stream_service_type(mmplayer_t *player)
315 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
319 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
321 player->pipeline->mainbin &&
322 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
323 STREAMING_SERVICE_NONE);
325 /* streaming service type if streaming */
326 if (!MMPLAYER_IS_STREAMING(player))
327 return STREAMING_SERVICE_NONE;
329 streaming_type = (player->duration == 0) ?
330 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
332 switch (streaming_type) {
333 case STREAMING_SERVICE_LIVE:
334 LOGD("it's live streaming");
336 case STREAMING_SERVICE_VOD:
337 LOGD("it's vod streaming");
340 LOGE("should not get here");
346 return streaming_type;
349 /* this function sets the player state and also report
350 * it to applicaton by calling callback function
353 _mmplayer_set_state(mmplayer_t *player, int state)
355 MMMessageParamType msg = {0, };
357 MMPLAYER_RETURN_IF_FAIL(player);
359 if (MMPLAYER_CURRENT_STATE(player) == state) {
360 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
361 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
365 /* update player states */
366 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
367 MMPLAYER_CURRENT_STATE(player) = state;
369 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
370 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
373 MMPLAYER_PRINT_STATE(player);
375 switch (MMPLAYER_CURRENT_STATE(player)) {
376 case MM_PLAYER_STATE_NULL:
377 case MM_PLAYER_STATE_READY:
379 case MM_PLAYER_STATE_PAUSED:
380 __mmplayer_set_pause_state(player);
382 case MM_PLAYER_STATE_PLAYING:
383 __mmplayer_set_playing_state(player);
385 case MM_PLAYER_STATE_NONE:
387 LOGW("invalid target state, there is nothing to do.");
392 /* post message to application */
393 if (MMPLAYER_TARGET_STATE(player) == state) {
394 /* fill the message with state of player */
395 msg.union_type = MM_MSG_UNION_STATE;
396 msg.state.previous = MMPLAYER_PREV_STATE(player);
397 msg.state.current = MMPLAYER_CURRENT_STATE(player);
399 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
401 /* state changed by resource callback */
402 if (player->interrupted_by_resource)
403 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
404 else /* state changed by usecase */
405 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
408 LOGD("intermediate state, do nothing.");
409 MMPLAYER_PRINT_STATE(player);
413 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
414 && !player->sent_bos) {
415 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
416 player->sent_bos = TRUE;
423 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
425 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
426 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
428 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
430 //LOGD("incomming command : %d ", command);
432 current_state = MMPLAYER_CURRENT_STATE(player);
433 pending_state = MMPLAYER_PENDING_STATE(player);
435 MMPLAYER_PRINT_STATE(player);
438 case MMPLAYER_COMMAND_CREATE:
440 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
442 if (current_state == MM_PLAYER_STATE_NULL ||
443 current_state == MM_PLAYER_STATE_READY ||
444 current_state == MM_PLAYER_STATE_PAUSED ||
445 current_state == MM_PLAYER_STATE_PLAYING)
450 case MMPLAYER_COMMAND_DESTROY:
452 /* destroy can called anytime */
454 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
458 case MMPLAYER_COMMAND_REALIZE:
460 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
462 if (pending_state != MM_PLAYER_STATE_NONE) {
465 /* need ready state to realize */
466 if (current_state == MM_PLAYER_STATE_READY)
469 if (current_state != MM_PLAYER_STATE_NULL)
475 case MMPLAYER_COMMAND_UNREALIZE:
477 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
479 if (current_state == MM_PLAYER_STATE_NULL)
484 case MMPLAYER_COMMAND_START:
486 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
488 if (pending_state == MM_PLAYER_STATE_NONE) {
489 if (current_state == MM_PLAYER_STATE_PLAYING)
491 else if (current_state != MM_PLAYER_STATE_READY &&
492 current_state != MM_PLAYER_STATE_PAUSED)
494 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
496 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
497 LOGD("player is going to paused state, just change the pending state as playing");
504 case MMPLAYER_COMMAND_STOP:
506 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
508 if (current_state == MM_PLAYER_STATE_READY)
511 /* need playing/paused state to stop */
512 if (current_state != MM_PLAYER_STATE_PLAYING &&
513 current_state != MM_PLAYER_STATE_PAUSED)
518 case MMPLAYER_COMMAND_PAUSE:
520 if (MMPLAYER_IS_LIVE_STREAMING(player))
523 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
524 goto NOT_COMPLETED_SEEK;
526 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
528 if (pending_state == MM_PLAYER_STATE_NONE) {
529 if (current_state == MM_PLAYER_STATE_PAUSED)
531 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
533 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
535 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
536 if (current_state == MM_PLAYER_STATE_PAUSED)
537 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
544 case MMPLAYER_COMMAND_RESUME:
546 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
547 goto NOT_COMPLETED_SEEK;
549 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
551 if (pending_state == MM_PLAYER_STATE_NONE) {
552 if (current_state == MM_PLAYER_STATE_PLAYING)
554 else if (current_state != MM_PLAYER_STATE_PAUSED)
556 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
558 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
559 LOGD("player is going to paused state, just change the pending state as playing");
569 player->cmd = command;
571 return MM_ERROR_NONE;
574 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
575 MMPLAYER_STATE_GET_NAME(current_state), command);
576 return MM_ERROR_PLAYER_INVALID_STATE;
579 LOGW("not completed seek");
580 return MM_ERROR_PLAYER_DOING_SEEK;
583 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
584 return MM_ERROR_PLAYER_NO_OP;
587 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
588 return MM_ERROR_PLAYER_NO_OP;
591 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
593 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
594 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
597 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
598 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
600 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
601 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
604 LOGE("invalid mmplayer resource type %d", type);
605 return MM_ERROR_PLAYER_INTERNAL;
608 if (player->hw_resource[type] != NULL) {
609 LOGD("[%d type] resource was already acquired", type);
610 return MM_ERROR_NONE;
613 LOGD("mark for acquire [%d type] resource", type);
614 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
615 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
616 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
617 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
618 return MM_ERROR_PLAYER_INTERNAL;
621 rm_ret = mm_resource_manager_commit(player->resource_manager);
622 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
623 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
624 return MM_ERROR_PLAYER_INTERNAL;
628 return MM_ERROR_NONE;
631 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
633 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
637 if (player->hw_resource[type] == NULL) {
638 LOGD("there is no acquired [%d type] resource", type);
639 return MM_ERROR_NONE;
642 LOGD("mark for release [%d type] resource", type);
643 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
644 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
645 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
646 return MM_ERROR_PLAYER_INTERNAL;
649 player->hw_resource[type] = NULL;
651 rm_ret = mm_resource_manager_commit(player->resource_manager);
652 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
653 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
654 return MM_ERROR_PLAYER_INTERNAL;
658 return MM_ERROR_NONE;
662 __mmplayer_initialize_gapless_play(mmplayer_t *player)
668 player->smooth_streaming = FALSE;
669 player->videodec_linked = 0;
670 player->audiodec_linked = 0;
671 player->textsink_linked = 0;
672 player->is_external_subtitle_present = FALSE;
673 player->is_external_subtitle_added_now = FALSE;
674 player->not_supported_codec = MISSING_PLUGIN_NONE;
675 player->can_support_codec = FOUND_PLUGIN_NONE;
676 player->pending_seek.is_pending = false;
677 player->pending_seek.pos = 0;
678 player->msg_posted = FALSE;
679 player->has_many_types = FALSE;
680 player->no_more_pad = FALSE;
681 player->not_found_demuxer = 0;
682 player->seek_state = MMPLAYER_SEEK_NONE;
683 player->is_subtitle_force_drop = FALSE;
684 player->play_subtitle = FALSE;
685 player->adjust_subtitle_pos = 0;
687 player->total_bitrate = 0;
688 player->total_maximum_bitrate = 0;
690 _mmplayer_track_initialize(player);
691 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
693 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
694 player->bitrate[i] = 0;
695 player->maximum_bitrate[i] = 0;
698 if (player->v_stream_caps) {
699 gst_caps_unref(player->v_stream_caps);
700 player->v_stream_caps = NULL;
703 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
705 /* clean found audio decoders */
706 if (player->audio_decoders) {
707 GList *a_dec = player->audio_decoders;
708 for (; a_dec; a_dec = g_list_next(a_dec)) {
709 gchar *name = a_dec->data;
710 MMPLAYER_FREEIF(name);
712 g_list_free(player->audio_decoders);
713 player->audio_decoders = NULL;
716 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
722 __mmplayer_gapless_play_thread(gpointer data)
724 mmplayer_t *player = (mmplayer_t *)data;
725 mmplayer_gst_element_t *mainbin = NULL;
727 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
729 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
730 while (!player->gapless_play_thread_exit) {
731 LOGD("gapless play thread started. waiting for signal.");
732 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
734 LOGD("reconfigure pipeline for gapless play.");
736 if (player->gapless_play_thread_exit) {
737 if (player->gapless.reconfigure) {
738 player->gapless.reconfigure = false;
739 MMPLAYER_PLAYBACK_UNLOCK(player);
741 LOGD("exiting gapless play thread");
745 mainbin = player->pipeline->mainbin;
747 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
748 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
749 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
753 /* Initialize Player values */
754 __mmplayer_initialize_gapless_play(player);
756 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
758 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
764 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
766 GSource *source = NULL;
770 source = g_main_context_find_source_by_id(context, source_id);
771 if (source != NULL) {
772 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
773 g_source_destroy(source);
780 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
782 mmplayer_t *player = (mmplayer_t *)hplayer;
783 GstMessage *msg = NULL;
784 GQueue *queue = NULL;
787 MMPLAYER_RETURN_IF_FAIL(player);
789 /* disconnecting bus watch */
790 if (player->bus_watcher)
791 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
792 player->bus_watcher = 0;
794 /* destroy the gst bus msg thread */
795 if (player->bus_msg_thread) {
796 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
797 player->bus_msg_thread_exit = TRUE;
798 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
799 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
801 LOGD("gst bus msg thread exit.");
802 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
803 player->bus_msg_thread = NULL;
805 g_mutex_clear(&player->bus_msg_thread_mutex);
806 g_cond_clear(&player->bus_msg_thread_cond);
809 g_mutex_lock(&player->bus_msg_q_lock);
810 queue = player->bus_msg_q;
811 while (!g_queue_is_empty(queue)) {
812 msg = (GstMessage *)g_queue_pop_head(queue);
817 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
818 gst_message_unref(msg);
820 g_mutex_unlock(&player->bus_msg_q_lock);
826 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
828 GstElement *parent = NULL;
830 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
831 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
834 MMPLAYER_FSINK_LOCK(player);
836 /* get parent of fakesink */
837 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
839 LOGD("fakesink already removed");
843 gst_element_set_locked_state(fakesink->gst, TRUE);
845 /* setting the state to NULL never returns async
846 * so no need to wait for completion of state transiton
848 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
849 LOGE("fakesink state change failure!");
850 /* FIXIT : should I return here? or try to proceed to next? */
853 /* remove fakesink from it's parent */
854 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
855 LOGE("failed to remove fakesink");
857 gst_object_unref(parent);
862 gst_object_unref(parent);
864 LOGD("state-holder removed");
866 gst_element_set_locked_state(fakesink->gst, FALSE);
868 MMPLAYER_FSINK_UNLOCK(player);
873 gst_element_set_locked_state(fakesink->gst, FALSE);
875 MMPLAYER_FSINK_UNLOCK(player);
879 static GstPadProbeReturn
880 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
882 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
883 return GST_PAD_PROBE_OK;
887 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
889 gint64 stop_running_time = 0;
890 gint64 position_running_time = 0;
894 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
895 if ((player->gapless.update_segment[idx] == TRUE) ||
896 !(player->selector[idx].event_probe_id)) {
897 /* LOGW("[%d] skip", idx); */
901 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
903 gst_segment_to_running_time(&player->gapless.segment[idx],
904 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
905 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
907 gst_segment_to_running_time(&player->gapless.segment[idx],
908 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
910 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
912 gst_segment_to_running_time(&player->gapless.segment[idx],
913 GST_FORMAT_TIME, player->duration);
916 position_running_time =
917 gst_segment_to_running_time(&player->gapless.segment[idx],
918 GST_FORMAT_TIME, player->gapless.segment[idx].position);
920 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
921 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
923 GST_TIME_ARGS(stop_running_time),
924 GST_TIME_ARGS(position_running_time),
925 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
926 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
928 position_running_time = MAX(position_running_time, stop_running_time);
929 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
930 GST_FORMAT_TIME, player->gapless.segment[idx].start);
931 position_running_time = MAX(0, position_running_time);
932 position = MAX(position, position_running_time);
936 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
937 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
938 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
940 player->gapless.start_time[stream_type] += position;
946 static GstPadProbeReturn
947 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
949 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
950 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
951 mmplayer_t *player = (mmplayer_t *)data;
952 GstCaps *caps = NULL;
953 GstStructure *str = NULL;
954 const gchar *name = NULL;
955 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
956 gboolean caps_ret = TRUE;
958 if (GST_EVENT_IS_DOWNSTREAM(event) &&
959 GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
960 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
961 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
962 GST_EVENT_TYPE(event) != GST_EVENT_EOS) {
964 } else if (GST_EVENT_IS_UPSTREAM(event) &&
965 GST_EVENT_TYPE(event) != GST_EVENT_QOS) {
969 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
973 if (strstr(name, "audio")) {
974 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
975 } else if (strstr(name, "video")) {
976 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
978 /* text track is not supportable */
979 LOGE("invalid name %s", name);
983 switch (GST_EVENT_TYPE(event)) {
986 /* in case of gapless, drop eos event not to send it to sink */
987 if (player->gapless.reconfigure && !player->msg_posted) {
988 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
989 ret = GST_PAD_PROBE_DROP;
993 case GST_EVENT_STREAM_START:
995 __mmplayer_gst_selector_update_start_time(player, stream_type);
998 case GST_EVENT_FLUSH_STOP:
1000 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1001 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1002 player->gapless.start_time[stream_type] = 0;
1005 case GST_EVENT_SEGMENT:
1010 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1011 gst_event_copy_segment(event, &segment);
1013 if (segment.format != GST_FORMAT_TIME)
1016 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1017 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1018 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1019 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1020 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1021 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1023 /* keep the all the segment ev to cover the seeking */
1024 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1025 player->gapless.update_segment[stream_type] = TRUE;
1027 if (!player->gapless.running)
1030 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1032 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1034 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1035 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1036 gst_event_unref(event);
1037 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1043 gdouble proportion = 0.0;
1044 GstClockTimeDiff diff = 0;
1045 GstClockTime timestamp = 0;
1046 gint64 running_time_diff = -1;
1047 GstQOSType type = 0;
1048 GstEvent *tmpev = NULL;
1050 running_time_diff = player->gapless.segment[stream_type].base;
1052 if (running_time_diff <= 0) /* don't need to adjust */
1055 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1056 gst_event_unref(event);
1058 if (timestamp < running_time_diff) {
1059 LOGW("QOS event from previous group");
1060 ret = GST_PAD_PROBE_DROP;
1064 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1065 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1066 stream_type, GST_TIME_ARGS(timestamp),
1067 GST_TIME_ARGS(running_time_diff),
1068 GST_TIME_ARGS(timestamp - running_time_diff));
1070 timestamp -= running_time_diff;
1072 /* That case is invalid for QoS events */
1073 if (diff < 0 && -diff > timestamp) {
1074 LOGW("QOS event from previous group");
1075 ret = GST_PAD_PROBE_DROP;
1079 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1080 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1090 gst_caps_unref(caps);
1094 /* create fakesink for audio or video path witout audiobin or videobin */
1096 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1098 GstElement *pipeline = NULL;
1099 GstElement *fakesink = NULL;
1100 GstPad *sinkpad = NULL;
1103 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1105 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1108 fakesink = gst_element_factory_make("fakesink", NULL);
1109 if (fakesink == NULL) {
1110 LOGE("failed to create fakesink");
1114 /* store it as it's sink element */
1115 __mmplayer_add_sink(player, fakesink);
1117 gst_bin_add(GST_BIN(pipeline), fakesink);
1120 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1122 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1124 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1125 LOGE("failed to link fakesink");
1126 gst_object_unref(GST_OBJECT(fakesink));
1130 if (strstr(name, "video")) {
1131 if (player->v_stream_caps) {
1132 gst_caps_unref(player->v_stream_caps);
1133 player->v_stream_caps = NULL;
1135 if (player->ini.set_dump_element_flag)
1136 __mmplayer_add_dump_buffer_probe(player, fakesink);
1139 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1140 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1144 gst_object_unref(GST_OBJECT(sinkpad));
1151 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1153 GstElement *pipeline = NULL;
1154 GstElement *selector = NULL;
1155 GstPad *srcpad = NULL;
1158 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1160 selector = gst_element_factory_make("input-selector", NULL);
1162 LOGE("failed to create input-selector");
1165 g_object_set(selector, "sync-streams", TRUE, NULL);
1167 player->pipeline->mainbin[elem_idx].id = elem_idx;
1168 player->pipeline->mainbin[elem_idx].gst = selector;
1170 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1172 srcpad = gst_element_get_static_pad(selector, "src");
1174 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1175 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1176 __mmplayer_gst_selector_blocked, NULL, NULL);
1177 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1178 __mmplayer_gst_selector_event_probe, player, NULL);
1180 gst_element_set_state(selector, GST_STATE_PAUSED);
1182 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1183 gst_bin_add(GST_BIN(pipeline), selector);
1185 gst_object_unref(GST_OBJECT(srcpad));
1192 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1194 mmplayer_t *player = (mmplayer_t *)data;
1195 GstElement *selector = NULL;
1196 GstCaps *caps = NULL;
1197 GstStructure *str = NULL;
1198 const gchar *name = NULL;
1199 GstPad *sinkpad = NULL;
1200 gboolean first_track = FALSE;
1201 gboolean caps_ret = TRUE;
1203 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1204 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1207 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1208 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1210 LOGD("pad-added signal handling");
1212 /* get mimetype from caps */
1213 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1217 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1218 /* LOGD("detected mimetype : %s", name); */
1220 if (strstr(name, "video")) {
1222 gchar *caps_str = NULL;
1224 caps_str = gst_caps_to_string(caps);
1225 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1226 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1227 player->set_mode.video_zc = true;
1229 MMPLAYER_FREEIF(caps_str);
1231 mm_attrs_set_int_by_name(player->attrs, "content_video_found", TRUE);
1232 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1234 LOGD("surface type : %d", stype);
1236 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player)) {
1237 __mmplayer_gst_create_sinkbin(elem, pad, player);
1241 /* in case of exporting video frame, it requires the 360 video filter.
1242 * it will be handled in _no_more_pads(). */
1243 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1244 __mmplayer_gst_make_fakesink(player, pad, name);
1248 LOGD("video selector is required");
1249 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1250 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1251 } else if (strstr(name, "audio")) {
1252 gint samplerate = 0;
1255 if (MMPLAYER_IS_MS_BUFF_SRC(player) || MMPLAYER_USE_URIDECODEBIN3(player) || player->build_audio_offload) {
1256 if (player->build_audio_offload)
1257 player->no_more_pad = TRUE; /* remove state holder */
1258 __mmplayer_gst_create_sinkbin(elem, pad, player);
1262 gst_structure_get_int(str, "rate", &samplerate);
1263 gst_structure_get_int(str, "channels", &channels);
1265 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1266 __mmplayer_gst_make_fakesink(player, pad, name);
1270 LOGD("audio selector is required");
1271 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1272 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1274 } else if (strstr(name, "text")) {
1275 LOGD("text selector is required");
1276 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1277 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1279 LOGE("invalid caps info");
1283 /* check selector and create it */
1284 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1285 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1290 LOGD("input-selector is already created.");
1294 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1296 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1298 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1299 LOGE("failed to link selector");
1300 gst_object_unref(GST_OBJECT(selector));
1305 LOGD("this track will be activated");
1306 g_object_set(selector, "active-pad", sinkpad, NULL);
1309 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1315 gst_caps_unref(caps);
1318 gst_object_unref(GST_OBJECT(sinkpad));
1326 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1328 GstPad *srcpad = NULL;
1331 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1333 LOGD("type %d", type);
1336 LOGD("there is no %d track", type);
1340 srcpad = gst_element_get_static_pad(selector, "src");
1342 LOGE("failed to get srcpad from selector");
1346 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1348 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1350 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1351 if (player->selector[type].block_id) {
1352 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1353 player->selector[type].block_id = 0;
1357 gst_object_unref(GST_OBJECT(srcpad));
1366 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1368 MMHandleType attrs = 0;
1369 gint active_index = 0;
1372 MMPLAYER_RETURN_IF_FAIL(player);
1374 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1376 /* change track to active pad */
1377 active_index = player->selector[type].active_pad_index;
1378 if ((active_index != DEFAULT_TRACK) &&
1379 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1380 LOGW("failed to change %d type track to %d", type, active_index);
1381 player->selector[type].active_pad_index = DEFAULT_TRACK;
1385 if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
1386 attrs = MMPLAYER_GET_ATTRS(player);
1388 mm_attrs_set_int_by_name(attrs, "content_text_track_num", player->selector[type].total_track_num);
1389 mm_attrs_set_int_by_name(attrs, "current_text_track_index", player->selector[type].active_pad_index);
1391 if (mm_attrs_commit_all(attrs))
1392 LOGW("failed to commit attrs.");
1394 LOGW("cannot get content attribute");
1403 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1406 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1408 if (!audio_selector) {
1409 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1411 /* in case the source is changed, output can be changed. */
1412 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1413 LOGD("remove previous audiobin if it exist");
1415 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1416 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1418 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1419 MMPLAYER_FREEIF(player->pipeline->audiobin);
1422 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1423 _mmplayer_pipeline_complete(NULL, player);
1428 /* apply the audio track information */
1429 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1431 /* create audio sink path */
1432 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1433 LOGE("failed to create audio sink path");
1442 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1445 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1447 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1448 LOGD("text path is not supproted");
1452 /* apply the text track information */
1453 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1455 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1456 player->has_closed_caption = TRUE;
1458 /* create text decode path */
1459 player->no_more_pad = TRUE;
1461 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1462 LOGE("failed to create text sink path");
1471 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1473 gint64 dur_bytes = 0L;
1476 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1477 player->pipeline->mainbin && player->streamer, FALSE);
1479 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1480 LOGE("fail to get duration.");
1482 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1483 * use file information was already set on Q2 when it was created. */
1484 _mm_player_streaming_set_queue2(player->streamer,
1485 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1486 TRUE, /* use_buffering */
1487 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1488 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1495 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1497 mmplayer_t *player = NULL;
1498 GstElement *video_selector = NULL;
1499 GstElement *audio_selector = NULL;
1500 GstElement *text_selector = NULL;
1503 player = (mmplayer_t *)data;
1505 LOGD("no-more-pad signal handling");
1507 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1508 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1509 LOGW("player is shutting down");
1513 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1514 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1515 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1516 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1517 LOGE("failed to set queue2 buffering");
1522 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1523 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1524 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1526 if (!video_selector && !audio_selector && !text_selector) {
1527 LOGW("there is no selector");
1528 player->no_more_pad = TRUE;
1532 /* create video path followed by video-select */
1533 if (video_selector && !audio_selector && !text_selector)
1534 player->no_more_pad = TRUE;
1536 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1539 /* create audio path followed by audio-select */
1540 if (audio_selector && !text_selector)
1541 player->no_more_pad = TRUE;
1543 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1546 /* create text path followed by text-select */
1547 __mmplayer_create_text_sink_path(player, text_selector);
1550 if (player->gapless.reconfigure) {
1551 player->gapless.reconfigure = FALSE;
1552 MMPLAYER_PLAYBACK_UNLOCK(player);
1559 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1561 gboolean ret = FALSE;
1562 GstElement *pipeline = NULL;
1563 GstPad *sinkpad = NULL;
1566 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1567 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1569 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1571 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1573 LOGE("failed to get pad from sinkbin");
1579 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1580 LOGE("failed to link sinkbin for reusing");
1581 goto EXIT; /* exit either pass or fail */
1585 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1586 LOGE("failed to set state(READY) to sinkbin");
1591 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1592 LOGE("failed to add sinkbin to pipeline");
1597 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1598 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1603 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1604 LOGE("failed to set state(PAUSED) to sinkbin");
1613 gst_object_unref(GST_OBJECT(sinkpad));
1621 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1623 mmplayer_t *player = NULL;
1624 GstCaps *caps = NULL;
1625 gchar *caps_str = NULL;
1626 GstStructure *str = NULL;
1627 const gchar *name = NULL;
1628 GstElement *sinkbin = NULL;
1629 gboolean reusing = FALSE;
1630 gboolean caps_ret = TRUE;
1631 gchar *sink_pad_name = "sink";
1634 player = (mmplayer_t *)data;
1637 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1638 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1640 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1644 caps_str = gst_caps_to_string(caps);
1646 /* LOGD("detected mimetype : %s", name); */
1647 if (strstr(name, "audio")) {
1648 if (player->pipeline->audiobin == NULL) {
1649 const gchar *audio_format = gst_structure_get_string(str, "format");
1651 LOGD("original audio format %s", audio_format);
1652 mm_attrs_set_string_by_name(player->attrs, "content_audio_format", audio_format);
1655 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1656 LOGE("failed to create audiobin. continuing without audio");
1660 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1661 LOGD("creating audiobin success");
1664 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1665 LOGD("reusing audiobin");
1666 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1668 } else if (strstr(name, "video")) {
1669 /* 1. zero copy is updated at _decode_pad_added()
1670 * 2. NULL surface type is handled in _decode_pad_added() */
1671 LOGD("zero copy %d", player->set_mode.video_zc);
1672 if (player->pipeline->videobin == NULL) {
1673 int surface_type = 0;
1674 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1675 LOGD("display_surface_type (%d)", surface_type);
1677 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1678 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1679 LOGE("failed to acquire video overlay resource");
1683 player->interrupted_by_resource = FALSE;
1685 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1686 LOGE("failed to create videobin. continuing without video");
1690 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1691 LOGD("creating videosink bin success");
1694 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1695 LOGD("re-using videobin");
1696 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1698 } else if (strstr(name, "text")) {
1699 if (player->pipeline->textbin == NULL) {
1700 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1701 LOGE("failed to create text sink bin. continuing without text");
1705 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1706 player->textsink_linked = 1;
1707 LOGD("creating textsink bin success");
1709 if (!player->textsink_linked) {
1710 LOGD("re-using textbin");
1712 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1713 player->textsink_linked = 1;
1715 /* linked textbin exist which means that the external subtitle path exist already */
1716 LOGW("ignoring internal subtutle since external subtitle is available");
1719 sink_pad_name = "text_sink";
1721 LOGW("unknown mime type %s, ignoring it", name);
1725 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1728 LOGD("[handle: %p] success to create and link sink bin", player);
1730 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1731 * streaming task. if the task blocked, then buffer will not flow to the next element
1732 *(autoplugging element). so this is special hack for streaming. please try to remove it
1734 /* dec stream count. we can remove fakesink if it's zero */
1735 if (player->num_dynamic_pad)
1736 player->num_dynamic_pad--;
1738 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1740 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1741 _mmplayer_pipeline_complete(NULL, player);
1745 MMPLAYER_FREEIF(caps_str);
1748 gst_caps_unref(caps);
1754 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1756 int required_angle = 0; /* Angle required for straight view */
1757 int rotation_angle = 0;
1759 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1760 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1762 /* Counter clockwise */
1763 switch (orientation) {
1768 required_angle = 270;
1771 required_angle = 180;
1774 required_angle = 90;
1778 rotation_angle = display_angle + required_angle;
1779 if (rotation_angle >= 360)
1780 rotation_angle -= 360;
1782 /* chech if supported or not */
1783 if (rotation_angle % 90) {
1784 LOGD("not supported rotation angle = %d", rotation_angle);
1788 switch (rotation_angle) {
1790 *value = MM_DISPLAY_ROTATION_NONE;
1793 *value = MM_DISPLAY_ROTATION_90;
1796 *value = MM_DISPLAY_ROTATION_180;
1799 *value = MM_DISPLAY_ROTATION_270;
1803 LOGD("setting rotation property value : %d", *value);
1809 __mmplayer_video_param_check_video_sink_bin(mmplayer_t *player)
1811 /* check video sinkbin is created */
1812 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
1814 player->pipeline->videobin &&
1815 player->pipeline->videobin[MMPLAYER_V_BIN].gst &&
1816 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
1817 MM_ERROR_PLAYER_NOT_INITIALIZED);
1819 return MM_ERROR_NONE;
1823 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1825 int display_rotation = 0;
1826 gchar *org_orient = NULL;
1827 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1830 LOGE("cannot get content attribute");
1831 return MM_ERROR_PLAYER_INTERNAL;
1834 if (display_angle) {
1835 /* update user roation */
1836 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1838 /* Counter clockwise */
1839 switch (display_rotation) {
1840 case MM_DISPLAY_ROTATION_NONE:
1843 case MM_DISPLAY_ROTATION_90:
1844 *display_angle = 90;
1846 case MM_DISPLAY_ROTATION_180:
1847 *display_angle = 180;
1849 case MM_DISPLAY_ROTATION_270:
1850 *display_angle = 270;
1853 LOGW("wrong angle type : %d", display_rotation);
1856 LOGD("check user angle: %d", *display_angle);
1860 /* Counter clockwise */
1861 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1864 if (!strcmp(org_orient, "rotate-90"))
1866 else if (!strcmp(org_orient, "rotate-180"))
1868 else if (!strcmp(org_orient, "rotate-270"))
1871 LOGD("original rotation is %s", org_orient);
1873 LOGD("content_video_orientation get fail");
1876 LOGD("check orientation: %d", *orientation);
1879 return MM_ERROR_NONE;
1883 __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1885 int rotation_value = 0;
1886 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1887 int display_angle = 0;
1890 /* check video sinkbin is created */
1891 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1894 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1896 /* get rotation value to set */
1897 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1898 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1899 LOGD("set video param : rotate %d", rotation_value);
1903 __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1905 MMHandleType attrs = 0;
1909 /* check video sinkbin is created */
1910 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1913 attrs = MMPLAYER_GET_ATTRS(player);
1914 MMPLAYER_RETURN_IF_FAIL(attrs);
1916 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1917 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1918 LOGD("set video param : visible %d", visible);
1922 __mmplayer_video_param_set_display_method(mmplayer_t *player)
1924 MMHandleType attrs = 0;
1925 int display_method = 0;
1928 /* check video sinkbin is created */
1929 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
1932 attrs = MMPLAYER_GET_ATTRS(player);
1933 MMPLAYER_RETURN_IF_FAIL(attrs);
1935 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1936 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1937 LOGD("set video param : method %d", display_method);
1941 __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1943 MMHandleType attrs = 0;
1944 void *handle = NULL;
1947 /* check video sinkbin is created */
1948 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1949 LOGW("There is no video sink");
1953 attrs = MMPLAYER_GET_ATTRS(player);
1954 MMPLAYER_RETURN_IF_FAIL(attrs);
1955 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1957 gst_video_overlay_set_video_roi_area(
1958 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1959 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1960 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1961 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1966 __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1968 MMHandleType attrs = 0;
1969 void *handle = NULL;
1973 int win_roi_width = 0;
1974 int win_roi_height = 0;
1977 /* check video sinkbin is created */
1978 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE) {
1979 LOGW("There is no video sink");
1983 attrs = MMPLAYER_GET_ATTRS(player);
1984 MMPLAYER_RETURN_IF_FAIL(attrs);
1986 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1989 /* It should be set after setting window */
1990 mm_attrs_get_int_by_name(attrs, "display_win_roi_x", &win_roi_x);
1991 mm_attrs_get_int_by_name(attrs, "display_win_roi_y", &win_roi_y);
1992 mm_attrs_get_int_by_name(attrs, "display_win_roi_width", &win_roi_width);
1993 mm_attrs_get_int_by_name(attrs, "display_win_roi_height", &win_roi_height);
1995 /* After setting window handle, set display roi area */
1996 gst_video_overlay_set_display_roi_area(
1997 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1998 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1999 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2000 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2005 __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2007 MMHandleType attrs = 0;
2008 void *handle = NULL;
2010 /* check video sinkbin is created */
2011 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2014 attrs = MMPLAYER_GET_ATTRS(player);
2015 MMPLAYER_RETURN_IF_FAIL(attrs);
2017 /* common case if using overlay surface */
2018 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
2021 /* default is using wl_surface_id */
2022 unsigned int wl_surface_id = 0;
2023 wl_surface_id = *(int *)handle;
2024 LOGD("set video param : wl_surface_id %d", wl_surface_id);
2025 gst_video_overlay_set_wl_window_wl_surface_id(
2026 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2029 /* FIXIT : is it error case? */
2030 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
2035 __mmplayer_update_wayland_videosink_video_param(mmplayer_t *player, char *param_name)
2037 gboolean update_all_param = FALSE;
2040 /* check video sinkbin is created */
2041 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2042 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2044 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2045 LOGE("can not find tizenwlsink");
2046 return MM_ERROR_PLAYER_INTERNAL;
2049 LOGD("param_name : %s", param_name);
2050 if (!g_strcmp0(param_name, "update_all_param"))
2051 update_all_param = TRUE;
2053 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2054 __mmplayer_video_param_set_display_overlay(player);
2055 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2056 __mmplayer_video_param_set_display_method(player);
2057 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2058 __mmplayer_video_param_set_display_visible(player);
2059 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2060 __mmplayer_video_param_set_display_rotation(player);
2061 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2062 __mmplayer_video_param_set_roi_area(player);
2063 if (update_all_param)
2064 __mmplayer_video_param_set_video_roi_area(player);
2066 return MM_ERROR_NONE;
2070 _mmplayer_update_video_param(mmplayer_t *player, char *param_name)
2072 MMHandleType attrs = 0;
2073 int surface_type = 0;
2074 int ret = MM_ERROR_NONE;
2078 /* check video sinkbin is created */
2079 if (MM_ERROR_NONE != __mmplayer_video_param_check_video_sink_bin(player))
2080 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2082 attrs = MMPLAYER_GET_ATTRS(player);
2084 LOGE("cannot get content attribute");
2085 return MM_ERROR_PLAYER_INTERNAL;
2087 LOGD("param_name : %s", param_name);
2089 /* update display surface */
2090 mm_attrs_get_int_by_name(attrs, "display_surface_type", &surface_type);
2091 LOGD("check display surface type attribute: %d", surface_type);
2093 /* configuring display */
2094 switch (surface_type) {
2095 case MM_DISPLAY_SURFACE_OVERLAY:
2097 ret = __mmplayer_update_wayland_videosink_video_param(player, param_name);
2098 if (ret != MM_ERROR_NONE)
2106 return MM_ERROR_NONE;
2110 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2112 gboolean disable_overlay = FALSE;
2113 mmplayer_t *player = (mmplayer_t *)hplayer;
2116 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2117 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2118 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2119 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2121 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2122 LOGW("Display control is not supported");
2123 return MM_ERROR_PLAYER_INTERNAL;
2126 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2128 if (audio_only == (bool)disable_overlay) {
2129 LOGE("It's the same with current setting: (%d)", audio_only);
2130 return MM_ERROR_NONE;
2134 LOGE("disable overlay");
2135 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2137 /* release overlay resource */
2138 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2139 LOGE("failed to release overlay resource");
2143 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2144 LOGE("failed to acquire video overlay resource");
2147 player->interrupted_by_resource = FALSE;
2149 LOGD("enable overlay");
2150 __mmplayer_video_param_set_display_overlay(player);
2151 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2156 return MM_ERROR_NONE;
2160 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2162 mmplayer_t *player = (mmplayer_t *)hplayer;
2163 gboolean disable_overlay = FALSE;
2167 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2168 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2169 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2170 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2171 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2173 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2174 LOGW("Display control is not supported");
2175 return MM_ERROR_PLAYER_INTERNAL;
2178 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2180 *paudio_only = (bool)disable_overlay;
2182 LOGD("audio_only : %d", *paudio_only);
2186 return MM_ERROR_NONE;
2190 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2192 GList *bucket = element_bucket;
2193 mmplayer_gst_element_t *element = NULL;
2194 mmplayer_gst_element_t *prv_element = NULL;
2195 GstElement *tee_element = NULL;
2196 gint successful_link_count = 0;
2200 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2202 prv_element = (mmplayer_gst_element_t *)bucket->data;
2203 bucket = bucket->next;
2205 for (; bucket; bucket = bucket->next) {
2206 element = (mmplayer_gst_element_t *)bucket->data;
2208 if (element && element->gst) {
2209 if (prv_element && prv_element->gst) {
2210 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2212 prv_element->gst = tee_element;
2214 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2215 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2216 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2220 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2221 LOGD("linking [%s] to [%s] success",
2222 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2223 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2224 successful_link_count++;
2225 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2226 LOGD("keep audio-tee element for next audio pipeline branch");
2227 tee_element = prv_element->gst;
2230 LOGD("linking [%s] to [%s] failed",
2231 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2232 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2238 prv_element = element;
2243 return successful_link_count;
2247 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2249 GList *bucket = element_bucket;
2250 mmplayer_gst_element_t *element = NULL;
2251 int successful_add_count = 0;
2255 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2256 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2258 for (; bucket; bucket = bucket->next) {
2259 element = (mmplayer_gst_element_t *)bucket->data;
2261 if (element && element->gst) {
2262 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2263 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2264 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2265 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2268 successful_add_count++;
2274 return successful_add_count;
2278 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2280 mmplayer_t *player = (mmplayer_t *)data;
2281 GstCaps *caps = NULL;
2282 GstStructure *str = NULL;
2284 gboolean caps_ret = TRUE;
2288 MMPLAYER_RETURN_IF_FAIL(pad);
2289 MMPLAYER_RETURN_IF_FAIL(unused);
2290 MMPLAYER_RETURN_IF_FAIL(data);
2292 caps = gst_pad_get_current_caps(pad);
2296 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2300 LOGD("name = %s", name);
2302 if (strstr(name, "audio")) {
2303 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2305 if (player->audio_stream_changed_cb) {
2306 LOGE("call the audio stream changed cb");
2307 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2309 } else if (strstr(name, "video")) {
2310 if ((name = gst_structure_get_string(str, "format")))
2311 player->set_mode.video_zc = name[0] == 'S';
2313 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2314 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2316 LOGW("invalid caps info");
2321 gst_caps_unref(caps);
2329 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2334 MMPLAYER_RETURN_IF_FAIL(player);
2336 if (player->audio_stream_buff_list) {
2337 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2338 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2341 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2342 __mmplayer_audio_stream_send_data(player, tmp);
2344 MMPLAYER_FREEIF(tmp->pcm_data);
2345 MMPLAYER_FREEIF(tmp);
2348 g_list_free(player->audio_stream_buff_list);
2349 player->audio_stream_buff_list = NULL;
2356 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2358 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2361 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2363 audio_stream.bitrate = a_buffer->bitrate;
2364 audio_stream.channel = a_buffer->channel;
2365 audio_stream.depth = a_buffer->depth;
2366 audio_stream.is_little_endian = a_buffer->is_little_endian;
2367 audio_stream.channel_mask = a_buffer->channel_mask;
2368 audio_stream.data_size = a_buffer->data_size;
2369 audio_stream.data = a_buffer->pcm_data;
2370 audio_stream.pcm_format = a_buffer->pcm_format;
2372 /* LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param); */
2373 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2379 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2381 mmplayer_t *player = (mmplayer_t *)data;
2382 const gchar *pcm_format = NULL;
2386 gint endianness = 0;
2387 guint64 channel_mask = 0;
2388 void *a_data = NULL;
2390 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2391 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2395 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2397 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2398 a_data = mapinfo.data;
2399 a_size = mapinfo.size;
2401 GstCaps *caps = gst_pad_get_current_caps(pad);
2402 GstStructure *structure = gst_caps_get_structure(caps, 0);
2404 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
2405 pcm_format = gst_structure_get_string(structure, "format");
2406 gst_structure_get_int(structure, "rate", &rate);
2407 gst_structure_get_int(structure, "channels", &channel);
2408 gst_structure_get_int(structure, "depth", &depth);
2409 gst_structure_get_int(structure, "endianness", &endianness);
2410 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2411 gst_caps_unref(GST_CAPS(caps));
2413 /* In case of the sync is false, use buffer list. *
2414 * The num of buffer list depends on the num of audio channels */
2415 if (player->audio_stream_buff_list) {
2416 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2417 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2419 if (channel_mask == tmp->channel_mask) {
2420 /* LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size); */
2421 if (tmp->data_size + a_size < tmp->buff_size) {
2422 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2423 tmp->data_size += a_size;
2425 /* send data to client */
2426 __mmplayer_audio_stream_send_data(player, tmp);
2428 if (a_size > tmp->buff_size) {
2429 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2430 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2431 if (tmp->pcm_data == NULL) {
2432 LOGE("failed to realloc data.");
2435 tmp->buff_size = a_size;
2437 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2438 memcpy(tmp->pcm_data, a_data, a_size);
2439 tmp->data_size = a_size;
2444 LOGE("data is empty in list.");
2450 /* create new audio stream data for newly found audio channel */
2451 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2452 if (a_buffer == NULL) {
2453 LOGE("failed to alloc data.");
2456 a_buffer->bitrate = rate;
2457 a_buffer->channel = channel;
2458 a_buffer->depth = depth;
2459 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2460 a_buffer->channel_mask = channel_mask;
2461 a_buffer->data_size = a_size;
2462 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2464 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2465 /* If sync is FALSE, use buffer list to reduce the IPC. */
2466 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2467 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2468 if (a_buffer->pcm_data == NULL) {
2469 LOGE("failed to alloc data.");
2470 MMPLAYER_FREEIF(a_buffer);
2473 memcpy(a_buffer->pcm_data, a_data, a_size);
2474 /* LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size); */
2475 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2477 /* If sync is TRUE, send data directly. */
2478 a_buffer->pcm_data = a_data;
2479 __mmplayer_audio_stream_send_data(player, a_buffer);
2480 MMPLAYER_FREEIF(a_buffer);
2484 gst_buffer_unmap(buffer, &mapinfo);
2489 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2491 mmplayer_t *player = (mmplayer_t *)data;
2492 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2493 GstPad *sinkpad = NULL;
2494 GstElement *queue = NULL, *sink = NULL;
2497 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2499 queue = gst_element_factory_make("queue", NULL);
2500 if (queue == NULL) {
2501 LOGD("fail make queue");
2505 sink = gst_element_factory_make("fakesink", NULL);
2507 LOGD("fail make fakesink");
2511 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2513 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2514 LOGW("failed to link queue & sink");
2518 sinkpad = gst_element_get_static_pad(queue, "sink");
2520 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2521 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2525 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2527 gst_object_unref(sinkpad);
2528 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2529 g_object_set(sink, "sync", TRUE, NULL);
2530 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2532 /* keep the first sink reference only */
2533 if (!audiobin[MMPLAYER_A_SINK].gst) {
2534 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2535 audiobin[MMPLAYER_A_SINK].gst = sink;
2538 gst_element_set_state(sink, GST_STATE_PAUSED);
2539 gst_element_set_state(queue, GST_STATE_PAUSED);
2541 _mmplayer_add_signal_connection(player,
2543 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2545 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2548 __mmplayer_add_sink(player, sink);
2554 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2556 gst_object_unref(GST_OBJECT(queue));
2560 gst_object_unref(GST_OBJECT(sink));
2564 gst_object_unref(GST_OBJECT(sinkpad));
2572 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2574 #define MAX_PROPS_LEN 128
2575 mmplayer_gst_element_t *audiobin = NULL;
2576 gint latency_mode = 0;
2577 gchar *stream_type = NULL;
2578 gchar *latency = NULL;
2580 gchar stream_props[MAX_PROPS_LEN] = {0,};
2581 GstStructure *props = NULL;
2584 * It should be set after player creation through attribute.
2585 * But, it can not be changed during playing.
2588 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2590 audiobin = player->pipeline->audiobin;
2592 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2593 if (player->sound.mute) {
2594 LOGD("mute enabled");
2595 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2598 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2599 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2602 snprintf(stream_props, sizeof(stream_props) - 1, "props,application.process.id.origin=%d", player->client_pid);
2604 snprintf(stream_props, sizeof(stream_props) - 1, "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2605 stream_type, stream_id, player->client_pid);
2607 props = gst_structure_from_string(stream_props, NULL);
2608 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2609 LOGI("props result[%s].", stream_props);
2610 gst_structure_free(props);
2612 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2614 switch (latency_mode) {
2615 case AUDIO_LATENCY_MODE_LOW:
2616 latency = g_strndup("low", 3);
2618 case AUDIO_LATENCY_MODE_MID:
2619 latency = g_strndup("mid", 3);
2621 case AUDIO_LATENCY_MODE_HIGH:
2622 latency = g_strndup("high", 4);
2626 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2628 LOGD("audiosink property - latency=%s", latency);
2630 MMPLAYER_FREEIF(latency);
2636 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2638 mmplayer_gst_element_t *audiobin = NULL;
2641 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2643 audiobin = player->pipeline->audiobin;
2645 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2646 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2647 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2649 if (player->video360_yaw_radians <= M_PI &&
2650 player->video360_yaw_radians >= -M_PI &&
2651 player->video360_pitch_radians <= M_PI_2 &&
2652 player->video360_pitch_radians >= -M_PI_2) {
2653 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2654 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2655 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2656 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2658 "source-orientation-y", player->video360_metadata.init_view_heading,
2659 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2666 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2668 mmplayer_gst_element_t *audiobin = NULL;
2669 GstPad *sink_pad = NULL;
2670 GstCaps *acaps = NULL;
2672 int pitch_control = 0;
2673 double pitch_value = 1.0;
2676 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2677 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2679 audiobin = player->pipeline->audiobin;
2681 LOGD("make element for normal audio playback");
2683 /* audio bin structure for playback. {} means optional.
2684 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2686 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2687 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2690 /* for pitch control */
2691 mm_attrs_multiple_get(player->attrs, NULL,
2692 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2693 MM_PLAYER_PITCH_VALUE, &pitch_value,
2696 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2697 if (pitch_control && (player->videodec_linked == 0)) {
2698 GstElementFactory *factory;
2700 factory = gst_element_factory_find("pitch");
2702 gst_object_unref(factory);
2705 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2708 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2709 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2711 LOGW("there is no pitch element");
2716 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2718 /* replaygain volume */
2719 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2720 if (player->sound.rg_enable)
2721 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2723 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2726 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2728 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2729 /* currently, only openalsink uses volume element */
2730 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2731 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2733 if (player->sound.mute) {
2734 LOGD("mute enabled");
2735 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2739 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2741 /* audio effect element. if audio effect is enabled */
2742 if ((strcmp(player->ini.audioeffect_element, ""))
2744 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2745 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2747 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2749 if ((!player->bypass_audio_effect)
2750 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2751 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2752 if (!_mmplayer_audio_effect_custom_apply(player))
2753 LOGI("apply audio effect(custom) setting success");
2757 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2758 && (player->set_mode.rich_audio)) {
2759 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2763 /* create audio sink */
2764 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2765 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2766 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2768 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2769 if (player->is_360_feature_enabled &&
2770 player->is_content_spherical &&
2772 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2773 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2774 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2776 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2778 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2780 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2781 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2782 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2783 gst_caps_unref(acaps);
2785 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2787 player->is_openal_plugin_used = TRUE;
2789 if (player->is_360_feature_enabled && player->is_content_spherical)
2790 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2791 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2794 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2795 (player->videodec_linked && player->ini.use_system_clock)) {
2796 LOGD("system clock will be used.");
2797 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2800 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2801 __mmplayer_gst_set_pulsesink_property(player);
2802 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2803 __mmplayer_gst_set_openalsink_property(player);
2806 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2807 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2809 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2810 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2811 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2812 gst_object_unref(GST_OBJECT(sink_pad));
2814 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2817 return MM_ERROR_NONE;
2819 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2821 return MM_ERROR_PLAYER_INTERNAL;
2825 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2827 mmplayer_gst_element_t *audiobin = NULL;
2828 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2830 gchar *dst_format = NULL;
2832 int dst_samplerate = 0;
2833 int dst_channels = 0;
2834 GstCaps *caps = NULL;
2835 char *caps_str = NULL;
2838 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2839 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2841 audiobin = player->pipeline->audiobin;
2843 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2845 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2847 [case 1] extract interleave audio pcm without playback
2848 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2849 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2851 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2853 [case 2] deinterleave for each channel without playback
2854 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2855 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2857 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2858 - fakesink (sync or not)
2861 [case 3] [case 1(sync only)] + playback
2862 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2864 * src - ... - tee - queue1 - playback path
2865 - queue2 - [case1 pipeline with sync]
2867 [case 4] [case 2(sync only)] + playback
2868 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2870 * src - ... - tee - queue1 - playback path
2871 - queue2 - [case2 pipeline with sync]
2875 /* 1. create tee and playback path
2876 'tee' should be added at first to copy the decoded stream
2878 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2879 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2880 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2882 /* tee - path 1 : for playback path */
2883 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2884 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2886 /* tee - path 2 : for extract path */
2887 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2888 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2891 /* if there is tee, 'tee - path 2' is linked here */
2893 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2896 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2898 /* 2. decide the extract pcm format */
2899 mm_attrs_multiple_get(player->attrs, NULL,
2900 "pcm_audioformat", &dst_format, &dst_len,
2901 "pcm_extraction_samplerate", &dst_samplerate,
2902 "pcm_extraction_channels", &dst_channels,
2905 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2906 dst_format, dst_len, dst_samplerate, dst_channels);
2908 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2909 mm_attrs_multiple_get(player->attrs, NULL,
2910 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2911 "content_audio_samplerate", &dst_samplerate,
2912 "content_audio_channels", &dst_channels,
2915 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2916 dst_format, dst_len, dst_samplerate, dst_channels);
2918 /* If there is no enough information, set it to platform default value. */
2919 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2920 LOGD("set platform default format");
2921 dst_format = DEFAULT_PCM_OUT_FORMAT;
2923 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2924 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2927 /* 3. create capsfilter */
2928 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2929 caps = gst_caps_new_simple("audio/x-raw",
2930 "format", G_TYPE_STRING, dst_format,
2931 "rate", G_TYPE_INT, dst_samplerate,
2932 "channels", G_TYPE_INT, dst_channels,
2935 caps_str = gst_caps_to_string(caps);
2936 LOGD("new caps : %s", caps_str);
2938 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2941 gst_caps_unref(caps);
2942 MMPLAYER_FREEIF(caps_str);
2944 /* 4-1. create deinterleave to extract pcm for each channel */
2945 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2946 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2947 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2949 /* audiosink will be added after getting signal for each channel */
2950 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2951 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2953 /* 4-2. create fakesink to extract interlevaed pcm */
2954 LOGD("add audio fakesink for interleaved audio");
2955 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2956 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2957 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2958 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2960 _mmplayer_add_signal_connection(player,
2961 G_OBJECT(audiobin[extract_sink_id].gst),
2962 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2964 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2967 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2971 return MM_ERROR_NONE;
2973 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2975 return MM_ERROR_PLAYER_INTERNAL;
2979 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2981 int ret = MM_ERROR_NONE;
2982 mmplayer_gst_element_t *audiobin = NULL;
2983 GList *element_bucket = NULL;
2986 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2987 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2989 audiobin = player->pipeline->audiobin;
2991 if (player->build_audio_offload) { /* skip all the audio filters */
2992 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2994 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2995 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2996 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2998 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
3002 /* FIXME: need to mention the supportable condition at API reference */
3003 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3004 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3006 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3008 if (ret != MM_ERROR_NONE)
3011 LOGD("success to make audio bin element");
3012 *bucket = element_bucket;
3015 return MM_ERROR_NONE;
3018 LOGE("failed to make audio bin element");
3019 g_list_free(element_bucket);
3023 return MM_ERROR_PLAYER_INTERNAL;
3027 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3029 mmplayer_gst_element_t *first_element = NULL;
3030 mmplayer_gst_element_t *audiobin = NULL;
3032 GstPad *ghostpad = NULL;
3033 GList *element_bucket = NULL;
3037 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3040 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3042 LOGE("failed to allocate memory for audiobin");
3043 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3047 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3048 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3049 if (!audiobin[MMPLAYER_A_BIN].gst) {
3050 LOGE("failed to create audiobin");
3055 player->pipeline->audiobin = audiobin;
3057 /* create audio filters and audiosink */
3058 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3061 /* adding created elements to bin */
3062 LOGD("adding created elements to bin");
3063 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3066 /* linking elements in the bucket by added order. */
3067 LOGD("Linking elements in the bucket by added order.");
3068 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3071 /* get first element's sinkpad for creating ghostpad */
3072 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3073 if (!first_element) {
3074 LOGE("failed to get first elem");
3078 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3080 LOGE("failed to get pad from first element of audiobin");
3084 ghostpad = gst_ghost_pad_new("sink", pad);
3086 LOGE("failed to create ghostpad");
3090 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3091 LOGE("failed to add ghostpad to audiobin");
3095 gst_object_unref(pad);
3097 g_list_free(element_bucket);
3100 return MM_ERROR_NONE;
3103 LOGD("ERROR : releasing audiobin");
3106 gst_object_unref(GST_OBJECT(pad));
3109 gst_object_unref(GST_OBJECT(ghostpad));
3112 g_list_free(element_bucket);
3114 /* release element which are not added to bin */
3115 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3116 /* NOTE : skip bin */
3117 if (audiobin[i].gst) {
3118 GstObject *parent = NULL;
3119 parent = gst_element_get_parent(audiobin[i].gst);
3122 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3123 audiobin[i].gst = NULL;
3125 gst_object_unref(GST_OBJECT(parent));
3129 /* release audiobin with it's childs */
3130 if (audiobin[MMPLAYER_A_BIN].gst)
3131 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3133 MMPLAYER_FREEIF(audiobin);
3135 player->pipeline->audiobin = NULL;
3137 return MM_ERROR_PLAYER_INTERNAL;
3141 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3143 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3147 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3149 int ret = MM_ERROR_NONE;
3151 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3152 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3154 MMPLAYER_VIDEO_BO_LOCK(player);
3156 if (player->video_bo_list) {
3157 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3158 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3159 if (tmp && tmp->bo == bo) {
3161 LOGD("release bo %p", bo);
3162 tbm_bo_unref(tmp->bo);
3163 MMPLAYER_VIDEO_BO_UNLOCK(player);
3164 MMPLAYER_VIDEO_BO_SIGNAL(player);
3169 /* hw codec is running or the list was reset for DRC. */
3170 LOGW("there is no bo list.");
3172 MMPLAYER_VIDEO_BO_UNLOCK(player);
3174 LOGW("failed to find bo %p", bo);
3179 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3184 MMPLAYER_RETURN_IF_FAIL(player);
3186 MMPLAYER_VIDEO_BO_LOCK(player);
3187 if (player->video_bo_list) {
3188 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3189 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3190 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3193 tbm_bo_unref(tmp->bo);
3197 g_list_free(player->video_bo_list);
3198 player->video_bo_list = NULL;
3200 player->video_bo_size = 0;
3201 MMPLAYER_VIDEO_BO_UNLOCK(player);
3208 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3211 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3212 gboolean ret = TRUE;
3214 /* check DRC, if it is, destroy the prev bo list to create again */
3215 if (player->video_bo_size != size) {
3216 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3217 __mmplayer_video_stream_destroy_bo_list(player);
3218 player->video_bo_size = size;
3221 MMPLAYER_VIDEO_BO_LOCK(player);
3223 if ((!player->video_bo_list) ||
3224 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3226 /* create bo list */
3228 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3230 if (player->video_bo_list) {
3231 /* if bo list did not created all, try it again. */
3232 idx = g_list_length(player->video_bo_list);
3233 LOGD("bo list exist(len: %d)", idx);
3236 for (; idx < player->ini.num_of_video_bo; idx++) {
3237 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3239 LOGE("Fail to alloc bo_info.");
3242 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3244 LOGE("Fail to tbm_bo_alloc.");
3245 MMPLAYER_FREEIF(bo_info);
3248 bo_info->used = FALSE;
3249 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3252 /* update video num buffers */
3253 LOGD("video_num_buffers : %d", idx);
3254 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx);
3255 mm_attrs_set_int_by_name(player->attrs, MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx/2)));
3258 MMPLAYER_VIDEO_BO_UNLOCK(player);
3264 /* get bo from list*/
3265 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3266 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3267 if (tmp && (tmp->used == FALSE)) {
3268 LOGD("found bo %p to use", tmp->bo);
3270 MMPLAYER_VIDEO_BO_UNLOCK(player);
3271 return tbm_bo_ref(tmp->bo);
3275 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3276 MMPLAYER_VIDEO_BO_UNLOCK(player);
3280 if (player->ini.video_bo_timeout <= 0) {
3281 MMPLAYER_VIDEO_BO_WAIT(player);
3283 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3284 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3291 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3293 mmplayer_t *player = (mmplayer_t *)data;
3295 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3297 /* send prerolled pkt */
3298 player->video_stream_prerolled = false;
3300 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3302 /* not to send prerolled pkt again */
3303 player->video_stream_prerolled = true;
3307 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3309 mmplayer_t *player = (mmplayer_t *)data;
3310 mmplayer_video_decoded_data_info_t *stream = NULL;
3311 GstMemory *mem = NULL;
3314 MMPLAYER_RETURN_IF_FAIL(player);
3315 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3317 if (player->video_stream_prerolled) {
3318 player->video_stream_prerolled = false;
3319 LOGD("skip the prerolled pkt not to send it again");
3323 /* clear stream data structure */
3324 stream = __mmplayer_create_stream_from_pad(pad);
3326 LOGE("failed to alloc stream");
3330 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3332 /* set size and timestamp */
3333 mem = gst_buffer_peek_memory(buffer, 0);
3334 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3335 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3337 /* check zero-copy */
3338 if (player->set_mode.video_zc &&
3339 player->set_mode.video_export &&
3340 gst_is_tizen_memory(mem)) {
3341 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3342 stream->internal_buffer = gst_buffer_ref(buffer);
3343 } else { /* sw codec */
3344 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3347 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3351 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3352 LOGE("failed to send video decoded data.");
3359 LOGE("release video stream resource.");
3360 if (gst_is_tizen_memory(mem)) {
3362 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3364 tbm_bo_unref(stream->bo[i]);
3367 /* unref gst buffer */
3368 if (stream->internal_buffer)
3369 gst_buffer_unref(stream->internal_buffer);
3372 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3374 MMPLAYER_FREEIF(stream);
3379 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3381 mmplayer_gst_element_t *videobin = NULL;
3384 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3386 videobin = player->pipeline->videobin;
3388 /* Set spatial media metadata and/or user settings to the element.
3390 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3391 "projection-type", player->video360_metadata.projection_type, NULL);
3393 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3394 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3396 if (player->video360_metadata.full_pano_width_pixels &&
3397 player->video360_metadata.full_pano_height_pixels &&
3398 player->video360_metadata.cropped_area_image_width &&
3399 player->video360_metadata.cropped_area_image_height) {
3400 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3401 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3402 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3403 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3404 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3405 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3406 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3410 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3411 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3412 "horizontal-fov", player->video360_horizontal_fov,
3413 "vertical-fov", player->video360_vertical_fov, NULL);
3416 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3417 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3418 "zoom", 1.0f / player->video360_zoom, NULL);
3421 if (player->video360_yaw_radians <= M_PI &&
3422 player->video360_yaw_radians >= -M_PI &&
3423 player->video360_pitch_radians <= M_PI_2 &&
3424 player->video360_pitch_radians >= -M_PI_2) {
3425 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3426 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3427 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3428 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3429 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3430 "pose-yaw", player->video360_metadata.init_view_heading,
3431 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3434 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3435 "passthrough", !player->is_video360_enabled, NULL);
3442 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3444 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3445 GList *element_bucket = NULL;
3448 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3450 /* create video360 filter */
3451 if (player->is_360_feature_enabled && player->is_content_spherical) {
3452 LOGD("create video360 element");
3453 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3454 __mmplayer_gst_set_video360_property(player);
3458 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3459 LOGD("skip creating the videoconv and rotator");
3460 return MM_ERROR_NONE;
3463 /* in case of sw codec & overlay surface type, except 360 playback.
3464 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3465 LOGD("create video converter: %s", video_csc);
3466 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3469 *bucket = element_bucket;
3471 return MM_ERROR_NONE;
3473 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3474 g_list_free(element_bucket);
3478 return MM_ERROR_PLAYER_INTERNAL;
3482 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3484 gchar *factory_name = NULL;
3486 switch (surface_type) {
3487 case MM_DISPLAY_SURFACE_OVERLAY:
3488 if (strlen(player->ini.videosink_element_overlay) > 0)
3489 factory_name = player->ini.videosink_element_overlay;
3491 case MM_DISPLAY_SURFACE_REMOTE:
3492 case MM_DISPLAY_SURFACE_NULL:
3493 if (strlen(player->ini.videosink_element_fake) > 0)
3494 factory_name = player->ini.videosink_element_fake;
3497 LOGE("unidentified surface type");
3501 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3502 return factory_name;
3506 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3508 gchar *factory_name = NULL;
3509 mmplayer_gst_element_t *videobin = NULL;
3514 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3516 videobin = player->pipeline->videobin;
3517 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3519 attrs = MMPLAYER_GET_ATTRS(player);
3521 LOGE("cannot get content attribute");
3522 return MM_ERROR_PLAYER_INTERNAL;
3525 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3526 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3527 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3529 /* support shard memory with S/W codec on HawkP */
3530 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3531 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3532 "use-tbm", use_tbm, NULL);
3536 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3537 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3540 mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless);
3542 LOGD("disable last-sample");
3543 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3546 if (player->set_mode.video_export) {
3548 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3549 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3550 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3552 _mmplayer_add_signal_connection(player,
3553 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3554 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3556 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3559 _mmplayer_add_signal_connection(player,
3560 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3561 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3563 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3567 if (_mmplayer_update_video_param(player, "update_all_param") != MM_ERROR_NONE)
3568 return MM_ERROR_PLAYER_INTERNAL;
3570 if (videobin[MMPLAYER_V_SINK].gst) {
3571 GstPad *sink_pad = NULL;
3572 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3574 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3575 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3576 gst_object_unref(GST_OBJECT(sink_pad));
3578 LOGE("failed to get sink pad from videosink");
3582 return MM_ERROR_NONE;
3587 * - video overlay surface(arm/x86) : tizenwlsink
3590 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3593 GList *element_bucket = NULL;
3594 mmplayer_gst_element_t *first_element = NULL;
3595 mmplayer_gst_element_t *videobin = NULL;
3596 gchar *videosink_factory_name = NULL;
3599 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3602 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3604 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3606 player->pipeline->videobin = videobin;
3609 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3610 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3611 if (!videobin[MMPLAYER_V_BIN].gst) {
3612 LOGE("failed to create videobin");
3616 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3619 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3620 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3622 /* additional setting for sink plug-in */
3623 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3624 LOGE("failed to set video property");
3628 /* store it as it's sink element */
3629 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3631 /* adding created elements to bin */
3632 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3633 LOGE("failed to add elements");
3637 /* Linking elements in the bucket by added order */
3638 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3639 LOGE("failed to link elements");
3643 /* get first element's sinkpad for creating ghostpad */
3644 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3645 if (!first_element) {
3646 LOGE("failed to get first element from bucket");
3650 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3652 LOGE("failed to get pad from first element");
3656 /* create ghostpad */
3657 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3658 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3659 LOGE("failed to add ghostpad to videobin");
3662 gst_object_unref(pad);
3664 /* done. free allocated variables */
3665 g_list_free(element_bucket);
3669 return MM_ERROR_NONE;
3672 LOGE("ERROR : releasing videobin");
3673 g_list_free(element_bucket);
3676 gst_object_unref(GST_OBJECT(pad));
3678 /* release videobin with it's childs */
3679 if (videobin[MMPLAYER_V_BIN].gst)
3680 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3682 MMPLAYER_FREEIF(videobin);
3683 player->pipeline->videobin = NULL;
3685 return MM_ERROR_PLAYER_INTERNAL;
3689 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3691 GList *element_bucket = NULL;
3692 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3694 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3695 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3696 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3697 "signal-handoffs", FALSE,
3700 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3701 _mmplayer_add_signal_connection(player,
3702 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3703 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3705 G_CALLBACK(__mmplayer_update_subtitle),
3708 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3709 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3711 if (!player->play_subtitle) {
3712 LOGD("add textbin sink as sink element of whole pipeline.");
3713 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3716 /* adding created elements to bin */
3717 LOGD("adding created elements to bin");
3718 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3719 LOGE("failed to add elements");
3723 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3724 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3725 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3727 /* linking elements in the bucket by added order. */
3728 LOGD("Linking elements in the bucket by added order.");
3729 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3730 LOGE("failed to link elements");
3734 /* done. free allocated variables */
3735 g_list_free(element_bucket);
3737 if (textbin[MMPLAYER_T_QUEUE].gst) {
3739 GstPad *ghostpad = NULL;
3741 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3743 LOGE("failed to get sink pad of text queue");
3747 ghostpad = gst_ghost_pad_new("text_sink", pad);
3748 gst_object_unref(pad);
3751 LOGE("failed to create ghostpad of textbin");
3755 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3756 LOGE("failed to add ghostpad to textbin");
3757 gst_object_unref(ghostpad);
3762 return MM_ERROR_NONE;
3765 g_list_free(element_bucket);
3767 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3768 LOGE("remove textbin sink from sink list");
3769 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3772 /* release element at __mmplayer_gst_create_text_sink_bin */
3773 return MM_ERROR_PLAYER_INTERNAL;
3777 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3779 mmplayer_gst_element_t *textbin = NULL;
3780 GList *element_bucket = NULL;
3781 int surface_type = 0;
3786 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3789 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3791 LOGE("failed to allocate memory for textbin");
3792 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3796 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3797 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3798 if (!textbin[MMPLAYER_T_BIN].gst) {
3799 LOGE("failed to create textbin");
3804 player->pipeline->textbin = textbin;
3807 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3808 LOGD("surface type for subtitle : %d", surface_type);
3809 switch (surface_type) {
3810 case MM_DISPLAY_SURFACE_OVERLAY:
3811 case MM_DISPLAY_SURFACE_NULL:
3812 case MM_DISPLAY_SURFACE_REMOTE:
3813 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3814 LOGE("failed to make plain text elements");
3825 return MM_ERROR_NONE;
3829 LOGD("ERROR : releasing textbin");
3831 g_list_free(element_bucket);
3833 /* release signal */
3834 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3836 /* release element which are not added to bin */
3837 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3838 /* NOTE : skip bin */
3839 if (textbin[i].gst) {
3840 GstObject *parent = NULL;
3841 parent = gst_element_get_parent(textbin[i].gst);
3844 gst_object_unref(GST_OBJECT(textbin[i].gst));
3845 textbin[i].gst = NULL;
3847 gst_object_unref(GST_OBJECT(parent));
3852 /* release textbin with it's childs */
3853 if (textbin[MMPLAYER_T_BIN].gst)
3854 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3856 MMPLAYER_FREEIF(player->pipeline->textbin);
3857 player->pipeline->textbin = NULL;
3860 return MM_ERROR_PLAYER_INTERNAL;
3864 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3866 mmplayer_gst_element_t *mainbin = NULL;
3867 mmplayer_gst_element_t *textbin = NULL;
3868 MMHandleType attrs = 0;
3869 GstElement *subsrc = NULL;
3870 GstElement *subparse = NULL;
3871 gchar *subtitle_uri = NULL;
3872 const gchar *charset = NULL;
3878 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3880 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3882 mainbin = player->pipeline->mainbin;
3884 attrs = MMPLAYER_GET_ATTRS(player);
3886 LOGE("cannot get content attribute");
3887 return MM_ERROR_PLAYER_INTERNAL;
3890 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3891 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3892 LOGE("subtitle uri is not proper filepath.");
3893 return MM_ERROR_PLAYER_INVALID_URI;
3896 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3897 LOGE("failed to get storage info of subtitle path");
3898 return MM_ERROR_PLAYER_INVALID_URI;
3901 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3903 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3904 player->subtitle_language_list = NULL;
3905 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3907 /* create the subtitle source */
3908 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3910 LOGE("failed to create filesrc element");
3913 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3915 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3916 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3918 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3919 LOGW("failed to add queue");
3920 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3921 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3922 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3927 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3929 LOGE("failed to create subparse element");
3933 charset = _mmplayer_get_charset(subtitle_uri);
3935 LOGD("detected charset is %s", charset);
3936 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3939 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3940 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3942 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3943 LOGW("failed to add subparse");
3944 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3945 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3946 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3950 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3951 LOGW("failed to link subsrc and subparse");
3955 player->play_subtitle = TRUE;
3956 player->adjust_subtitle_pos = 0;
3958 LOGD("play subtitle using subtitle file");
3960 if (player->pipeline->textbin == NULL) {
3961 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3962 LOGE("failed to create text sink bin. continuing without text");
3966 textbin = player->pipeline->textbin;
3968 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3969 LOGW("failed to add textbin");
3971 /* release signal */
3972 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3974 /* release textbin with it's childs */
3975 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3976 MMPLAYER_FREEIF(player->pipeline->textbin);
3977 player->pipeline->textbin = textbin = NULL;
3981 LOGD("link text input selector and textbin ghost pad");
3983 player->textsink_linked = 1;
3984 player->external_text_idx = 0;
3985 LOGI("textsink is linked");
3987 textbin = player->pipeline->textbin;
3988 LOGD("text bin has been created. reuse it.");
3989 player->external_text_idx = 1;
3992 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3993 LOGW("failed to link subparse and textbin");
3997 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3999 LOGE("failed to get sink pad from textsink to probe data");
4003 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4004 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4006 gst_object_unref(pad);
4009 /* create dot. for debugging */
4010 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4013 return MM_ERROR_NONE;
4016 /* release text pipeline resource */
4017 player->textsink_linked = 0;
4019 /* release signal */
4020 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4022 if (player->pipeline->textbin) {
4023 LOGE("remove textbin");
4025 /* release textbin with it's childs */
4026 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4027 MMPLAYER_FREEIF(player->pipeline->textbin);
4028 player->pipeline->textbin = NULL;
4032 /* release subtitle elem */
4033 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4034 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4036 return MM_ERROR_PLAYER_INTERNAL;
4040 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4042 mmplayer_t *player = (mmplayer_t *)data;
4043 MMMessageParamType msg = {0, };
4044 GstClockTime duration = 0;
4045 gpointer text = NULL;
4046 guint text_size = 0;
4047 gboolean ret = TRUE;
4048 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4052 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4053 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4055 if (player->is_subtitle_force_drop) {
4056 LOGW("subtitle is dropped forcedly.");
4060 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4061 text = mapinfo.data;
4062 text_size = mapinfo.size;
4064 if (player->set_mode.subtitle_off) {
4065 LOGD("subtitle is OFF.");
4069 if (!text || (text_size == 0)) {
4070 LOGD("There is no subtitle to be displayed.");
4074 msg.data = (void *)text;
4076 duration = GST_BUFFER_DURATION(buffer);
4078 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4079 if (player->duration > GST_BUFFER_PTS(buffer))
4080 duration = player->duration - GST_BUFFER_PTS(buffer);
4083 LOGI("subtitle duration is invalid, subtitle duration change "
4084 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4086 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4088 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4090 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4091 gst_buffer_unmap(buffer, &mapinfo);
4098 static GstPadProbeReturn
4099 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4101 mmplayer_t *player = (mmplayer_t *)u_data;
4102 GstClockTime cur_timestamp = 0;
4103 gint64 adjusted_timestamp = 0;
4104 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4106 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4108 if (player->set_mode.subtitle_off) {
4109 LOGD("subtitle is OFF.");
4113 if (player->adjust_subtitle_pos == 0) {
4114 LOGD("nothing to do");
4118 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4119 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4121 if (adjusted_timestamp < 0) {
4122 LOGD("adjusted_timestamp under zero");
4127 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4128 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4129 GST_TIME_ARGS(cur_timestamp),
4130 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4132 return GST_PAD_PROBE_OK;
4136 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4140 /* check player and subtitlebin are created */
4141 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4142 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4144 if (position == 0) {
4145 LOGD("nothing to do");
4147 return MM_ERROR_NONE;
4150 /* check current postion */
4151 player->adjust_subtitle_pos = position;
4153 LOGD("save adjust_subtitle_pos in player");
4157 return MM_ERROR_NONE;
4161 * This function is to create audio or video pipeline for playing.
4163 * @param player [in] handle of player
4165 * @return This function returns zero on success.
4170 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4172 int ret = MM_ERROR_NONE;
4173 mmplayer_gst_element_t *mainbin = NULL;
4174 MMHandleType attrs = 0;
4177 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4179 /* get profile attribute */
4180 attrs = MMPLAYER_GET_ATTRS(player);
4182 LOGE("failed to get content attribute");
4186 /* create pipeline handles */
4187 if (player->pipeline) {
4188 LOGE("pipeline should be released before create new one");
4192 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4193 if (player->pipeline == NULL)
4196 /* create mainbin */
4197 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4198 if (mainbin == NULL)
4201 /* create pipeline */
4202 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4203 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4204 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4205 LOGE("failed to create pipeline");
4210 player->pipeline->mainbin = mainbin;
4212 /* create the source and decoder elements */
4213 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4214 ret = _mmplayer_gst_build_es_pipeline(player);
4216 ret = _mmplayer_gst_build_pipeline(player);
4218 if (ret != MM_ERROR_NONE) {
4219 LOGE("failed to create some elements");
4223 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4224 if (__mmplayer_check_subtitle(player)
4225 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4226 LOGE("failed to create text pipeline");
4229 ret = _mmplayer_gst_add_bus_watch(player);
4230 if (ret != MM_ERROR_NONE) {
4231 LOGE("failed to add bus watch");
4236 return MM_ERROR_NONE;
4239 __mmplayer_gst_destroy_pipeline(player);
4240 return MM_ERROR_PLAYER_INTERNAL;
4244 __mmplayer_reset_gapless_state(mmplayer_t *player)
4247 MMPLAYER_RETURN_IF_FAIL(player
4249 && player->pipeline->audiobin
4250 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4252 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4259 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4262 int ret = MM_ERROR_NONE;
4266 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4268 /* cleanup stuffs */
4269 MMPLAYER_FREEIF(player->type);
4270 player->no_more_pad = FALSE;
4271 player->num_dynamic_pad = 0;
4272 player->demux_pad_index = 0;
4274 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4275 player->subtitle_language_list = NULL;
4276 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4278 __mmplayer_reset_gapless_state(player);
4280 if (player->streamer) {
4281 _mm_player_streaming_initialize(player->streamer, FALSE);
4282 _mm_player_streaming_destroy(player->streamer);
4283 player->streamer = NULL;
4286 /* cleanup unlinked mime type */
4287 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4288 MMPLAYER_FREEIF(player->unlinked_video_mime);
4289 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4291 /* cleanup running stuffs */
4292 _mmplayer_cancel_eos_timer(player);
4294 /* cleanup gst stuffs */
4295 if (player->pipeline) {
4296 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4297 GstTagList *tag_list = player->pipeline->tag_list;
4299 /* first we need to disconnect all signal hander */
4300 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4303 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4304 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4305 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4306 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4307 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4308 gst_object_unref(bus);
4310 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4311 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4312 if (ret != MM_ERROR_NONE) {
4313 LOGE("fail to change state to NULL");
4314 return MM_ERROR_PLAYER_INTERNAL;
4317 LOGW("succeeded in changing state to NULL");
4319 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4322 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4323 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4325 /* free avsysaudiosink
4326 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4327 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4329 MMPLAYER_FREEIF(audiobin);
4330 MMPLAYER_FREEIF(videobin);
4331 MMPLAYER_FREEIF(textbin);
4332 MMPLAYER_FREEIF(mainbin);
4336 gst_tag_list_unref(tag_list);
4338 MMPLAYER_FREEIF(player->pipeline);
4340 MMPLAYER_FREEIF(player->album_art);
4342 if (player->v_stream_caps) {
4343 gst_caps_unref(player->v_stream_caps);
4344 player->v_stream_caps = NULL;
4347 if (player->a_stream_caps) {
4348 gst_caps_unref(player->a_stream_caps);
4349 player->a_stream_caps = NULL;
4352 if (player->s_stream_caps) {
4353 gst_caps_unref(player->s_stream_caps);
4354 player->s_stream_caps = NULL;
4356 _mmplayer_track_destroy(player);
4358 if (player->sink_elements)
4359 g_list_free(player->sink_elements);
4360 player->sink_elements = NULL;
4362 if (player->bufmgr) {
4363 tbm_bufmgr_deinit(player->bufmgr);
4364 player->bufmgr = NULL;
4367 LOGW("finished destroy pipeline");
4375 __mmplayer_gst_realize(mmplayer_t *player)
4378 int ret = MM_ERROR_NONE;
4382 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4384 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4386 ret = __mmplayer_gst_create_pipeline(player);
4388 LOGE("failed to create pipeline");
4392 /* set pipeline state to READY */
4393 /* NOTE : state change to READY must be performed sync. */
4394 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4395 ret = _mmplayer_gst_set_state(player,
4396 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4398 if (ret != MM_ERROR_NONE) {
4399 /* return error if failed to set state */
4400 LOGE("failed to set READY state");
4404 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4406 /* create dot before error-return. for debugging */
4407 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4415 __mmplayer_gst_unrealize(mmplayer_t *player)
4417 int ret = MM_ERROR_NONE;
4421 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4423 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4424 MMPLAYER_PRINT_STATE(player);
4426 /* release miscellaneous information */
4427 __mmplayer_release_misc(player);
4429 /* destroy pipeline */
4430 ret = __mmplayer_gst_destroy_pipeline(player);
4431 if (ret != MM_ERROR_NONE) {
4432 LOGE("failed to destory pipeline");
4436 /* release miscellaneous information.
4437 these info needs to be released after pipeline is destroyed. */
4438 __mmplayer_release_misc_post(player);
4440 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4448 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4453 LOGW("set_message_callback is called with invalid player handle");
4454 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4457 player->msg_cb = callback;
4458 player->msg_cb_param = user_param;
4460 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4464 return MM_ERROR_NONE;
4468 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4470 int ret = MM_ERROR_NONE;
4475 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4476 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4477 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4479 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4481 if (strstr(uri, "es_buff://")) {
4482 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4483 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4484 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4485 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4487 tmp = g_ascii_strdown(uri, strlen(uri));
4488 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4489 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4491 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4493 } else if (strstr(uri, "mms://")) {
4494 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4495 } else if ((path = strstr(uri, "mem://"))) {
4496 ret = __mmplayer_set_mem_uri(data, path, param);
4498 ret = __mmplayer_set_file_uri(data, uri);
4501 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4502 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4503 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4504 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4506 /* dump parse result */
4507 SECURE_LOGW("incoming uri : %s", uri);
4508 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4509 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4517 __mmplayer_can_do_interrupt(mmplayer_t *player)
4519 if (!player || !player->pipeline || !player->attrs) {
4520 LOGW("not initialized");
4524 if (player->audio_decoded_cb) {
4525 LOGW("not support in pcm extraction mode");
4529 /* check if seeking */
4530 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4531 MMMessageParamType msg_param;
4532 memset(&msg_param, 0, sizeof(MMMessageParamType));
4533 msg_param.code = MM_ERROR_PLAYER_SEEK;
4534 player->seek_state = MMPLAYER_SEEK_NONE;
4535 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4539 /* check other thread */
4540 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4541 LOGW("locked already, cmd state : %d", player->cmd);
4543 /* check application command */
4544 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4545 LOGW("playing.. should wait cmd lock then, will be interrupted");
4547 /* lock will be released at mrp_resource_release_cb() */
4548 MMPLAYER_CMD_LOCK(player);
4551 LOGW("nothing to do");
4554 LOGW("can interrupt immediately");
4558 FAILED: /* with CMD UNLOCKED */
4561 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4566 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4569 mmplayer_t *player = NULL;
4570 MMMessageParamType msg = {0, };
4572 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4577 LOGE("user_data is null");
4580 player = (mmplayer_t *)user_data;
4582 if (!__mmplayer_can_do_interrupt(player)) {
4583 LOGW("no need to interrupt, so leave");
4584 /* FIXME: there is no way to avoid releasing resource. */
4588 player->interrupted_by_resource = TRUE;
4590 /* get last play position */
4591 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4592 msg.union_type = MM_MSG_UNION_TIME;
4593 msg.time.elapsed = pos;
4594 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4596 LOGW("failed to get play position.");
4599 LOGD("video resource conflict so, resource will be freed by unrealizing");
4600 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4601 LOGE("failed to unrealize");
4603 /* lock is called in __mmplayer_can_do_interrupt() */
4604 MMPLAYER_CMD_UNLOCK(player);
4606 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4607 player->hw_resource[res_idx] = NULL;
4611 return TRUE; /* release all the resources */
4615 __mmplayer_initialize_video_roi(mmplayer_t *player)
4617 player->video_roi.scale_x = 0.0;
4618 player->video_roi.scale_y = 0.0;
4619 player->video_roi.scale_width = 1.0;
4620 player->video_roi.scale_height = 1.0;
4624 _mmplayer_create_player(MMHandleType handle)
4626 int ret = MM_ERROR_PLAYER_INTERNAL;
4627 bool enabled = false;
4629 mmplayer_t *player = MM_PLAYER_CAST(handle);
4633 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4635 /* initialize player state */
4636 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4637 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4638 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4639 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4641 /* check current state */
4642 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4644 /* construct attributes */
4645 player->attrs = _mmplayer_construct_attribute(handle);
4647 if (!player->attrs) {
4648 LOGE("Failed to construct attributes");
4652 /* initialize gstreamer with configured parameter */
4653 if (!__mmplayer_init_gstreamer(player)) {
4654 LOGE("Initializing gstreamer failed");
4655 _mmplayer_deconstruct_attribute(handle);
4659 /* create lock. note that g_tread_init() has already called in gst_init() */
4660 g_mutex_init(&player->fsink_lock);
4662 /* create update tag lock */
4663 g_mutex_init(&player->update_tag_lock);
4665 /* create gapless play mutex */
4666 g_mutex_init(&player->gapless_play_thread_mutex);
4668 /* create gapless play cond */
4669 g_cond_init(&player->gapless_play_thread_cond);
4671 /* create gapless play thread */
4672 player->gapless_play_thread =
4673 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4674 if (!player->gapless_play_thread) {
4675 LOGE("failed to create gapless play thread");
4676 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4677 g_mutex_clear(&player->gapless_play_thread_mutex);
4678 g_cond_clear(&player->gapless_play_thread_cond);
4682 player->bus_msg_q = g_queue_new();
4683 if (!player->bus_msg_q) {
4684 LOGE("failed to create queue for bus_msg");
4685 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4689 ret = _mmplayer_initialize_video_capture(player);
4690 if (ret != MM_ERROR_NONE) {
4691 LOGE("failed to initialize video capture");
4695 /* initialize resource manager */
4696 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4697 __resource_release_cb, player, &player->resource_manager)
4698 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4699 LOGE("failed to initialize resource manager");
4700 ret = MM_ERROR_PLAYER_INTERNAL;
4704 /* create video bo lock and cond */
4705 g_mutex_init(&player->video_bo_mutex);
4706 g_cond_init(&player->video_bo_cond);
4708 /* create subtitle info lock and cond */
4709 g_mutex_init(&player->subtitle_info_mutex);
4710 g_cond_init(&player->subtitle_info_cond);
4712 player->streaming_type = STREAMING_SERVICE_NONE;
4714 /* give default value of audio effect setting */
4715 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4716 player->sound.rg_enable = false;
4717 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4719 player->play_subtitle = FALSE;
4720 player->has_closed_caption = FALSE;
4721 player->pending_resume = FALSE;
4722 if (player->ini.dump_element_keyword[0][0] == '\0')
4723 player->ini.set_dump_element_flag = FALSE;
4725 player->ini.set_dump_element_flag = TRUE;
4727 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4728 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4729 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4731 /* Set video360 settings to their defaults for just-created player.
4734 player->is_360_feature_enabled = FALSE;
4735 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4736 LOGI("spherical feature info: %d", enabled);
4738 player->is_360_feature_enabled = TRUE;
4740 LOGE("failed to get spherical feature info");
4743 player->is_content_spherical = FALSE;
4744 player->is_video360_enabled = TRUE;
4745 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4746 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4747 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4748 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4749 player->video360_zoom = 1.0f;
4750 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4751 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4753 __mmplayer_initialize_video_roi(player);
4755 /* set player state to null */
4756 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4757 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4761 return MM_ERROR_NONE;
4765 g_mutex_clear(&player->fsink_lock);
4766 /* free update tag lock */
4767 g_mutex_clear(&player->update_tag_lock);
4768 g_queue_free(player->bus_msg_q);
4769 player->bus_msg_q = NULL;
4770 /* free gapless play thread */
4771 if (player->gapless_play_thread) {
4772 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4773 player->gapless_play_thread_exit = TRUE;
4774 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4775 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4777 g_thread_join(player->gapless_play_thread);
4778 player->gapless_play_thread = NULL;
4780 g_mutex_clear(&player->gapless_play_thread_mutex);
4781 g_cond_clear(&player->gapless_play_thread_cond);
4784 /* release attributes */
4785 _mmplayer_deconstruct_attribute(handle);
4793 __mmplayer_init_gstreamer(mmplayer_t *player)
4795 static gboolean initialized = FALSE;
4796 static const int max_argc = 50;
4798 gchar **argv = NULL;
4799 gchar **argv2 = NULL;
4805 LOGD("gstreamer already initialized.");
4810 argc = malloc(sizeof(int));
4811 argv = malloc(sizeof(gchar *) * max_argc);
4812 argv2 = malloc(sizeof(gchar *) * max_argc);
4814 if (!argc || !argv || !argv2)
4817 memset(argv, 0, sizeof(gchar *) * max_argc);
4818 memset(argv2, 0, sizeof(gchar *) * max_argc);
4822 argv[0] = g_strdup("mmplayer");
4825 for (i = 0; i < 5; i++) {
4826 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4827 if (strlen(player->ini.gst_param[i]) > 0) {
4828 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4833 /* we would not do fork for scanning plugins */
4834 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4837 /* check disable registry scan */
4838 if (player->ini.skip_rescan) {
4839 argv[*argc] = g_strdup("--gst-disable-registry-update");
4843 /* check disable segtrap */
4844 if (player->ini.disable_segtrap) {
4845 argv[*argc] = g_strdup("--gst-disable-segtrap");
4849 LOGD("initializing gstreamer with following parameter");
4850 LOGD("argc : %d", *argc);
4853 for (i = 0; i < arg_count; i++) {
4855 LOGD("argv[%d] : %s", i, argv2[i]);
4858 /* initializing gstreamer */
4859 if (!gst_init_check(argc, &argv, &err)) {
4860 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4867 for (i = 0; i < arg_count; i++) {
4868 //LOGD("release - argv[%d] : %s", i, argv2[i]);
4869 MMPLAYER_FREEIF(argv2[i]);
4872 MMPLAYER_FREEIF(argv);
4873 MMPLAYER_FREEIF(argv2);
4874 MMPLAYER_FREEIF(argc);
4884 for (i = 0; i < arg_count; i++) {
4885 LOGD("free[%d] : %s", i, argv2[i]);
4886 MMPLAYER_FREEIF(argv2[i]);
4889 MMPLAYER_FREEIF(argv);
4890 MMPLAYER_FREEIF(argv2);
4891 MMPLAYER_FREEIF(argc);
4897 __mmplayer_check_async_state_transition(mmplayer_t *player)
4899 GstState element_state = GST_STATE_VOID_PENDING;
4900 GstState element_pending_state = GST_STATE_VOID_PENDING;
4901 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4902 GstElement *element = NULL;
4903 gboolean async = FALSE;
4905 /* check player handle */
4906 MMPLAYER_RETURN_IF_FAIL(player &&
4908 player->pipeline->mainbin &&
4909 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4912 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4914 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4915 LOGD("don't need to check the pipeline state");
4919 MMPLAYER_PRINT_STATE(player);
4921 /* wait for state transition */
4922 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4923 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4925 if (ret == GST_STATE_CHANGE_FAILURE) {
4926 LOGE(" [%s] state : %s pending : %s",
4927 GST_ELEMENT_NAME(element),
4928 gst_element_state_get_name(element_state),
4929 gst_element_state_get_name(element_pending_state));
4931 /* dump state of all element */
4932 _mmplayer_dump_pipeline_state(player);
4937 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4942 _mmplayer_destroy(MMHandleType handle)
4944 mmplayer_t *player = MM_PLAYER_CAST(handle);
4948 /* check player handle */
4949 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4951 /* destroy can called at anytime */
4952 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4954 /* check async state transition */
4955 __mmplayer_check_async_state_transition(player);
4957 /* release gapless play thread */
4958 if (player->gapless_play_thread) {
4959 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4960 player->gapless_play_thread_exit = TRUE;
4961 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4962 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4964 LOGD("waitting for gapless play thread exit");
4965 g_thread_join(player->gapless_play_thread);
4966 g_mutex_clear(&player->gapless_play_thread_mutex);
4967 g_cond_clear(&player->gapless_play_thread_cond);
4968 LOGD("gapless play thread released");
4971 _mmplayer_release_video_capture(player);
4973 /* de-initialize resource manager */
4974 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4975 player->resource_manager))
4976 LOGE("failed to deinitialize resource manager");
4978 /* release pipeline */
4979 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4980 LOGE("failed to destory pipeline");
4981 return MM_ERROR_PLAYER_INTERNAL;
4984 g_queue_free(player->bus_msg_q);
4986 /* release subtitle info lock and cond */
4987 g_mutex_clear(&player->subtitle_info_mutex);
4988 g_cond_clear(&player->subtitle_info_cond);
4990 __mmplayer_release_dump_list(player->dump_list);
4992 /* release miscellaneous information */
4993 __mmplayer_release_misc(player);
4995 /* release miscellaneous information.
4996 these info needs to be released after pipeline is destroyed. */
4997 __mmplayer_release_misc_post(player);
4999 /* release attributes */
5000 _mmplayer_deconstruct_attribute(handle);
5003 g_mutex_clear(&player->fsink_lock);
5006 g_mutex_clear(&player->update_tag_lock);
5008 /* release video bo lock and cond */
5009 g_mutex_clear(&player->video_bo_mutex);
5010 g_cond_clear(&player->video_bo_cond);
5014 return MM_ERROR_NONE;
5018 _mmplayer_realize(MMHandleType hplayer)
5020 mmplayer_t *player = (mmplayer_t *)hplayer;
5023 MMHandleType attrs = 0;
5024 int ret = MM_ERROR_NONE;
5028 /* check player handle */
5029 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5031 /* check current state */
5032 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5034 attrs = MMPLAYER_GET_ATTRS(player);
5036 LOGE("fail to get attributes.");
5037 return MM_ERROR_PLAYER_INTERNAL;
5039 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5040 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5042 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5043 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5045 if (ret != MM_ERROR_NONE) {
5046 LOGE("failed to parse profile");
5051 if (uri && (strstr(uri, "es_buff://"))) {
5052 if (strstr(uri, "es_buff://push_mode"))
5053 player->es_player_push_mode = TRUE;
5055 player->es_player_push_mode = FALSE;
5058 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5059 LOGW("mms protocol is not supported format.");
5060 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5063 if (MMPLAYER_IS_STREAMING(player))
5064 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5066 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5068 player->smooth_streaming = FALSE;
5069 player->videodec_linked = 0;
5070 player->audiodec_linked = 0;
5071 player->textsink_linked = 0;
5072 player->is_external_subtitle_present = FALSE;
5073 player->is_external_subtitle_added_now = FALSE;
5074 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5075 player->video360_metadata.is_spherical = -1;
5076 player->is_openal_plugin_used = FALSE;
5077 player->demux_pad_index = 0;
5078 player->subtitle_language_list = NULL;
5079 player->is_subtitle_force_drop = FALSE;
5081 _mmplayer_track_initialize(player);
5082 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5084 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5085 gint prebuffer_ms = 0, rebuffer_ms = 0;
5087 player->streamer = _mm_player_streaming_create();
5088 _mm_player_streaming_initialize(player->streamer, TRUE);
5090 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_PREBUFFER_MS, &prebuffer_ms);
5091 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_REBUFFER_MS, &rebuffer_ms);
5093 if (prebuffer_ms > 0) {
5094 prebuffer_ms = MAX(prebuffer_ms, 1000);
5095 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5098 if (rebuffer_ms > 0) {
5099 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5100 rebuffer_ms = MAX(rebuffer_ms, 1000);
5101 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5104 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5105 player->streamer->buffering_req.rebuffer_time);
5108 /* realize pipeline */
5109 ret = __mmplayer_gst_realize(player);
5110 if (ret != MM_ERROR_NONE)
5111 LOGE("fail to realize the player.");
5113 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5121 _mmplayer_unrealize(MMHandleType hplayer)
5123 mmplayer_t *player = (mmplayer_t *)hplayer;
5124 int ret = MM_ERROR_NONE;
5128 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5130 MMPLAYER_CMD_UNLOCK(player);
5131 /* destroy the gst bus msg thread which is created during realize.
5132 this funct have to be called before getting cmd lock. */
5133 _mmplayer_bus_msg_thread_destroy(player);
5134 MMPLAYER_CMD_LOCK(player);
5136 /* check current state */
5137 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5139 /* check async state transition */
5140 __mmplayer_check_async_state_transition(player);
5142 /* unrealize pipeline */
5143 ret = __mmplayer_gst_unrealize(player);
5145 if (!player->interrupted_by_resource) {
5146 if ((__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) ||
5147 (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE))
5148 LOGE("failed to release video resources");
5156 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5158 mmplayer_t *player = (mmplayer_t *)hplayer;
5160 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5162 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5166 _mmplayer_get_state(MMHandleType hplayer, int *state)
5168 mmplayer_t *player = (mmplayer_t *)hplayer;
5170 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5172 *state = MMPLAYER_CURRENT_STATE(player);
5174 return MM_ERROR_NONE;
5178 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5180 GstElement *vol_element = NULL;
5181 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5184 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5185 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5187 /* check pipeline handle */
5188 if (!player->pipeline || !player->pipeline->audiobin) {
5189 LOGD("'%s' will be applied when audiobin is created", prop_name);
5191 /* NOTE : stored value will be used in create_audiobin
5192 * returning MM_ERROR_NONE here makes application to able to
5193 * set audio volume or mute at anytime.
5195 return MM_ERROR_NONE;
5198 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5199 volume_elem_id = MMPLAYER_A_SINK;
5201 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5203 LOGE("failed to get vol element %d", volume_elem_id);
5204 return MM_ERROR_PLAYER_INTERNAL;
5207 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5209 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5210 LOGE("there is no '%s' property", prop_name);
5211 return MM_ERROR_PLAYER_INTERNAL;
5214 if (!strcmp(prop_name, "volume")) {
5215 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5216 } else if (!strcmp(prop_name, "mute")) {
5217 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5219 LOGE("invalid property %s", prop_name);
5220 return MM_ERROR_PLAYER_INTERNAL;
5223 return MM_ERROR_NONE;
5227 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5229 int ret = MM_ERROR_NONE;
5230 mmplayer_t *player = (mmplayer_t *)hplayer;
5233 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5235 LOGD("volume = %f", volume);
5237 /* invalid factor range or not */
5238 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5239 LOGE("Invalid volume value");
5240 return MM_ERROR_INVALID_ARGUMENT;
5243 player->sound.volume = volume;
5245 ret = __mmplayer_gst_set_volume_property(player, "volume");
5252 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5254 mmplayer_t *player = (mmplayer_t *)hplayer;
5258 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5259 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5261 *volume = player->sound.volume;
5263 LOGD("current vol = %f", *volume);
5266 return MM_ERROR_NONE;
5270 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5272 int ret = MM_ERROR_NONE;
5273 mmplayer_t *player = (mmplayer_t *)hplayer;
5276 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5278 LOGD("mute = %d", mute);
5280 player->sound.mute = mute;
5282 ret = __mmplayer_gst_set_volume_property(player, "mute");
5289 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5291 mmplayer_t *player = (mmplayer_t *)hplayer;
5295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5296 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5298 *mute = player->sound.mute;
5300 LOGD("current mute = %d", *mute);
5304 return MM_ERROR_NONE;
5308 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5310 mmplayer_t *player = (mmplayer_t *)hplayer;
5314 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5316 player->audio_stream_changed_cb = callback;
5317 player->audio_stream_changed_cb_user_param = user_param;
5318 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5322 return MM_ERROR_NONE;
5326 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5328 mmplayer_t *player = (mmplayer_t *)hplayer;
5332 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5334 player->audio_decoded_cb = callback;
5335 player->audio_decoded_cb_user_param = user_param;
5336 player->audio_extract_opt = opt;
5337 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5341 return MM_ERROR_NONE;
5345 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5347 mmplayer_t *player = (mmplayer_t *)hplayer;
5351 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5353 if (callback && !player->bufmgr)
5354 player->bufmgr = tbm_bufmgr_init(-1);
5356 player->set_mode.video_export = (callback) ? true : false;
5357 player->video_decoded_cb = callback;
5358 player->video_decoded_cb_user_param = user_param;
5360 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5364 return MM_ERROR_NONE;
5368 _mmplayer_start(MMHandleType hplayer)
5370 mmplayer_t *player = (mmplayer_t *)hplayer;
5371 gint ret = MM_ERROR_NONE;
5375 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5377 /* check current state */
5378 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5380 /* start pipeline */
5381 ret = _mmplayer_gst_start(player);
5382 if (ret != MM_ERROR_NONE)
5383 LOGE("failed to start player.");
5385 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5386 LOGD("force playing start even during buffering");
5387 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5395 /* NOTE: post "not supported codec message" to application
5396 * when one codec is not found during AUTOPLUGGING in MSL.
5397 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5398 * And, if any codec is not found, don't send message here.
5399 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5402 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5404 MMMessageParamType msg_param;
5405 memset(&msg_param, 0, sizeof(MMMessageParamType));
5406 gboolean post_msg_direct = FALSE;
5410 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5412 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5413 player->not_supported_codec, player->can_support_codec);
5415 if (player->not_found_demuxer) {
5416 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5417 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5419 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5420 MMPLAYER_FREEIF(msg_param.data);
5422 return MM_ERROR_NONE;
5425 if (player->not_supported_codec) {
5426 if (player->can_support_codec) {
5427 // There is one codec to play
5428 post_msg_direct = TRUE;
5430 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5431 post_msg_direct = TRUE;
5434 if (post_msg_direct) {
5435 MMMessageParamType msg_param;
5436 memset(&msg_param, 0, sizeof(MMMessageParamType));
5438 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5439 LOGW("not found AUDIO codec, posting error code to application.");
5441 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5442 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5443 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5444 LOGW("not found VIDEO codec, posting error code to application.");
5446 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5447 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5450 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5452 MMPLAYER_FREEIF(msg_param.data);
5454 return MM_ERROR_NONE;
5456 // no any supported codec case
5457 LOGW("not found any codec, posting error code to application.");
5459 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5460 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5461 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5463 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5464 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5467 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5469 MMPLAYER_FREEIF(msg_param.data);
5475 return MM_ERROR_NONE;
5479 __mmplayer_check_pipeline(mmplayer_t *player)
5481 GstState element_state = GST_STATE_VOID_PENDING;
5482 GstState element_pending_state = GST_STATE_VOID_PENDING;
5484 int ret = MM_ERROR_NONE;
5486 if (!player->gapless.reconfigure)
5489 LOGW("pipeline is under construction.");
5491 MMPLAYER_PLAYBACK_LOCK(player);
5492 MMPLAYER_PLAYBACK_UNLOCK(player);
5494 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5496 /* wait for state transition */
5497 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5498 if (ret == GST_STATE_CHANGE_FAILURE)
5499 LOGE("failed to change pipeline state within %d sec", timeout);
5502 /* NOTE : it should be able to call 'stop' anytime*/
5504 _mmplayer_stop(MMHandleType hplayer)
5506 mmplayer_t *player = (mmplayer_t *)hplayer;
5507 int ret = MM_ERROR_NONE;
5511 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5513 /* check current state */
5514 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5516 /* check pipline building state */
5517 __mmplayer_check_pipeline(player);
5518 __mmplayer_reset_gapless_state(player);
5520 /* NOTE : application should not wait for EOS after calling STOP */
5521 _mmplayer_cancel_eos_timer(player);
5524 player->seek_state = MMPLAYER_SEEK_NONE;
5527 ret = _mmplayer_gst_stop(player);
5529 if (ret != MM_ERROR_NONE)
5530 LOGE("failed to stop player.");
5538 _mmplayer_pause(MMHandleType hplayer)
5540 mmplayer_t *player = (mmplayer_t *)hplayer;
5541 gint64 pos_nsec = 0;
5542 gboolean async = FALSE;
5543 gint ret = MM_ERROR_NONE;
5547 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5549 /* check current state */
5550 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5552 /* check pipline building state */
5553 __mmplayer_check_pipeline(player);
5555 switch (MMPLAYER_CURRENT_STATE(player)) {
5556 case MM_PLAYER_STATE_READY:
5558 /* check prepare async or not.
5559 * In the case of streaming playback, it's recommned to avoid blocking wait.
5561 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5562 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5564 /* Changing back sync of rtspsrc to async */
5565 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5566 LOGD("async prepare working mode for rtsp");
5572 case MM_PLAYER_STATE_PLAYING:
5574 /* NOTE : store current point to overcome some bad operation
5575 *(returning zero when getting current position in paused state) of some
5578 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5579 LOGW("getting current position failed in paused");
5581 player->last_position = pos_nsec;
5583 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5584 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5585 This causes problem is position calculation during normal pause resume scenarios also.
5586 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5587 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5588 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5589 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5595 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5596 LOGD("doing async pause in case of ms buff src");
5600 /* pause pipeline */
5601 ret = _mmplayer_gst_pause(player, async);
5603 if (ret != MM_ERROR_NONE)
5604 LOGE("failed to pause player. ret : 0x%x", ret);
5606 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5607 if (MM_ERROR_NONE != _mmplayer_update_video_param(player, "display_rotation"))
5608 LOGE("failed to update display_rotation");
5616 /* in case of streaming, pause could take long time.*/
5618 _mmplayer_abort_pause(MMHandleType hplayer)
5620 mmplayer_t *player = (mmplayer_t *)hplayer;
5621 int ret = MM_ERROR_NONE;
5625 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5627 player->pipeline->mainbin,
5628 MM_ERROR_PLAYER_NOT_INITIALIZED);
5630 LOGD("set the pipeline state to READY");
5632 /* set state to READY */
5633 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5634 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5635 if (ret != MM_ERROR_NONE) {
5636 LOGE("fail to change state to READY");
5637 return MM_ERROR_PLAYER_INTERNAL;
5640 LOGD("succeeded in changing state to READY");
5645 _mmplayer_resume(MMHandleType hplayer)
5647 mmplayer_t *player = (mmplayer_t *)hplayer;
5648 int ret = MM_ERROR_NONE;
5649 gboolean async = FALSE;
5653 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5655 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5656 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5657 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5661 /* Changing back sync mode rtspsrc to async */
5662 LOGD("async resume for rtsp case");
5666 /* check current state */
5667 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5669 ret = _mmplayer_gst_resume(player, async);
5670 if (ret != MM_ERROR_NONE)
5671 LOGE("failed to resume player.");
5673 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5674 LOGD("force resume even during buffering");
5675 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5684 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5686 mmplayer_t *player = (mmplayer_t *)hplayer;
5687 gint64 pos_nsec = 0;
5688 int ret = MM_ERROR_NONE;
5690 signed long long start = 0, stop = 0;
5691 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5694 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5695 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5697 /* The sound of video is not supported under 0.0 and over 2.0. */
5698 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5699 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5702 _mmplayer_set_mute(hplayer, mute);
5704 if (player->playback_rate == rate)
5705 return MM_ERROR_NONE;
5707 /* If the position is reached at start potion during fast backward, EOS is posted.
5708 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5710 player->playback_rate = rate;
5712 current_state = MMPLAYER_CURRENT_STATE(player);
5714 if (current_state != MM_PLAYER_STATE_PAUSED)
5715 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5717 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5719 if ((current_state == MM_PLAYER_STATE_PAUSED)
5720 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5721 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5722 pos_nsec = player->last_position;
5727 stop = GST_CLOCK_TIME_NONE;
5729 start = GST_CLOCK_TIME_NONE;
5733 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5734 player->playback_rate,
5736 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5737 GST_SEEK_TYPE_SET, start,
5738 GST_SEEK_TYPE_SET, stop)) {
5739 LOGE("failed to set speed playback");
5740 return MM_ERROR_PLAYER_SEEK;
5743 LOGD("succeeded to set speed playback as %0.1f", rate);
5747 return MM_ERROR_NONE;;
5751 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5753 mmplayer_t *player = (mmplayer_t *)hplayer;
5754 int ret = MM_ERROR_NONE;
5758 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5760 /* check pipline building state */
5761 __mmplayer_check_pipeline(player);
5763 ret = _mmplayer_gst_set_position(player, position, FALSE);
5771 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5773 mmplayer_t *player = (mmplayer_t *)hplayer;
5774 int ret = MM_ERROR_NONE;
5776 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5777 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5779 if (g_strrstr(player->type, "video/mpegts"))
5780 __mmplayer_update_duration_value(player);
5782 *duration = player->duration;
5787 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5789 mmplayer_t *player = (mmplayer_t *)hplayer;
5790 int ret = MM_ERROR_NONE;
5792 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5794 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5800 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5802 mmplayer_t *player = (mmplayer_t *)hplayer;
5803 int ret = MM_ERROR_NONE;
5807 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5809 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5817 __mmplayer_is_midi_type(gchar *str_caps)
5819 if ((g_strrstr(str_caps, "audio/midi")) ||
5820 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5821 (g_strrstr(str_caps, "application/x-smaf")) ||
5822 (g_strrstr(str_caps, "audio/x-imelody")) ||
5823 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5824 (g_strrstr(str_caps, "audio/xmf")) ||
5825 (g_strrstr(str_caps, "audio/mxmf"))) {
5834 __mmplayer_is_only_mp3_type(gchar *str_caps)
5836 if (g_strrstr(str_caps, "application/x-id3") ||
5837 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5843 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5845 GstStructure *caps_structure = NULL;
5846 gint samplerate = 0;
5850 MMPLAYER_RETURN_IF_FAIL(player && caps);
5852 caps_structure = gst_caps_get_structure(caps, 0);
5854 /* set stream information */
5855 gst_structure_get_int(caps_structure, "rate", &samplerate);
5856 mm_attrs_set_int_by_name(player->attrs, "content_audio_samplerate", samplerate);
5858 gst_structure_get_int(caps_structure, "channels", &channels);
5859 mm_attrs_set_int_by_name(player->attrs, "content_audio_channels", channels);
5861 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5865 __mmplayer_update_content_type_info(mmplayer_t *player)
5868 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5870 if (__mmplayer_is_midi_type(player->type)) {
5871 player->bypass_audio_effect = TRUE;
5875 if (!player->streamer) {
5876 LOGD("no need to check streaming type");
5880 if (g_strrstr(player->type, "application/x-hls")) {
5881 /* If it can't know exact type when it parses uri because of redirection case,
5882 * it will be fixed by typefinder or when doing autoplugging.
5884 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5885 player->streamer->is_adaptive_streaming = TRUE;
5886 } else if (g_strrstr(player->type, "application/dash+xml")) {
5887 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5888 player->streamer->is_adaptive_streaming = TRUE;
5891 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5892 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5893 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5895 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5896 if (player->streamer->is_adaptive_streaming)
5897 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5899 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5903 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5908 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5909 GstCaps *caps, gpointer data)
5911 mmplayer_t *player = (mmplayer_t *)data;
5916 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5918 /* store type string */
5919 MMPLAYER_FREEIF(player->type);
5920 player->type = gst_caps_to_string(caps);
5922 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5923 player, player->type, probability, gst_caps_get_size(caps));
5925 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5926 (g_strrstr(player->type, "audio/x-raw-int"))) {
5927 LOGE("not support media format");
5929 if (player->msg_posted == FALSE) {
5930 MMMessageParamType msg_param;
5931 memset(&msg_param, 0, sizeof(MMMessageParamType));
5933 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5934 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5936 /* don't post more if one was sent already */
5937 player->msg_posted = TRUE;
5942 __mmplayer_update_content_type_info(player);
5944 pad = gst_element_get_static_pad(tf, "src");
5946 LOGE("fail to get typefind src pad.");
5950 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5951 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5952 gboolean async = FALSE;
5953 LOGE("failed to autoplug %s", player->type);
5955 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5957 if (async && player->msg_posted == FALSE)
5958 __mmplayer_handle_missed_plugin(player);
5962 gst_object_unref(GST_OBJECT(pad));
5968 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5970 GstElement *decodebin = NULL;
5974 /* create decodebin */
5975 decodebin = gst_element_factory_make("decodebin", NULL);
5978 LOGE("fail to create decodebin");
5982 /* raw pad handling signal */
5983 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5984 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5986 /* no-more-pad pad handling signal */
5987 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5988 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
5990 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5991 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
5993 /* This signal is emitted when a pad for which there is no further possible
5994 decoding is added to the decodebin.*/
5995 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5996 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
5998 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5999 before looking for any elements that can handle that stream.*/
6000 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6001 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6003 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6004 before looking for any elements that can handle that stream.*/
6005 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6006 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6008 /* This signal is emitted once decodebin has finished decoding all the data.*/
6009 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6010 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6012 /* This signal is emitted when a element is added to the bin.*/
6013 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6014 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6021 __mmplayer_gst_make_queue2(mmplayer_t *player)
6023 GstElement *queue2 = NULL;
6024 gint64 dur_bytes = 0L;
6025 mmplayer_gst_element_t *mainbin = NULL;
6026 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6029 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6031 mainbin = player->pipeline->mainbin;
6033 queue2 = gst_element_factory_make("queue2", "queue2");
6035 LOGE("failed to create buffering queue element");
6039 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6040 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6042 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6044 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6045 * skip the pull mode(file or ring buffering) setting. */
6046 if (dur_bytes > 0) {
6047 if (!g_strrstr(player->type, "video/mpegts")) {
6048 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6049 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6055 _mm_player_streaming_set_queue2(player->streamer,
6059 (guint64)dur_bytes); /* no meaning at the moment */
6065 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6067 mmplayer_gst_element_t *mainbin = NULL;
6068 GstElement *decodebin = NULL;
6069 GstElement *queue2 = NULL;
6070 GstPad *sinkpad = NULL;
6071 GstPad *qsrcpad = NULL;
6074 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6076 mainbin = player->pipeline->mainbin;
6078 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6080 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6081 LOGW("need to check: muxed buffer is not null");
6084 queue2 = __mmplayer_gst_make_queue2(player);
6086 LOGE("failed to make queue2");
6090 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6091 LOGE("failed to add buffering queue");
6095 sinkpad = gst_element_get_static_pad(queue2, "sink");
6096 qsrcpad = gst_element_get_static_pad(queue2, "src");
6098 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6099 LOGE("failed to link [%s:%s]-[%s:%s]",
6100 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6104 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6105 LOGE("failed to sync queue2 state with parent");
6109 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6110 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6114 gst_object_unref(GST_OBJECT(sinkpad));
6118 /* create decodebin */
6119 decodebin = _mmplayer_gst_make_decodebin(player);
6121 LOGE("failed to make decodebin");
6125 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6126 LOGE("failed to add decodebin");
6130 /* to force caps on the decodebin element and avoid reparsing stuff by
6131 * typefind. It also avoids a deadlock in the way typefind activates pads in
6132 * the state change */
6133 g_object_set(decodebin, "sink-caps", caps, NULL);
6135 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6137 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6138 LOGE("failed to link [%s:%s]-[%s:%s]",
6139 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6143 gst_object_unref(GST_OBJECT(sinkpad));
6145 gst_object_unref(GST_OBJECT(qsrcpad));
6148 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6149 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6151 /* set decodebin property about buffer in streaming playback. *
6152 * in case of HLS/DASH, it does not need to have big buffer *
6153 * because it is kind of adaptive streaming. */
6154 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6155 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6156 gint high_percent = 0;
6158 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6159 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6161 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6163 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6165 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6166 "high-percent", high_percent,
6167 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6168 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6169 "max-size-buffers", 0, NULL); // disable or automatic
6172 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6173 LOGE("failed to sync decodebin state with parent");
6184 gst_object_unref(GST_OBJECT(sinkpad));
6187 gst_object_unref(GST_OBJECT(qsrcpad));
6190 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6191 * You need to explicitly set elements to the NULL state before
6192 * dropping the final reference, to allow them to clean up.
6194 gst_element_set_state(queue2, GST_STATE_NULL);
6196 /* And, it still has a parent "player".
6197 * You need to let the parent manage the object instead of unreffing the object directly.
6199 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6200 gst_object_unref(queue2);
6205 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6206 * You need to explicitly set elements to the NULL state before
6207 * dropping the final reference, to allow them to clean up.
6209 gst_element_set_state(decodebin, GST_STATE_NULL);
6211 /* And, it still has a parent "player".
6212 * You need to let the parent manage the object instead of unreffing the object directly.
6215 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6216 gst_object_unref(decodebin);
6224 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6228 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6229 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6231 LOGD("class : %s, mime : %s", factory_class, mime);
6233 /* add missing plugin */
6234 /* NOTE : msl should check missing plugin for image mime type.
6235 * Some motion jpeg clips can have playable audio track.
6236 * So, msl have to play audio after displaying popup written video format not supported.
6238 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6239 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6240 LOGD("not found demuxer");
6241 player->not_found_demuxer = TRUE;
6242 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6248 if (!g_strrstr(factory_class, "Demuxer")) {
6249 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6250 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6251 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6253 /* check that clip have multi tracks or not */
6254 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6255 LOGD("video plugin is already linked");
6257 LOGW("add VIDEO to missing plugin");
6258 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6259 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6261 } else if (g_str_has_prefix(mime, "audio")) {
6262 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6263 LOGD("audio plugin is already linked");
6265 LOGW("add AUDIO to missing plugin");
6266 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6267 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6275 return MM_ERROR_NONE;
6279 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6281 mmplayer_t *player = (mmplayer_t *)data;
6285 MMPLAYER_RETURN_IF_FAIL(player);
6287 /* remove fakesink. */
6288 if (!_mmplayer_gst_remove_fakesink(player,
6289 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6290 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6291 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6292 * source element are not same. To overcome this situation, this function will called
6293 * several places and several times. Therefore, this is not an error case.
6298 LOGD("[handle: %p] pipeline has completely constructed", player);
6300 if ((player->ini.async_start) &&
6301 (player->msg_posted == FALSE) &&
6302 (player->cmd >= MMPLAYER_COMMAND_START))
6303 __mmplayer_handle_missed_plugin(player);
6305 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6309 __mmplayer_check_profile(void)
6312 static int profile_tv = -1;
6314 if (__builtin_expect(profile_tv != -1, 1))
6317 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6318 switch (*profileName) {
6333 __mmplayer_get_next_uri(mmplayer_t *player)
6335 mmplayer_parse_profile_t profile;
6337 guint num_of_list = 0;
6340 num_of_list = g_list_length(player->uri_info.uri_list);
6341 uri_idx = player->uri_info.uri_idx;
6343 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6344 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6345 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6347 LOGW("next uri does not exist");
6351 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6352 LOGE("failed to parse profile");
6356 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6357 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6358 LOGW("uri type is not supported(%d)", profile.uri_type);
6362 LOGD("success to find next uri %d", uri_idx);
6366 if (uri_idx == num_of_list) {
6367 LOGE("failed to find next uri");
6371 player->uri_info.uri_idx = uri_idx;
6372 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6374 if (mm_attrs_commit_all(player->attrs)) {
6375 LOGE("failed to commit");
6379 SECURE_LOGD("next playback uri: %s", uri);
6384 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6386 #define REPEAT_COUNT_INFINITE -1
6387 #define REPEAT_COUNT_MIN 2
6388 #define ORIGINAL_URI_ONLY 1
6390 MMHandleType attrs = 0;
6394 guint num_of_uri = 0;
6395 int profile_tv = -1;
6399 LOGD("checking for gapless play option");
6401 if (player->pipeline->textbin) {
6402 LOGE("subtitle path is enabled. gapless play is not supported.");
6406 attrs = MMPLAYER_GET_ATTRS(player);
6408 LOGE("fail to get attributes.");
6412 mm_attrs_get_int_by_name(attrs, "content_video_found", &video);
6414 /* gapless playback is not supported in case of video at TV profile. */
6415 profile_tv = __mmplayer_check_profile();
6416 if (profile_tv && video) {
6417 LOGW("not support video gapless playback");
6421 if (mm_attrs_get_int_by_name(attrs, "profile_play_count", &count) != MM_ERROR_NONE)
6422 LOGE("failed to get play count");
6424 if (mm_attrs_get_int_by_name(attrs, "gapless_mode", &gapless) != MM_ERROR_NONE)
6425 LOGE("failed to get gapless mode");
6427 /* check repeat count in case of audio */
6429 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6430 LOGW("gapless is disabled");
6434 num_of_uri = g_list_length(player->uri_info.uri_list);
6436 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6438 if (num_of_uri == ORIGINAL_URI_ONLY) {
6439 /* audio looping path */
6440 if (count >= REPEAT_COUNT_MIN) {
6441 /* decrease play count */
6442 /* we succeeded to rewind. update play count and then wait for next EOS */
6444 mm_attrs_set_int_by_name(attrs, "profile_play_count", count);
6445 /* commit attribute */
6446 if (mm_attrs_commit_all(attrs))
6447 LOGE("failed to commit attribute");
6449 } else if (count != REPEAT_COUNT_INFINITE) {
6450 LOGD("there is no next uri and no repeat");
6453 LOGD("looping cnt %d", count);
6455 /* gapless playback path */
6456 if (!__mmplayer_get_next_uri(player)) {
6457 LOGE("failed to get next uri");
6464 LOGE("unable to play gapless path. EOS will be posted soon");
6469 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6471 mmplayer_selector_t *selector = &player->selector[type];
6472 mmplayer_gst_element_t *sinkbin = NULL;
6473 main_element_id_e selectorId = MMPLAYER_M_NUM;
6474 main_element_id_e sinkId = MMPLAYER_M_NUM;
6475 GstPad *srcpad = NULL;
6476 GstPad *sinkpad = NULL;
6477 gboolean send_notice = FALSE;
6480 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6482 LOGD("type %d", type);
6485 case MM_PLAYER_TRACK_TYPE_AUDIO:
6486 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6487 sinkId = MMPLAYER_A_BIN;
6488 sinkbin = player->pipeline->audiobin;
6490 case MM_PLAYER_TRACK_TYPE_VIDEO:
6491 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6492 sinkId = MMPLAYER_V_BIN;
6493 sinkbin = player->pipeline->videobin;
6496 case MM_PLAYER_TRACK_TYPE_TEXT:
6497 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6498 sinkId = MMPLAYER_T_BIN;
6499 sinkbin = player->pipeline->textbin;
6502 LOGE("requested type is not supportable");
6507 if (player->pipeline->mainbin[selectorId].gst) {
6510 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6512 if (selector->event_probe_id != 0)
6513 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6514 selector->event_probe_id = 0;
6516 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6517 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6519 if (srcpad && sinkpad) {
6520 /* after getting drained signal there is no data flows, so no need to do pad_block */
6521 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6522 gst_pad_unlink(srcpad, sinkpad);
6524 /* send custom event to sink pad to handle it at video sink */
6526 LOGD("send custom event to sinkpad");
6527 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6528 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6529 gst_pad_send_event(sinkpad, event);
6533 gst_object_unref(sinkpad);
6536 gst_object_unref(srcpad);
6539 LOGD("selector release");
6541 /* release and unref requests pad from the selector */
6542 for (n = 0; n < selector->channels->len; n++) {
6543 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6544 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6546 g_ptr_array_set_size(selector->channels, 0);
6548 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6549 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6551 player->pipeline->mainbin[selectorId].gst = NULL;
6559 __mmplayer_deactivate_old_path(mmplayer_t *player)
6562 MMPLAYER_RETURN_IF_FAIL(player);
6564 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6565 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6566 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6567 LOGE("deactivate selector error");
6571 _mmplayer_track_destroy(player);
6572 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6574 if (player->streamer) {
6575 _mm_player_streaming_initialize(player->streamer, FALSE);
6576 _mm_player_streaming_destroy(player->streamer);
6577 player->streamer = NULL;
6580 MMPLAYER_PLAYBACK_LOCK(player);
6581 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6588 if (!player->msg_posted) {
6589 MMMessageParamType msg = {0,};
6592 msg.code = MM_ERROR_PLAYER_INTERNAL;
6593 LOGE("gapless_uri_play> deactivate error");
6595 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6596 player->msg_posted = TRUE;
6602 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6604 int result = MM_ERROR_NONE;
6605 mmplayer_t *player = (mmplayer_t *)hplayer;
6608 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6610 mm_attrs_set_string_by_name(player->attrs, "profile_uri", uri);
6611 if (mm_attrs_commit_all(player->attrs)) {
6612 LOGE("failed to commit the original uri.");
6613 result = MM_ERROR_PLAYER_INTERNAL;
6615 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6616 LOGE("failed to add the original uri in the uri list.");
6624 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6626 mmplayer_t *player = (mmplayer_t *)hplayer;
6627 guint num_of_list = 0;
6631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6632 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6634 if (player->pipeline && player->pipeline->textbin) {
6635 LOGE("subtitle path is enabled.");
6636 return MM_ERROR_PLAYER_INVALID_STATE;
6639 num_of_list = g_list_length(player->uri_info.uri_list);
6641 if (is_first_path) {
6642 if (num_of_list == 0) {
6643 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6644 SECURE_LOGD("add original path : %s", uri);
6646 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6647 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6649 SECURE_LOGD("change original path : %s", uri);
6652 MMHandleType attrs = 0;
6653 attrs = MMPLAYER_GET_ATTRS(player);
6655 if (num_of_list == 0) {
6656 char *original_uri = NULL;
6659 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6661 if (!original_uri) {
6662 LOGE("there is no original uri.");
6663 return MM_ERROR_PLAYER_INVALID_STATE;
6666 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6667 player->uri_info.uri_idx = 0;
6669 SECURE_LOGD("add original path at first : %s", original_uri);
6673 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6674 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6678 return MM_ERROR_NONE;
6682 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6684 mmplayer_t *player = (mmplayer_t *)hplayer;
6685 char *next_uri = NULL;
6686 guint num_of_list = 0;
6689 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6691 num_of_list = g_list_length(player->uri_info.uri_list);
6693 if (num_of_list > 0) {
6694 gint uri_idx = player->uri_info.uri_idx;
6696 if (uri_idx < num_of_list-1)
6701 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6702 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6704 *uri = g_strdup(next_uri);
6708 return MM_ERROR_NONE;
6712 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6713 GstCaps *caps, gpointer data)
6715 mmplayer_t *player = (mmplayer_t *)data;
6716 const gchar *klass = NULL;
6717 const gchar *mime = NULL;
6718 gchar *caps_str = NULL;
6720 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6721 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6722 caps_str = gst_caps_to_string(caps);
6724 LOGW("unknown type of caps : %s from %s",
6725 caps_str, GST_ELEMENT_NAME(elem));
6727 MMPLAYER_FREEIF(caps_str);
6729 /* There is no available codec. */
6730 __mmplayer_check_not_supported_codec(player, klass, mime);
6734 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6735 GstCaps *caps, gpointer data)
6737 mmplayer_t *player = (mmplayer_t *)data;
6738 const char *mime = NULL;
6739 gboolean ret = TRUE;
6741 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6742 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6744 if (g_str_has_prefix(mime, "audio")) {
6745 GstStructure *caps_structure = NULL;
6746 gint samplerate = 0;
6748 gchar *caps_str = NULL;
6750 caps_structure = gst_caps_get_structure(caps, 0);
6751 gst_structure_get_int(caps_structure, "rate", &samplerate);
6752 gst_structure_get_int(caps_structure, "channels", &channels);
6754 if ((channels > 0 && samplerate == 0)) {
6755 LOGD("exclude audio...");
6759 caps_str = gst_caps_to_string(caps);
6760 /* set it directly because not sent by TAG */
6761 if (g_strrstr(caps_str, "mobile-xmf"))
6762 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", "mobile-xmf");
6763 MMPLAYER_FREEIF(caps_str);
6764 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6765 MMMessageParamType msg_param;
6766 memset(&msg_param, 0, sizeof(MMMessageParamType));
6767 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6768 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6769 LOGD("video file is not supported on this device");
6771 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6772 LOGD("already video linked");
6775 LOGD("found new stream");
6782 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6784 gboolean ret = TRUE;
6785 GDBusConnection *conn = NULL;
6787 GVariant *result = NULL;
6788 const gchar *dbus_device_type = NULL;
6789 const gchar *dbus_ret = NULL;
6792 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6794 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6800 result = g_dbus_connection_call_sync(conn,
6801 "org.pulseaudio.Server",
6802 "/org/pulseaudio/StreamManager",
6803 "org.pulseaudio.StreamManager",
6804 "GetCurrentMediaRoutingPath",
6805 g_variant_new("(s)", "out"),
6806 G_VARIANT_TYPE("(ss)"),
6807 G_DBUS_CALL_FLAGS_NONE,
6811 if (!result || err) {
6812 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6818 /* device type is listed in stream-map.json at mmfw-sysconf */
6819 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6821 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6822 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6827 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6828 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6829 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6830 LOGD("audio offload is supportable");
6836 LOGD("audio offload is not supportable");
6840 g_variant_unref(result);
6841 g_object_unref(conn);
6846 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6848 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6849 gint64 position = 0;
6851 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6852 player->pipeline && player->pipeline->mainbin);
6854 MMPLAYER_CMD_LOCK(player);
6855 current_state = MMPLAYER_CURRENT_STATE(player);
6857 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6858 LOGW("getting current position failed in paused");
6860 _mmplayer_unrealize((MMHandleType)player);
6861 _mmplayer_realize((MMHandleType)player);
6863 _mmplayer_set_position((MMHandleType)player, position);
6865 /* async not to be blocked in streaming case */
6866 mm_attrs_set_int_by_name(player->attrs, "profile_prepare_async", TRUE);
6867 if (mm_attrs_commit_all(player->attrs))
6868 LOGE("failed to commit");
6870 _mmplayer_pause((MMHandleType)player);
6872 if (current_state == MM_PLAYER_STATE_PLAYING)
6873 _mmplayer_start((MMHandleType)player);
6874 MMPLAYER_CMD_UNLOCK(player);
6876 LOGD("rebuilding audio pipeline is completed.");
6879 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6881 mmplayer_t *player = (mmplayer_t *)user_data;
6882 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6883 gboolean is_supportable = FALSE;
6885 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6886 LOGW("failed to get device type");
6888 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6890 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6891 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6892 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6893 LOGD("ignore this dev connected info");
6897 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6898 if (player->build_audio_offload == is_supportable) {
6899 LOGD("keep current pipeline without re-building");
6903 /* rebuild pipeline */
6904 LOGD("re-build pipeline - offload: %d", is_supportable);
6905 player->build_audio_offload = FALSE;
6906 __mmplayer_rebuild_audio_pipeline(player);
6912 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6914 unsigned int id = 0;
6916 if (player->audio_device_cb_id != 0) {
6917 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6921 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6922 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6923 LOGD("added device connected cb (%u)", id);
6924 player->audio_device_cb_id = id;
6926 LOGW("failed to add device connected cb");
6934 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6936 gboolean ret = FALSE;
6937 GstElementFactory *factory = NULL;
6940 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6942 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6943 if (!__mmplayer_is_only_mp3_type(player->type))
6946 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6947 LOGD("there is no audio offload sink");
6951 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6952 LOGW("there is no audio device type to support offload");
6956 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6958 LOGW("there is no installed audio offload sink element");
6961 gst_object_unref(factory);
6963 if (!__mmplayer_add_audio_device_connected_cb(player))
6966 if (!__mmplayer_is_audio_offload_device_type(player))
6969 LOGD("audio offload can be built");
6977 static GstAutoplugSelectResult
6978 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6980 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6982 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6983 int audio_offload = 0;
6985 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6986 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6988 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6989 LOGD("expose audio path to build offload output path");
6990 player->build_audio_offload = TRUE;
6991 /* update codec info */
6992 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6993 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6994 player->audiodec_linked = 1;
6996 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7000 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
7002 LOGD("audio codec type: %d", codec_type);
7003 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7004 /* sw codec will be skipped */
7005 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
7006 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
7007 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
7008 ret = GST_AUTOPLUG_SELECT_SKIP;
7012 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7013 /* hw codec will be skipped */
7014 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7015 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7016 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7017 ret = GST_AUTOPLUG_SELECT_SKIP;
7022 /* set stream information */
7023 if (!player->audiodec_linked)
7024 __mmplayer_set_audio_attrs(player, caps);
7026 /* update codec info */
7027 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7028 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7029 player->audiodec_linked = 1;
7031 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7033 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7035 LOGD("video codec type: %d", codec_type);
7036 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7037 /* sw codec is skipped */
7038 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7039 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7040 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7041 ret = GST_AUTOPLUG_SELECT_SKIP;
7045 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7046 /* hw codec is skipped */
7047 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7048 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7049 ret = GST_AUTOPLUG_SELECT_SKIP;
7054 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7055 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7057 /* mark video decoder for acquire */
7058 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7059 LOGW("video decoder resource is already acquired, skip it.");
7060 ret = GST_AUTOPLUG_SELECT_SKIP;
7064 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7065 LOGE("failed to acquire video decoder resource");
7066 ret = GST_AUTOPLUG_SELECT_SKIP;
7069 player->interrupted_by_resource = FALSE;
7072 /* update codec info */
7073 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7074 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7075 player->videodec_linked = 1;
7083 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7084 GstCaps *caps, GstElementFactory *factory, gpointer data)
7086 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7087 mmplayer_t *player = (mmplayer_t *)data;
7089 gchar *factory_name = NULL;
7090 gchar *caps_str = NULL;
7091 const gchar *klass = NULL;
7094 factory_name = GST_OBJECT_NAME(factory);
7095 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7096 caps_str = gst_caps_to_string(caps);
7098 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7100 /* store type string */
7101 if (player->type == NULL) {
7102 player->type = gst_caps_to_string(caps);
7103 __mmplayer_update_content_type_info(player);
7106 /* filtering exclude keyword */
7107 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7108 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7109 LOGW("skipping [%s] by exculde keyword [%s]",
7110 factory_name, player->ini.exclude_element_keyword[idx]);
7112 result = GST_AUTOPLUG_SELECT_SKIP;
7117 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7118 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7119 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7120 factory_name, player->ini.unsupported_codec_keyword[idx]);
7121 result = GST_AUTOPLUG_SELECT_SKIP;
7126 /* exclude webm format */
7127 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7128 * because webm format is not supportable.
7129 * If webm is disabled in "autoplug-continue", there is no state change
7130 * failure or error because the decodebin will expose the pad directly.
7131 * It make MSL invoke _prepare_async_callback.
7132 * So, we need to disable webm format in "autoplug-select" */
7133 if (caps_str && strstr(caps_str, "webm")) {
7134 LOGW("webm is not supported");
7135 result = GST_AUTOPLUG_SELECT_SKIP;
7139 /* check factory class for filtering */
7140 /* NOTE : msl don't need to use image plugins.
7141 * So, those plugins should be skipped for error handling.
7143 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7144 LOGD("skipping [%s] by not required", factory_name);
7145 result = GST_AUTOPLUG_SELECT_SKIP;
7149 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7150 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7151 // TO CHECK : subtitle if needed, add subparse exception.
7152 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7153 result = GST_AUTOPLUG_SELECT_SKIP;
7157 if (g_strrstr(factory_name, "mpegpsdemux")) {
7158 LOGD("skipping PS container - not support");
7159 result = GST_AUTOPLUG_SELECT_SKIP;
7163 if (g_strrstr(factory_name, "mssdemux"))
7164 player->smooth_streaming = TRUE;
7166 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7167 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7170 GstStructure *str = NULL;
7171 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7173 /* don't make video because of not required */
7174 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7175 (!player->set_mode.video_export)) {
7176 LOGD("no need video decoding, expose pad");
7177 result = GST_AUTOPLUG_SELECT_EXPOSE;
7181 /* get w/h for omx state-tune */
7182 /* FIXME: deprecated? */
7183 str = gst_caps_get_structure(caps, 0);
7184 gst_structure_get_int(str, "width", &width);
7187 if (player->v_stream_caps) {
7188 gst_caps_unref(player->v_stream_caps);
7189 player->v_stream_caps = NULL;
7192 player->v_stream_caps = gst_caps_copy(caps);
7193 LOGD("take caps for video state tune");
7194 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7198 if (g_strrstr(klass, "Codec/Decoder")) {
7199 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7200 if (result != GST_AUTOPLUG_SELECT_TRY) {
7201 LOGW("skip add decoder");
7207 MMPLAYER_FREEIF(caps_str);
7213 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7216 //mmplayer_t *player = (mmplayer_t *)data;
7217 GstCaps *caps = NULL;
7219 LOGD("[Decodebin2] pad-removed signal");
7221 caps = gst_pad_query_caps(new_pad, NULL);
7223 LOGW("query caps is NULL");
7227 gchar *caps_str = NULL;
7228 caps_str = gst_caps_to_string(caps);
7230 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7232 MMPLAYER_FREEIF(caps_str);
7233 gst_caps_unref(caps);
7237 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7239 mmplayer_t *player = (mmplayer_t *)data;
7240 GstIterator *iter = NULL;
7241 GValue item = { 0, };
7243 gboolean done = FALSE;
7244 gboolean is_all_drained = TRUE;
7247 MMPLAYER_RETURN_IF_FAIL(player);
7249 LOGD("got drained signal");
7251 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7252 LOGW("Fail to get cmd lock");
7256 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7257 !__mmplayer_verify_gapless_play_path(player)) {
7258 LOGD("decoding is finished.");
7259 __mmplayer_reset_gapless_state(player);
7260 MMPLAYER_CMD_UNLOCK(player);
7264 player->gapless.reconfigure = TRUE;
7266 /* check decodebin src pads whether they received EOS or not */
7267 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7270 switch (gst_iterator_next(iter, &item)) {
7271 case GST_ITERATOR_OK:
7272 pad = g_value_get_object(&item);
7273 if (pad && !GST_PAD_IS_EOS(pad)) {
7274 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7275 is_all_drained = FALSE;
7278 g_value_reset(&item);
7280 case GST_ITERATOR_RESYNC:
7281 gst_iterator_resync(iter);
7283 case GST_ITERATOR_ERROR:
7284 case GST_ITERATOR_DONE:
7289 g_value_unset(&item);
7290 gst_iterator_free(iter);
7292 if (!is_all_drained) {
7293 LOGD("Wait util the all pads get EOS.");
7294 MMPLAYER_CMD_UNLOCK(player);
7299 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7300 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7302 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7303 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7304 __mmplayer_deactivate_old_path(player);
7305 MMPLAYER_CMD_UNLOCK(player);
7311 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7313 mmplayer_t *player = (mmplayer_t *)data;
7314 const gchar *klass = NULL;
7315 gchar *factory_name = NULL;
7317 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7318 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7320 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7322 if (__mmplayer_add_dump_buffer_probe(player, element))
7323 LOGD("add buffer probe");
7325 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7326 gchar *selected = NULL;
7327 selected = g_strdup(GST_ELEMENT_NAME(element));
7328 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7331 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7332 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7333 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7335 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7336 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7338 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7339 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7340 "max-video-width", player->adaptive_info.limit.width,
7341 "max-video-height", player->adaptive_info.limit.height, NULL);
7343 } else if (g_strrstr(klass, "Demuxer")) {
7344 //LOGD("plugged element is demuxer. take it");
7345 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7346 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7349 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7350 int surface_type = 0;
7352 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7355 // to support trust-zone only
7356 if (g_strrstr(factory_name, "asfdemux")) {
7357 LOGD("set file-location %s", player->profile.uri);
7358 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7359 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7360 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7361 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7362 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7363 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7364 (__mmplayer_is_only_mp3_type(player->type))) {
7365 LOGD("[mpegaudioparse] set streaming pull mode.");
7366 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7368 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7369 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7372 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7373 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7374 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7376 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7377 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7379 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7380 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7381 (MMPLAYER_IS_DASH_STREAMING(player))) {
7382 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7383 _mm_player_streaming_set_multiqueue(player->streamer, element);
7384 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7393 __mmplayer_release_misc(mmplayer_t *player)
7396 bool cur_mode = player->set_mode.rich_audio;
7399 MMPLAYER_RETURN_IF_FAIL(player);
7401 player->video_decoded_cb = NULL;
7402 player->video_decoded_cb_user_param = NULL;
7403 player->video_stream_prerolled = false;
7405 player->audio_decoded_cb = NULL;
7406 player->audio_decoded_cb_user_param = NULL;
7407 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7409 player->audio_stream_changed_cb = NULL;
7410 player->audio_stream_changed_cb_user_param = NULL;
7412 player->sent_bos = FALSE;
7413 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7415 player->seek_state = MMPLAYER_SEEK_NONE;
7417 player->total_bitrate = 0;
7418 player->total_maximum_bitrate = 0;
7420 player->not_found_demuxer = 0;
7422 player->last_position = 0;
7423 player->duration = 0;
7424 player->http_content_size = 0;
7425 player->not_supported_codec = MISSING_PLUGIN_NONE;
7426 player->can_support_codec = FOUND_PLUGIN_NONE;
7427 player->pending_seek.is_pending = false;
7428 player->pending_seek.pos = 0;
7429 player->msg_posted = FALSE;
7430 player->has_many_types = FALSE;
7431 player->is_subtitle_force_drop = FALSE;
7432 player->play_subtitle = FALSE;
7433 player->adjust_subtitle_pos = 0;
7434 player->has_closed_caption = FALSE;
7435 player->set_mode.video_export = false;
7436 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7437 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7439 player->set_mode.rich_audio = cur_mode;
7441 if (player->audio_device_cb_id > 0 &&
7442 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7443 LOGW("failed to remove audio device_connected_callback");
7444 player->audio_device_cb_id = 0;
7446 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7447 player->bitrate[i] = 0;
7448 player->maximum_bitrate[i] = 0;
7451 /* free memory related to audio effect */
7452 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7454 if (player->adaptive_info.var_list) {
7455 g_list_free_full(player->adaptive_info.var_list, g_free);
7456 player->adaptive_info.var_list = NULL;
7459 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7460 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7461 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7463 /* Reset video360 settings to their defaults in case if the pipeline is to be
7466 player->video360_metadata.is_spherical = -1;
7467 player->is_openal_plugin_used = FALSE;
7469 player->is_content_spherical = FALSE;
7470 player->is_video360_enabled = TRUE;
7471 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7472 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7473 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7474 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7475 player->video360_zoom = 1.0f;
7476 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7477 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7479 player->sound.rg_enable = false;
7481 __mmplayer_initialize_video_roi(player);
7486 __mmplayer_release_misc_post(mmplayer_t *player)
7488 char *original_uri = NULL;
7491 /* player->pipeline is already released before. */
7493 MMPLAYER_RETURN_IF_FAIL(player);
7495 mm_attrs_set_int_by_name(player->attrs, "content_video_found", 0);
7497 /* clean found audio decoders */
7498 if (player->audio_decoders) {
7499 GList *a_dec = player->audio_decoders;
7500 for (; a_dec; a_dec = g_list_next(a_dec)) {
7501 gchar *name = a_dec->data;
7502 MMPLAYER_FREEIF(name);
7504 g_list_free(player->audio_decoders);
7505 player->audio_decoders = NULL;
7508 /* clean the uri list except original uri */
7509 if (player->uri_info.uri_list) {
7510 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7512 if (player->attrs) {
7513 mm_attrs_set_string_by_name(player->attrs, "profile_uri", original_uri);
7514 LOGD("restore original uri = %s", original_uri);
7516 if (mm_attrs_commit_all(player->attrs))
7517 LOGE("failed to commit the original uri.");
7520 GList *uri_list = player->uri_info.uri_list;
7521 for (; uri_list; uri_list = g_list_next(uri_list)) {
7522 gchar *uri = uri_list->data;
7523 MMPLAYER_FREEIF(uri);
7525 g_list_free(player->uri_info.uri_list);
7526 player->uri_info.uri_list = NULL;
7529 /* clear the audio stream buffer list */
7530 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7532 /* clear the video stream bo list */
7533 __mmplayer_video_stream_destroy_bo_list(player);
7534 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7536 if (player->profile.input_mem.buf) {
7537 free(player->profile.input_mem.buf);
7538 player->profile.input_mem.buf = NULL;
7540 player->profile.input_mem.len = 0;
7541 player->profile.input_mem.offset = 0;
7543 player->uri_info.uri_idx = 0;
7548 __mmplayer_check_subtitle(mmplayer_t *player)
7550 MMHandleType attrs = 0;
7551 char *subtitle_uri = NULL;
7555 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7557 /* get subtitle attribute */
7558 attrs = MMPLAYER_GET_ATTRS(player);
7562 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7563 if (!subtitle_uri || !strlen(subtitle_uri))
7566 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7567 player->is_external_subtitle_present = TRUE;
7575 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7577 MMPLAYER_RETURN_IF_FAIL(player);
7579 if (player->eos_timer) {
7580 LOGD("cancel eos timer");
7581 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7582 player->eos_timer = 0;
7589 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7593 MMPLAYER_RETURN_IF_FAIL(player);
7594 MMPLAYER_RETURN_IF_FAIL(sink);
7596 player->sink_elements = g_list_append(player->sink_elements, sink);
7602 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7606 MMPLAYER_RETURN_IF_FAIL(player);
7607 MMPLAYER_RETURN_IF_FAIL(sink);
7609 player->sink_elements = g_list_remove(player->sink_elements, sink);
7615 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7616 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7618 mmplayer_signal_item_t *item = NULL;
7621 MMPLAYER_RETURN_IF_FAIL(player);
7623 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7624 LOGE("invalid signal type [%d]", type);
7628 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7630 LOGE("cannot connect signal [%s]", signal);
7635 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7636 player->signals[type] = g_list_append(player->signals[type], item);
7642 /* NOTE : be careful with calling this api. please refer to below glib comment
7643 * glib comment : Note that there is a bug in GObject that makes this function much
7644 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7645 * will no longer be called, but, the signal handler is not currently disconnected.
7646 * If the instance is itself being freed at the same time than this doesn't matter,
7647 * since the signal will automatically be removed, but if instance persists,
7648 * then the signal handler will leak. You should not remove the signal yourself
7649 * because in a future versions of GObject, the handler will automatically be
7652 * It's possible to work around this problem in a way that will continue to work
7653 * with future versions of GObject by checking that the signal handler is still
7654 * connected before disconnected it:
7656 * if (g_signal_handler_is_connected(instance, id))
7657 * g_signal_handler_disconnect(instance, id);
7660 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7662 GList *sig_list = NULL;
7663 mmplayer_signal_item_t *item = NULL;
7667 MMPLAYER_RETURN_IF_FAIL(player);
7669 LOGD("release signals type : %d", type);
7671 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7672 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7673 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7674 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7675 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7676 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7680 sig_list = player->signals[type];
7682 for (; sig_list; sig_list = sig_list->next) {
7683 item = sig_list->data;
7685 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7686 if (g_signal_handler_is_connected(item->obj, item->sig))
7687 g_signal_handler_disconnect(item->obj, item->sig);
7690 MMPLAYER_FREEIF(item);
7693 g_list_free(player->signals[type]);
7694 player->signals[type] = NULL;
7702 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7704 mmplayer_t *player = 0;
7705 int prev_display_surface_type = 0;
7706 void *prev_display_overlay = NULL;
7710 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7711 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7713 player = MM_PLAYER_CAST(handle);
7715 /* check video sinkbin is created */
7716 if (__mmplayer_video_param_check_video_sink_bin(player) == MM_ERROR_NONE) {
7717 LOGE("Videosink is already created");
7718 return MM_ERROR_NONE;
7721 LOGD("videosink element is not yet ready");
7723 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7724 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7726 return MM_ERROR_INVALID_ARGUMENT;
7729 /* load previous attributes */
7730 if (player->attrs) {
7731 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7732 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7733 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7734 if (prev_display_surface_type == surface_type) {
7735 LOGD("incoming display surface type is same as previous one, do nothing..");
7737 return MM_ERROR_NONE;
7740 LOGE("failed to load attributes");
7742 return MM_ERROR_PLAYER_INTERNAL;
7745 /* videobin is not created yet, so we just set attributes related to display surface */
7746 LOGD("store display attribute for given surface type(%d)", surface_type);
7747 mm_attrs_set_int_by_name(player->attrs, "display_surface_type", surface_type);
7748 mm_attrs_set_data_by_name(player->attrs, "display_overlay", display_overlay, sizeof(display_overlay));
7749 if (mm_attrs_commit_all(player->attrs)) {
7750 LOGE("failed to commit attribute");
7752 return MM_ERROR_PLAYER_INTERNAL;
7756 return MM_ERROR_NONE;
7759 /* Note : if silent is true, then subtitle would not be displayed. :*/
7761 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7763 mmplayer_t *player = (mmplayer_t *)hplayer;
7767 /* check player handle */
7768 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7770 player->set_mode.subtitle_off = silent;
7772 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7776 return MM_ERROR_NONE;
7780 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7782 mmplayer_gst_element_t *mainbin = NULL;
7783 mmplayer_gst_element_t *textbin = NULL;
7784 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7785 GstState current_state = GST_STATE_VOID_PENDING;
7786 GstState element_state = GST_STATE_VOID_PENDING;
7787 GstState element_pending_state = GST_STATE_VOID_PENDING;
7789 GstEvent *event = NULL;
7790 int result = MM_ERROR_NONE;
7792 GstClock *curr_clock = NULL;
7793 GstClockTime base_time, start_time, curr_time;
7798 /* check player handle */
7799 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7801 player->pipeline->mainbin &&
7802 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7804 mainbin = player->pipeline->mainbin;
7805 textbin = player->pipeline->textbin;
7807 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7809 // sync clock with current pipeline
7810 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7811 curr_time = gst_clock_get_time(curr_clock);
7813 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7814 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7816 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7817 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7819 if (current_state > GST_STATE_READY) {
7820 // sync state with current pipeline
7821 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7822 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7823 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7825 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7826 if (GST_STATE_CHANGE_FAILURE == ret) {
7827 LOGE("fail to state change.");
7828 result = MM_ERROR_PLAYER_INTERNAL;
7832 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7833 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7836 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7837 gst_object_unref(curr_clock);
7840 // seek to current position
7841 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7842 result = MM_ERROR_PLAYER_INVALID_STATE;
7843 LOGE("gst_element_query_position failed, invalid state");
7847 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7848 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
7850 _mmplayer_gst_send_event_to_sink(player, event);
7852 result = MM_ERROR_PLAYER_INTERNAL;
7853 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7857 /* sync state with current pipeline */
7858 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7859 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7860 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7862 return MM_ERROR_NONE;
7865 /* release text pipeline resource */
7866 player->textsink_linked = 0;
7868 /* release signal */
7869 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7871 /* release textbin with it's childs */
7872 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7873 MMPLAYER_FREEIF(player->pipeline->textbin);
7874 player->pipeline->textbin = NULL;
7876 /* release subtitle elem */
7877 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7878 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7884 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7886 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7887 GstState current_state = GST_STATE_VOID_PENDING;
7889 MMHandleType attrs = 0;
7890 mmplayer_gst_element_t *mainbin = NULL;
7891 mmplayer_gst_element_t *textbin = NULL;
7893 gchar *subtitle_uri = NULL;
7894 int result = MM_ERROR_NONE;
7895 const gchar *charset = NULL;
7899 /* check player handle */
7900 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7902 player->pipeline->mainbin &&
7903 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7904 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7906 mainbin = player->pipeline->mainbin;
7907 textbin = player->pipeline->textbin;
7909 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7910 if (current_state < GST_STATE_READY) {
7911 result = MM_ERROR_PLAYER_INVALID_STATE;
7912 LOGE("Pipeline is not in proper state");
7916 attrs = MMPLAYER_GET_ATTRS(player);
7918 LOGE("cannot get content attribute");
7919 result = MM_ERROR_PLAYER_INTERNAL;
7923 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7924 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7925 LOGE("subtitle uri is not proper filepath");
7926 result = MM_ERROR_PLAYER_INVALID_URI;
7930 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7931 LOGE("failed to get storage info of subtitle path");
7932 result = MM_ERROR_PLAYER_INVALID_URI;
7936 LOGD("old subtitle file path is [%s]", subtitle_uri);
7937 LOGD("new subtitle file path is [%s]", filepath);
7939 if (!strcmp(filepath, subtitle_uri)) {
7940 LOGD("No need to swtich subtitle, as input filepath is same as current filepath");
7943 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
7944 if (mm_attrs_commit_all(player->attrs)) {
7945 LOGE("failed to commit.");
7950 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7951 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7952 player->subtitle_language_list = NULL;
7953 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7955 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7956 if (ret != GST_STATE_CHANGE_SUCCESS) {
7957 LOGE("failed to change state of textbin to READY");
7958 result = MM_ERROR_PLAYER_INTERNAL;
7962 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7963 if (ret != GST_STATE_CHANGE_SUCCESS) {
7964 LOGE("failed to change state of subparse to READY");
7965 result = MM_ERROR_PLAYER_INTERNAL;
7969 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7970 if (ret != GST_STATE_CHANGE_SUCCESS) {
7971 LOGE("failed to change state of filesrc to READY");
7972 result = MM_ERROR_PLAYER_INTERNAL;
7976 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7978 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7980 charset = _mmplayer_get_charset(filepath);
7982 LOGD("detected charset is %s", charset);
7983 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7986 result = _mmplayer_sync_subtitle_pipeline(player);
7993 /* API to switch between external subtitles */
7995 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7997 int result = MM_ERROR_NONE;
7998 mmplayer_t *player = (mmplayer_t *)hplayer;
8003 /* check player handle */
8004 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8006 /* filepath can be null in idle state */
8008 /* check file path */
8009 if ((path = strstr(filepath, "file://")))
8010 result = _mmplayer_exist_file_path(path + 7);
8012 result = _mmplayer_exist_file_path(filepath);
8014 if (result != MM_ERROR_NONE) {
8015 LOGE("invalid subtitle path 0x%X", result);
8016 return result; /* file not found or permission denied */
8020 if (!player->pipeline) {
8022 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8023 if (mm_attrs_commit_all(player->attrs)) {
8024 LOGE("failed to commit"); /* subtitle path will not be created */
8025 return MM_ERROR_PLAYER_INTERNAL;
8028 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8029 /* check filepath */
8030 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8032 if (!__mmplayer_check_subtitle(player)) {
8033 mm_attrs_set_string_by_name(player->attrs, "subtitle_uri", filepath);
8034 if (mm_attrs_commit_all(player->attrs)) {
8035 LOGE("failed to commit");
8036 return MM_ERROR_PLAYER_INTERNAL;
8039 if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player)) {
8040 LOGE("fail to create text pipeline");
8041 return MM_ERROR_PLAYER_INTERNAL;
8044 result = _mmplayer_sync_subtitle_pipeline(player);
8046 result = __mmplayer_change_external_subtitle_language(player, filepath);
8049 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8050 player->is_external_subtitle_added_now = TRUE;
8052 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8053 if (!player->subtitle_language_list) {
8054 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8055 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8056 LOGW("subtitle language list is not updated yet");
8058 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8066 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8068 int result = MM_ERROR_NONE;
8069 gchar *change_pad_name = NULL;
8070 GstPad *sinkpad = NULL;
8071 mmplayer_gst_element_t *mainbin = NULL;
8072 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8073 GstCaps *caps = NULL;
8074 gint total_track_num = 0;
8078 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8079 MM_ERROR_PLAYER_NOT_INITIALIZED);
8081 LOGD("Change Track(%d) to %d", type, index);
8083 mainbin = player->pipeline->mainbin;
8085 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8086 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8087 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8088 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8090 /* Changing Video Track is not supported. */
8091 LOGE("Track Type Error");
8095 if (mainbin[elem_idx].gst == NULL) {
8096 result = MM_ERROR_PLAYER_NO_OP;
8097 LOGD("Req track doesn't exist");
8101 total_track_num = player->selector[type].total_track_num;
8102 if (total_track_num <= 0) {
8103 result = MM_ERROR_PLAYER_NO_OP;
8104 LOGD("Language list is not available");
8108 if ((index < 0) || (index >= total_track_num)) {
8109 result = MM_ERROR_INVALID_ARGUMENT;
8110 LOGD("Not a proper index : %d", index);
8114 /*To get the new pad from the selector*/
8115 change_pad_name = g_strdup_printf("sink_%u", index);
8116 if (change_pad_name == NULL) {
8117 result = MM_ERROR_PLAYER_INTERNAL;
8118 LOGD("Pad does not exists");
8122 LOGD("new active pad name: %s", change_pad_name);
8124 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8125 if (sinkpad == NULL) {
8126 LOGD("sinkpad is NULL");
8127 result = MM_ERROR_PLAYER_INTERNAL;
8131 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8132 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8134 caps = gst_pad_get_current_caps(sinkpad);
8135 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8138 gst_object_unref(sinkpad);
8140 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8141 __mmplayer_set_audio_attrs(player, caps);
8144 MMPLAYER_FREEIF(change_pad_name);
8149 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8151 int result = MM_ERROR_NONE;
8152 mmplayer_t *player = NULL;
8153 mmplayer_gst_element_t *mainbin = NULL;
8155 gint current_active_index = 0;
8157 GstState current_state = GST_STATE_VOID_PENDING;
8158 GstEvent *event = NULL;
8163 player = (mmplayer_t *)hplayer;
8164 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8166 if (!player->pipeline) {
8167 LOGE("Track %d pre setting -> %d", type, index);
8169 player->selector[type].active_pad_index = index;
8173 mainbin = player->pipeline->mainbin;
8175 current_active_index = player->selector[type].active_pad_index;
8177 /*If index is same as running index no need to change the pad*/
8178 if (current_active_index == index)
8181 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8182 result = MM_ERROR_PLAYER_INVALID_STATE;
8186 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8187 if (current_state < GST_STATE_PAUSED) {
8188 result = MM_ERROR_PLAYER_INVALID_STATE;
8189 LOGW("Pipeline not in porper state");
8193 result = __mmplayer_change_selector_pad(player, type, index);
8194 if (result != MM_ERROR_NONE) {
8195 LOGE("change selector pad error");
8199 player->selector[type].active_pad_index = index;
8201 if (current_state == GST_STATE_PLAYING) {
8202 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8203 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8204 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8206 _mmplayer_gst_send_event_to_sink(player, event);
8208 result = MM_ERROR_PLAYER_INTERNAL;
8218 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8220 mmplayer_t *player = (mmplayer_t *)hplayer;
8224 /* check player handle */
8225 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8227 *silent = player->set_mode.subtitle_off;
8229 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8233 return MM_ERROR_NONE;
8237 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8239 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8240 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8242 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8243 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8247 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8248 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8249 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8250 mmplayer_dump_t *dump_s;
8251 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8252 if (dump_s == NULL) {
8253 LOGE("malloc fail");
8257 dump_s->dump_element_file = NULL;
8258 dump_s->dump_pad = NULL;
8259 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8261 if (dump_s->dump_pad) {
8262 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8263 snprintf(dump_file_name, PLAYER_INI_MAX_STRLEN * 2, "%s/%s_sink_pad.dump", player->ini.dump_element_path, player->ini.dump_element_keyword[idx]);
8264 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8265 dump_s->probe_handle_id = gst_pad_add_probe(dump_s->dump_pad, GST_PAD_PROBE_TYPE_BUFFER, __mmplayer_dump_buffer_probe_cb, dump_s->dump_element_file, NULL);
8266 /* add list for removed buffer probe and close FILE */
8267 player->dump_list = g_list_append(player->dump_list, dump_s);
8268 LOGD("%s sink pad added buffer probe for dump", factory_name);
8271 MMPLAYER_FREEIF(dump_s);
8272 LOGE("failed to get %s sink pad added", factory_name);
8279 static GstPadProbeReturn
8280 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8282 FILE *dump_data = (FILE *)u_data;
8284 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8285 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8287 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8289 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8291 // LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8293 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8295 gst_buffer_unmap(buffer, &probe_info);
8297 return GST_PAD_PROBE_OK;
8301 __mmplayer_release_dump_list(GList *dump_list)
8303 GList *d_list = dump_list;
8308 for (; d_list; d_list = g_list_next(d_list)) {
8309 mmplayer_dump_t *dump_s = d_list->data;
8310 if (dump_s->dump_pad) {
8311 if (dump_s->probe_handle_id)
8312 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8313 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8315 if (dump_s->dump_element_file) {
8316 fclose(dump_s->dump_element_file);
8317 dump_s->dump_element_file = NULL;
8319 MMPLAYER_FREEIF(dump_s);
8321 g_list_free(dump_list);
8326 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8328 mmplayer_t *player = (mmplayer_t *)hplayer;
8332 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8333 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8335 *exist = (bool)player->has_closed_caption;
8339 return MM_ERROR_NONE;
8343 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8347 // LOGD("unref internal gst buffer %p", buffer);
8348 gst_buffer_unref((GstBuffer *)buffer);
8355 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8357 mmplayer_t *player = (mmplayer_t *)hplayer;
8361 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8362 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8364 if (MMPLAYER_IS_STREAMING(player))
8365 *timeout = (int)player->ini.live_state_change_timeout;
8367 *timeout = (int)player->ini.localplayback_state_change_timeout;
8369 LOGD("timeout = %d", *timeout);
8372 return MM_ERROR_NONE;
8376 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8380 MMPLAYER_RETURN_IF_FAIL(player);
8382 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8384 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8385 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8386 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8387 player->storage_info[i].id = -1;
8388 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8390 if (path_type != MMPLAYER_PATH_MAX)
8399 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8401 int ret = MM_ERROR_NONE;
8402 mmplayer_t *player = (mmplayer_t *)hplayer;
8403 MMMessageParamType msg_param = {0, };
8406 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8408 LOGW("state changed storage %d:%d", id, state);
8410 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8411 return MM_ERROR_NONE;
8413 /* FIXME: text path should be handled seperately. */
8414 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8415 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8416 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8417 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8418 LOGW("external storage is removed");
8420 if (player->msg_posted == FALSE) {
8421 memset(&msg_param, 0, sizeof(MMMessageParamType));
8422 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8423 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8424 player->msg_posted = TRUE;
8427 /* unrealize the player */
8428 ret = _mmplayer_unrealize(hplayer);
8429 if (ret != MM_ERROR_NONE)
8430 LOGE("failed to unrealize");
8438 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8440 int ret = MM_ERROR_NONE;
8441 mmplayer_t *player = (mmplayer_t *)hplayer;
8442 int idx = 0, total = 0;
8443 gchar *result = NULL, *tmp = NULL;
8446 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8447 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8449 total = *num = g_list_length(player->adaptive_info.var_list);
8451 LOGW("There is no stream variant info.");
8455 result = g_strdup("");
8456 for (idx = 0 ; idx < total ; idx++) {
8457 stream_variant_t *v_data = NULL;
8458 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8461 gchar data[64] = {0};
8462 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8464 tmp = g_strconcat(result, data, NULL);
8468 LOGW("There is no variant data in %d", idx);
8473 *var_info = (char *)result;
8475 LOGD("variant info %d:%s", *num, *var_info);
8481 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8483 int ret = MM_ERROR_NONE;
8484 mmplayer_t *player = (mmplayer_t *)hplayer;
8487 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8489 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8491 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8492 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8493 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8495 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8496 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8497 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8498 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8500 /* FIXME: seek to current position for applying new variant limitation */
8509 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8511 int ret = MM_ERROR_NONE;
8512 mmplayer_t *player = (mmplayer_t *)hplayer;
8515 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8516 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8518 *bandwidth = player->adaptive_info.limit.bandwidth;
8519 *width = player->adaptive_info.limit.width;
8520 *height = player->adaptive_info.limit.height;
8522 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8529 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8531 int ret = MM_ERROR_NONE;
8532 mmplayer_t *player = (mmplayer_t *)hplayer;
8535 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8536 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8537 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8539 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8541 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8542 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8543 else /* live case */
8544 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8546 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8553 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8555 #define IDX_FIRST_SW_CODEC 0
8556 mmplayer_t *player = (mmplayer_t *)hplayer;
8557 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8558 MMHandleType attrs = 0;
8561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8563 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8564 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8565 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8567 switch (stream_type) {
8568 case MM_PLAYER_STREAM_TYPE_AUDIO:
8569 /* to support audio codec selection, codec info have to be added in ini file as below.
8570 audio codec element hw = xxxx
8571 audio codec element sw = avdec */
8572 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8573 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8574 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8575 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8576 LOGE("There is no audio codec info for codec_type %d", codec_type);
8577 return MM_ERROR_PLAYER_NO_OP;
8580 case MM_PLAYER_STREAM_TYPE_VIDEO:
8581 /* to support video codec selection, codec info have to be added in ini file as below.
8582 video codec element hw = omx
8583 video codec element sw = avdec */
8584 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8585 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8586 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8587 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8588 LOGE("There is no video codec info for codec_type %d", codec_type);
8589 return MM_ERROR_PLAYER_NO_OP;
8593 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8594 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8598 LOGD("update %s codec_type to %d", attr_name, codec_type);
8600 attrs = MMPLAYER_GET_ATTRS(player);
8601 mm_attrs_set_int_by_name(attrs, attr_name, codec_type);
8603 if (mm_attrs_commit_all(player->attrs)) {
8604 LOGE("failed to commit codec_type attributes");
8605 return MM_ERROR_PLAYER_INTERNAL;
8609 return MM_ERROR_NONE;
8613 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8615 mmplayer_t *player = (mmplayer_t *)hplayer;
8616 GstElement *rg_vol_element = NULL;
8620 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8622 player->sound.rg_enable = enabled;
8624 /* just hold rgvolume enable value if pipeline is not ready */
8625 if (!player->pipeline || !player->pipeline->audiobin) {
8626 LOGD("pipeline is not ready. holding rgvolume enable value");
8627 return MM_ERROR_NONE;
8630 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8632 if (!rg_vol_element) {
8633 LOGD("rgvolume element is not created");
8634 return MM_ERROR_PLAYER_INTERNAL;
8638 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8640 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8644 return MM_ERROR_NONE;
8648 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8650 mmplayer_t *player = (mmplayer_t *)hplayer;
8651 GstElement *rg_vol_element = NULL;
8652 gboolean enable = FALSE;
8656 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8657 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8659 /* just hold enable_rg value if pipeline is not ready */
8660 if (!player->pipeline || !player->pipeline->audiobin) {
8661 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8662 *enabled = player->sound.rg_enable;
8663 return MM_ERROR_NONE;
8666 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8668 if (!rg_vol_element) {
8669 LOGD("rgvolume element is not created");
8670 return MM_ERROR_PLAYER_INTERNAL;
8673 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8674 *enabled = (bool)enable;
8678 return MM_ERROR_NONE;
8682 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8684 mmplayer_t *player = (mmplayer_t *)hplayer;
8685 MMHandleType attrs = 0;
8686 void *handle = NULL;
8687 int ret = MM_ERROR_NONE;
8691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8693 attrs = MMPLAYER_GET_ATTRS(player);
8694 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8696 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8698 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8699 return MM_ERROR_PLAYER_INTERNAL;
8702 player->video_roi.scale_x = scale_x;
8703 player->video_roi.scale_y = scale_y;
8704 player->video_roi.scale_width = scale_width;
8705 player->video_roi.scale_height = scale_height;
8707 /* check video sinkbin is created */
8708 if (__mmplayer_video_param_check_video_sink_bin(player) != MM_ERROR_NONE)
8709 return MM_ERROR_NONE;
8711 if (!gst_video_overlay_set_video_roi_area(
8712 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8713 scale_x, scale_y, scale_width, scale_height))
8714 ret = MM_ERROR_PLAYER_INTERNAL;
8716 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8717 scale_x, scale_y, scale_width, scale_height);
8725 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8727 mmplayer_t *player = (mmplayer_t *)hplayer;
8728 int ret = MM_ERROR_NONE;
8732 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8733 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8735 *scale_x = player->video_roi.scale_x;
8736 *scale_y = player->video_roi.scale_y;
8737 *scale_width = player->video_roi.scale_width;
8738 *scale_height = player->video_roi.scale_height;
8740 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8741 *scale_x, *scale_y, *scale_width, *scale_height);
8747 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8749 mmplayer_t* player = (mmplayer_t*)hplayer;
8753 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8755 player->client_pid = pid;
8757 LOGD("client pid[%d] %p", pid, player);
8761 return MM_ERROR_NONE;
8765 __mmplayer_update_duration_value(mmplayer_t *player)
8767 gboolean ret = FALSE;
8768 gint64 dur_nsec = 0;
8769 LOGD("try to update duration");
8771 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8772 player->duration = dur_nsec;
8773 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8777 if (player->duration < 0) {
8778 LOGW("duration is Non-Initialized !!!");
8779 player->duration = 0;
8782 /* update streaming service type */
8783 player->streaming_type = _mmplayer_get_stream_service_type(player);
8785 /* check duration is OK */
8786 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8787 /* FIXIT : find another way to get duration here. */
8788 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8794 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8796 /* update audio params
8797 NOTE : We need original audio params and it can be only obtained from src pad of audio
8798 decoder. Below code only valid when we are not using 'resampler' just before
8799 'audioconverter'. */
8800 GstCaps *caps_a = NULL;
8802 gint samplerate = 0, channels = 0;
8803 GstStructure *p = NULL;
8804 GstElement *aconv = NULL;
8806 LOGD("try to update audio attrs");
8808 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8810 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8811 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8812 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8813 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8815 LOGE("there is no audio converter");
8819 pad = gst_element_get_static_pad(aconv, "sink");
8822 LOGW("failed to get pad from audio converter");
8826 caps_a = gst_pad_get_current_caps(pad);
8828 LOGW("not ready to get audio caps");
8829 gst_object_unref(pad);
8833 p = gst_caps_get_structure(caps_a, 0);
8835 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8837 gst_structure_get_int(p, "rate", &samplerate);
8838 mm_attrs_set_int_by_name(attrs, "content_audio_samplerate", samplerate);
8840 gst_structure_get_int(p, "channels", &channels);
8841 mm_attrs_set_int_by_name(attrs, "content_audio_channels", channels);
8843 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8845 gst_caps_unref(caps_a);
8846 gst_object_unref(pad);
8852 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8854 LOGD("try to update video attrs");
8856 GstCaps *caps_v = NULL;
8860 GstStructure *p = NULL;
8862 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8863 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8865 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8867 LOGD("no videosink sink pad");
8871 caps_v = gst_pad_get_current_caps(pad);
8872 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8873 if (!caps_v && player->v_stream_caps) {
8874 caps_v = player->v_stream_caps;
8875 gst_caps_ref(caps_v);
8879 LOGD("no negitiated caps from videosink");
8880 gst_object_unref(pad);
8884 p = gst_caps_get_structure(caps_v, 0);
8885 gst_structure_get_int(p, "width", &width);
8886 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_WIDTH, width);
8888 gst_structure_get_int(p, "height", &height);
8889 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_HEIGHT, height);
8891 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8893 SECURE_LOGD("width : %d height : %d", width, height);
8895 gst_caps_unref(caps_v);
8896 gst_object_unref(pad);
8899 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_FPS, tmpNu / tmpDe);
8900 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8907 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8909 gboolean ret = FALSE;
8910 guint64 data_size = 0;
8914 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8915 if (!player->duration)
8918 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8919 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8920 if (stat(path, &sb) == 0)
8921 data_size = (guint64)sb.st_size;
8923 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8924 data_size = player->http_content_size;
8927 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8930 guint64 bitrate = 0;
8931 guint64 msec_dur = 0;
8933 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8935 bitrate = data_size * 8 * 1000 / msec_dur;
8936 SECURE_LOGD("file size : %"G_GUINT64_FORMAT", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8937 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, bitrate);
8941 LOGD("player duration is less than 0");
8945 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8946 if (player->total_bitrate) {
8947 mm_attrs_set_int_by_name(attrs, MM_PLAYER_VIDEO_BITRATE, player->total_bitrate);
8956 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8958 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8959 data->uri_type = uri_type;
8963 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8965 int ret = MM_ERROR_PLAYER_INVALID_URI;
8967 char *buffer = NULL;
8968 char *seperator = strchr(path, ',');
8969 char ext[100] = {0,}, size[100] = {0,};
8972 if ((buffer = strstr(path, "ext="))) {
8973 buffer += strlen("ext=");
8975 if (strlen(buffer)) {
8976 strncpy(ext, buffer, 99);
8978 if ((seperator = strchr(ext, ','))
8979 || (seperator = strchr(ext, ' '))
8980 || (seperator = strchr(ext, '\0'))) {
8981 seperator[0] = '\0';
8986 if ((buffer = strstr(path, "size="))) {
8987 buffer += strlen("size=");
8989 if (strlen(buffer) > 0) {
8990 strncpy(size, buffer, 99);
8992 if ((seperator = strchr(size, ','))
8993 || (seperator = strchr(size, ' '))
8994 || (seperator = strchr(size, '\0'))) {
8995 seperator[0] = '\0';
8998 mem_size = atoi(size);
9003 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9005 if (mem_size && param) {
9006 if (data->input_mem.buf)
9007 free(data->input_mem.buf);
9008 data->input_mem.buf = malloc(mem_size);
9010 if (data->input_mem.buf) {
9011 memcpy(data->input_mem.buf, param, mem_size);
9012 data->input_mem.len = mem_size;
9013 ret = MM_ERROR_NONE;
9015 LOGE("failed to alloc mem %d", mem_size);
9016 ret = MM_ERROR_PLAYER_INTERNAL;
9019 data->input_mem.offset = 0;
9020 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9027 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9029 gchar *location = NULL;
9032 int ret = MM_ERROR_NONE;
9034 if ((path = strstr(uri, "file://"))) {
9035 location = g_filename_from_uri(uri, NULL, &err);
9036 if (!location || (err != NULL)) {
9037 LOGE("Invalid URI '%s' for filesrc: %s", path,
9038 (err != NULL) ? err->message : "unknown error");
9042 MMPLAYER_FREEIF(location);
9044 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9045 return MM_ERROR_PLAYER_INVALID_URI;
9047 LOGD("path from uri: %s", location);
9050 path = (location != NULL) ? (location) : ((char *)uri);
9053 ret = _mmplayer_exist_file_path(path);
9055 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9056 if (ret == MM_ERROR_NONE) {
9057 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9058 if (_mmplayer_is_sdp_file(path)) {
9059 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9060 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9062 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9064 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9065 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9067 LOGE("invalid uri, could not play..");
9068 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9071 MMPLAYER_FREEIF(location);
9076 static mmplayer_video_decoded_data_info_t *
9077 __mmplayer_create_stream_from_pad(GstPad *pad)
9079 GstCaps *caps = NULL;
9080 GstStructure *structure = NULL;
9081 unsigned int fourcc = 0;
9082 const gchar *string_format = NULL;
9083 mmplayer_video_decoded_data_info_t *stream = NULL;
9085 MMPixelFormatType format;
9088 caps = gst_pad_get_current_caps(pad);
9090 LOGE("Caps is NULL.");
9094 /* MMPLAYER_LOG_GST_CAPS_TYPE(caps); */
9095 structure = gst_caps_get_structure(caps, 0);
9096 gst_structure_get_int(structure, "width", &width);
9097 gst_structure_get_int(structure, "height", &height);
9098 string_format = gst_structure_get_string(structure, "format");
9101 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9102 format = _mmplayer_get_pixtype(fourcc);
9103 gst_video_info_from_caps(&info, caps);
9104 gst_caps_unref(caps);
9107 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9108 LOGE("Wrong condition!!");
9112 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9114 LOGE("failed to alloc mem for video data");
9118 stream->width = width;
9119 stream->height = height;
9120 stream->format = format;
9121 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9127 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9129 unsigned int pitch = 0;
9130 unsigned int size = 0;
9132 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9135 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9136 bo = gst_tizen_memory_get_bos(mem, index);
9138 stream->bo[index] = tbm_bo_ref(bo);
9140 LOGE("failed to get bo for index %d", index);
9143 for (index = 0; index < stream->plane_num; index++) {
9144 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9145 stream->stride[index] = pitch;
9147 stream->elevation[index] = size / pitch;
9149 stream->elevation[index] = stream->height;
9154 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9156 if (stream->format == MM_PIXEL_FORMAT_I420) {
9157 int ret = TBM_SURFACE_ERROR_NONE;
9158 tbm_surface_h surface;
9159 tbm_surface_info_s info;
9161 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9163 ret = tbm_surface_get_info(surface, &info);
9164 if (ret != TBM_SURFACE_ERROR_NONE) {
9165 tbm_surface_destroy(surface);
9169 tbm_surface_destroy(surface);
9170 stream->stride[0] = info.planes[0].stride;
9171 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9172 stream->stride[1] = info.planes[1].stride;
9173 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9174 stream->stride[2] = info.planes[2].stride;
9175 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9176 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9177 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9178 stream->stride[0] = stream->width * 4;
9179 stream->elevation[0] = stream->height;
9180 stream->bo_size = stream->stride[0] * stream->height;
9182 LOGE("Not support format %d", stream->format);
9190 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9192 tbm_bo_handle thandle;
9194 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9195 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9196 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9200 unsigned char *src = NULL;
9201 unsigned char *dest = NULL;
9202 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9204 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9206 LOGE("fail to gst_memory_map");
9210 if (!mapinfo.data) {
9211 LOGE("data pointer is wrong");
9215 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9216 if (!stream->bo[0]) {
9217 LOGE("Fail to tbm_bo_alloc!!");
9221 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9223 LOGE("thandle pointer is wrong");
9227 if (stream->format == MM_PIXEL_FORMAT_I420) {
9228 src_stride[0] = GST_ROUND_UP_4(stream->width);
9229 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9230 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9231 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9234 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9235 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9237 for (i = 0; i < 3; i++) {
9238 src = mapinfo.data + src_offset[i];
9239 dest = thandle.ptr + dest_offset[i];
9244 for (j = 0; j < stream->height >> k; j++) {
9245 memcpy(dest, src, stream->width>>k);
9246 src += src_stride[i];
9247 dest += stream->stride[i];
9250 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9251 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9253 LOGE("Not support format %d", stream->format);
9257 tbm_bo_unmap(stream->bo[0]);
9258 gst_memory_unmap(mem, &mapinfo);
9264 tbm_bo_unmap(stream->bo[0]);
9267 gst_memory_unmap(mem, &mapinfo);
9273 __mmplayer_set_pause_state(mmplayer_t *player)
9275 if (player->sent_bos)
9278 /* rtsp case, get content attrs by GstMessage */
9279 if (MMPLAYER_IS_RTSP_STREAMING(player))
9282 /* it's first time to update all content attrs. */
9283 _mmplayer_update_content_attrs(player, ATTR_ALL);
9287 __mmplayer_set_playing_state(mmplayer_t *player)
9289 gchar *audio_codec = NULL;
9291 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9292 /* initialize because auto resume is done well. */
9293 player->resumed_by_rewind = FALSE;
9294 player->playback_rate = 1.0;
9297 if (player->sent_bos)
9300 /* try to get content metadata */
9302 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9303 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9304 * legacy mmfw-player api
9306 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9308 if ((player->cmd == MMPLAYER_COMMAND_START)
9309 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9310 __mmplayer_handle_missed_plugin(player);
9313 /* check audio codec field is set or not
9314 * we can get it from typefinder or codec's caps.
9316 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9318 /* The codec format can't be sent for audio only case like amr, mid etc.
9319 * Because, parser don't make related TAG.
9320 * So, if it's not set yet, fill it with found data.
9323 if (g_strrstr(player->type, "audio/midi"))
9324 audio_codec = "MIDI";
9325 else if (g_strrstr(player->type, "audio/x-amr"))
9326 audio_codec = "AMR";
9327 else if (g_strrstr(player->type, "audio/mpeg")
9328 && !g_strrstr(player->type, "mpegversion=(int)1"))
9329 audio_codec = "AAC";
9331 audio_codec = "unknown";
9333 mm_attrs_set_string_by_name(player->attrs, "content_audio_codec", audio_codec);
9335 if (mm_attrs_commit_all(player->attrs))
9336 LOGE("failed to update attributes");
9338 LOGD("set audio codec type with caps");