4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
212 /* This function should be called after the pipeline goes PAUSED or higher
215 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
217 static gboolean has_duration = FALSE;
218 static gboolean has_video_attrs = FALSE;
219 static gboolean has_audio_attrs = FALSE;
220 static gboolean has_bitrate = FALSE;
221 gboolean missing_only = FALSE;
222 gboolean all = FALSE;
223 MMHandleType attrs = 0;
227 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
229 /* check player state here */
230 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
231 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
232 /* give warning now only */
233 LOGW("be careful. content attributes may not available in this state ");
236 /* get content attribute first */
237 attrs = MMPLAYER_GET_ATTRS(player);
239 LOGE("cannot get content attribute");
243 /* get update flag */
245 if (flag & ATTR_MISSING_ONLY) {
247 LOGD("updating missed attr only");
250 if (flag & ATTR_ALL) {
252 has_duration = FALSE;
253 has_video_attrs = FALSE;
254 has_audio_attrs = FALSE;
257 LOGD("updating all attrs");
260 if (missing_only && all) {
261 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
262 missing_only = FALSE;
265 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
266 has_duration = __mmplayer_update_duration_value(player);
268 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
269 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
271 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
272 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
274 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
275 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
283 _mmplayer_get_stream_service_type(mmplayer_t *player)
285 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
289 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
291 player->pipeline->mainbin &&
292 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
293 STREAMING_SERVICE_NONE);
295 /* streaming service type if streaming */
296 if (!MMPLAYER_IS_STREAMING(player))
297 return STREAMING_SERVICE_NONE;
299 streaming_type = (player->duration == 0) ?
300 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
302 switch (streaming_type) {
303 case STREAMING_SERVICE_LIVE:
304 LOGD("it's live streaming");
306 case STREAMING_SERVICE_VOD:
307 LOGD("it's vod streaming");
310 LOGE("should not get here");
316 return streaming_type;
319 /* this function sets the player state and also report
320 * it to applicaton by calling callback function
323 _mmplayer_set_state(mmplayer_t *player, int state)
325 MMMessageParamType msg = {0, };
327 MMPLAYER_RETURN_IF_FAIL(player);
329 if (MMPLAYER_CURRENT_STATE(player) == state) {
330 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
331 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
335 /* update player states */
336 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
337 MMPLAYER_CURRENT_STATE(player) = state;
339 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
340 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
343 MMPLAYER_PRINT_STATE(player);
345 switch (MMPLAYER_CURRENT_STATE(player)) {
346 case MM_PLAYER_STATE_NULL:
347 case MM_PLAYER_STATE_READY:
349 case MM_PLAYER_STATE_PAUSED:
350 __mmplayer_set_pause_state(player);
352 case MM_PLAYER_STATE_PLAYING:
353 __mmplayer_set_playing_state(player);
355 case MM_PLAYER_STATE_NONE:
357 LOGW("invalid target state, there is nothing to do.");
362 /* post message to application */
363 if (MMPLAYER_TARGET_STATE(player) == state) {
364 /* fill the message with state of player */
365 msg.union_type = MM_MSG_UNION_STATE;
366 msg.state.previous = MMPLAYER_PREV_STATE(player);
367 msg.state.current = MMPLAYER_CURRENT_STATE(player);
369 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
371 /* state changed by resource callback */
372 if (player->interrupted_by_resource)
373 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
374 else /* state changed by usecase */
375 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
378 LOGD("intermediate state, do nothing.");
379 MMPLAYER_PRINT_STATE(player);
383 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
384 && !player->sent_bos) {
385 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
386 player->sent_bos = TRUE;
393 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
395 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
396 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
398 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
400 LOGD("incomming command : %d ", command);
402 current_state = MMPLAYER_CURRENT_STATE(player);
403 pending_state = MMPLAYER_PENDING_STATE(player);
405 MMPLAYER_PRINT_STATE(player);
408 case MMPLAYER_COMMAND_CREATE:
410 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
412 if (current_state == MM_PLAYER_STATE_NULL ||
413 current_state == MM_PLAYER_STATE_READY ||
414 current_state == MM_PLAYER_STATE_PAUSED ||
415 current_state == MM_PLAYER_STATE_PLAYING)
420 case MMPLAYER_COMMAND_DESTROY:
422 /* destroy can called anytime */
424 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
428 case MMPLAYER_COMMAND_REALIZE:
430 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
432 if (pending_state != MM_PLAYER_STATE_NONE) {
435 /* need ready state to realize */
436 if (current_state == MM_PLAYER_STATE_READY)
439 if (current_state != MM_PLAYER_STATE_NULL)
445 case MMPLAYER_COMMAND_UNREALIZE:
447 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
449 if (current_state == MM_PLAYER_STATE_NULL)
454 case MMPLAYER_COMMAND_START:
456 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
458 if (pending_state == MM_PLAYER_STATE_NONE) {
459 if (current_state == MM_PLAYER_STATE_PLAYING)
461 else if (current_state != MM_PLAYER_STATE_READY &&
462 current_state != MM_PLAYER_STATE_PAUSED)
464 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
466 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
467 LOGD("player is going to paused state, just change the pending state as playing");
474 case MMPLAYER_COMMAND_STOP:
476 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
478 if (current_state == MM_PLAYER_STATE_READY)
481 /* need playing/paused state to stop */
482 if (current_state != MM_PLAYER_STATE_PLAYING &&
483 current_state != MM_PLAYER_STATE_PAUSED)
488 case MMPLAYER_COMMAND_PAUSE:
490 if (MMPLAYER_IS_LIVE_STREAMING(player))
493 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
494 goto NOT_COMPLETED_SEEK;
496 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
498 if (pending_state == MM_PLAYER_STATE_NONE) {
499 if (current_state == MM_PLAYER_STATE_PAUSED)
501 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
503 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
505 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
506 if (current_state == MM_PLAYER_STATE_PAUSED)
507 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
514 case MMPLAYER_COMMAND_RESUME:
516 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
517 goto NOT_COMPLETED_SEEK;
519 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
521 if (pending_state == MM_PLAYER_STATE_NONE) {
522 if (current_state == MM_PLAYER_STATE_PLAYING)
524 else if (current_state != MM_PLAYER_STATE_PAUSED)
526 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
528 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
529 LOGD("player is going to paused state, just change the pending state as playing");
539 player->cmd = command;
541 return MM_ERROR_NONE;
544 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
545 MMPLAYER_STATE_GET_NAME(current_state), command);
546 return MM_ERROR_PLAYER_INVALID_STATE;
549 LOGW("not completed seek");
550 return MM_ERROR_PLAYER_DOING_SEEK;
553 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
554 return MM_ERROR_PLAYER_NO_OP;
557 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
558 return MM_ERROR_PLAYER_NO_OP;
561 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
563 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
564 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
567 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
568 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
570 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
571 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
573 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
574 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
577 LOGE("invalid mmplayer resource type %d", type);
578 return MM_ERROR_PLAYER_INTERNAL;
581 if (player->hw_resource[type] != NULL) {
582 LOGD("[%d type] resource was already acquired", type);
583 return MM_ERROR_NONE;
586 LOGD("mark for acquire [%d type] resource", type);
587 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
588 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
589 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
590 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
591 return MM_ERROR_PLAYER_INTERNAL;
594 rm_ret = mm_resource_manager_commit(player->resource_manager);
595 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
596 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
597 return MM_ERROR_PLAYER_INTERNAL;
601 return MM_ERROR_NONE;
604 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
606 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
610 if (player->hw_resource[type] == NULL) {
611 LOGD("there is no acquired [%d type] resource", type);
612 return MM_ERROR_NONE;
615 LOGD("mark for release [%d type] resource", type);
616 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
617 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
618 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
619 return MM_ERROR_PLAYER_INTERNAL;
622 player->hw_resource[type] = NULL;
624 rm_ret = mm_resource_manager_commit(player->resource_manager);
625 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
626 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
627 return MM_ERROR_PLAYER_INTERNAL;
631 return MM_ERROR_NONE;
635 __mmplayer_initialize_gapless_play(mmplayer_t *player)
641 player->smooth_streaming = FALSE;
642 player->videodec_linked = 0;
643 player->audiodec_linked = 0;
644 player->textsink_linked = 0;
645 player->is_external_subtitle_present = FALSE;
646 player->is_external_subtitle_added_now = FALSE;
647 player->not_supported_codec = MISSING_PLUGIN_NONE;
648 player->can_support_codec = FOUND_PLUGIN_NONE;
649 player->pending_seek.is_pending = false;
650 player->pending_seek.pos = 0;
651 player->msg_posted = FALSE;
652 player->has_many_types = FALSE;
653 player->no_more_pad = FALSE;
654 player->not_found_demuxer = 0;
655 player->seek_state = MMPLAYER_SEEK_NONE;
656 player->is_subtitle_force_drop = FALSE;
657 player->play_subtitle = FALSE;
658 player->adjust_subtitle_pos = 0;
660 player->total_bitrate = 0;
661 player->total_maximum_bitrate = 0;
663 _mmplayer_track_initialize(player);
664 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
666 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
667 player->bitrate[i] = 0;
668 player->maximum_bitrate[i] = 0;
671 if (player->v_stream_caps) {
672 gst_caps_unref(player->v_stream_caps);
673 player->v_stream_caps = NULL;
676 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
678 /* clean found audio decoders */
679 if (player->audio_decoders) {
680 GList *a_dec = player->audio_decoders;
681 for (; a_dec; a_dec = g_list_next(a_dec)) {
682 gchar *name = a_dec->data;
683 MMPLAYER_FREEIF(name);
685 g_list_free(player->audio_decoders);
686 player->audio_decoders = NULL;
689 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
695 __mmplayer_gapless_play_thread(gpointer data)
697 mmplayer_t *player = (mmplayer_t *)data;
698 mmplayer_gst_element_t *mainbin = NULL;
700 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
702 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
703 while (!player->gapless_play_thread_exit) {
704 LOGD("gapless play thread started. waiting for signal.");
705 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
707 LOGD("reconfigure pipeline for gapless play.");
709 if (player->gapless_play_thread_exit) {
710 if (player->gapless.reconfigure) {
711 player->gapless.reconfigure = false;
712 MMPLAYER_PLAYBACK_UNLOCK(player);
714 LOGD("exiting gapless play thread");
718 mainbin = player->pipeline->mainbin;
720 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
721 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
722 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
723 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
724 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
726 /* Initialize Player values */
727 __mmplayer_initialize_gapless_play(player);
729 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
731 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
737 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
739 GSource *source = NULL;
743 source = g_main_context_find_source_by_id(context, source_id);
744 if (source != NULL) {
745 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
746 g_source_destroy(source);
753 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
755 mmplayer_t *player = (mmplayer_t *)hplayer;
756 GstMessage *msg = NULL;
757 GQueue *queue = NULL;
760 MMPLAYER_RETURN_IF_FAIL(player);
762 /* disconnecting bus watch */
763 if (player->bus_watcher)
764 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
765 player->bus_watcher = 0;
767 /* destroy the gst bus msg thread */
768 if (player->bus_msg_thread) {
769 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
770 player->bus_msg_thread_exit = TRUE;
771 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
772 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
774 LOGD("gst bus msg thread exit.");
775 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
776 player->bus_msg_thread = NULL;
778 g_mutex_clear(&player->bus_msg_thread_mutex);
779 g_cond_clear(&player->bus_msg_thread_cond);
782 g_mutex_lock(&player->bus_msg_q_lock);
783 queue = player->bus_msg_q;
784 while (!g_queue_is_empty(queue)) {
785 msg = (GstMessage *)g_queue_pop_head(queue);
790 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
791 gst_message_unref(msg);
793 g_mutex_unlock(&player->bus_msg_q_lock);
799 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
801 GstElement *parent = NULL;
803 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
804 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
807 MMPLAYER_FSINK_LOCK(player);
809 /* get parent of fakesink */
810 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
812 LOGD("fakesink already removed");
816 gst_element_set_locked_state(fakesink->gst, TRUE);
818 /* setting the state to NULL never returns async
819 * so no need to wait for completion of state transiton
821 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
822 LOGE("fakesink state change failure!");
823 /* FIXIT : should I return here? or try to proceed to next? */
826 /* remove fakesink from it's parent */
827 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
828 LOGE("failed to remove fakesink");
830 gst_object_unref(parent);
835 gst_object_unref(parent);
837 LOGD("state-holder removed");
839 gst_element_set_locked_state(fakesink->gst, FALSE);
841 MMPLAYER_FSINK_UNLOCK(player);
846 gst_element_set_locked_state(fakesink->gst, FALSE);
848 MMPLAYER_FSINK_UNLOCK(player);
852 static GstPadProbeReturn
853 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
855 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
856 return GST_PAD_PROBE_OK;
860 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
862 gint64 stop_running_time = 0;
863 gint64 position_running_time = 0;
867 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
868 if ((player->gapless.update_segment[idx] == TRUE) ||
869 !(player->selector[idx].event_probe_id)) {
871 LOGW("[%d] skip", idx);
876 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
878 gst_segment_to_running_time(&player->gapless.segment[idx],
879 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
880 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
882 gst_segment_to_running_time(&player->gapless.segment[idx],
883 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
885 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
887 gst_segment_to_running_time(&player->gapless.segment[idx],
888 GST_FORMAT_TIME, player->duration);
891 position_running_time =
892 gst_segment_to_running_time(&player->gapless.segment[idx],
893 GST_FORMAT_TIME, player->gapless.segment[idx].position);
895 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
896 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
898 GST_TIME_ARGS(stop_running_time),
899 GST_TIME_ARGS(position_running_time),
900 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
901 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
903 position_running_time = MAX(position_running_time, stop_running_time);
904 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
905 GST_FORMAT_TIME, player->gapless.segment[idx].start);
906 position_running_time = MAX(0, position_running_time);
907 position = MAX(position, position_running_time);
911 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
912 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
913 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
915 player->gapless.start_time[stream_type] += position;
921 static GstPadProbeReturn
922 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
924 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
925 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
926 mmplayer_t *player = (mmplayer_t *)data;
927 GstCaps *caps = NULL;
928 GstStructure *str = NULL;
929 const gchar *name = NULL;
930 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
931 gboolean caps_ret = TRUE;
933 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
934 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
935 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
936 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
937 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
940 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
944 if (strstr(name, "audio")) {
945 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
946 } else if (strstr(name, "video")) {
947 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
949 /* text track is not supportable */
950 LOGE("invalid name %s", name);
954 switch (GST_EVENT_TYPE(event)) {
957 /* in case of gapless, drop eos event not to send it to sink */
958 if (player->gapless.reconfigure && !player->msg_posted) {
959 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
960 ret = GST_PAD_PROBE_DROP;
964 case GST_EVENT_STREAM_START:
966 __mmplayer_gst_selector_update_start_time(player, stream_type);
969 case GST_EVENT_FLUSH_STOP:
971 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
972 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
973 player->gapless.start_time[stream_type] = 0;
976 case GST_EVENT_SEGMENT:
981 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
982 gst_event_copy_segment(event, &segment);
984 if (segment.format != GST_FORMAT_TIME)
987 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
988 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
989 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
990 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
991 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
992 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
994 /* keep the all the segment ev to cover the seeking */
995 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
996 player->gapless.update_segment[stream_type] = TRUE;
998 if (!player->gapless.running)
1001 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1003 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1005 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1006 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1007 gst_event_unref(event);
1008 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1014 gdouble proportion = 0.0;
1015 GstClockTimeDiff diff = 0;
1016 GstClockTime timestamp = 0;
1017 gint64 running_time_diff = -1;
1018 GstQOSType type = 0;
1019 GstEvent *tmpev = NULL;
1021 running_time_diff = player->gapless.segment[stream_type].base;
1023 if (running_time_diff <= 0) /* don't need to adjust */
1026 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1027 gst_event_unref(event);
1029 if (timestamp < running_time_diff) {
1030 LOGW("QOS event from previous group");
1031 ret = GST_PAD_PROBE_DROP;
1036 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1037 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1038 stream_type, GST_TIME_ARGS(timestamp),
1039 GST_TIME_ARGS(running_time_diff),
1040 GST_TIME_ARGS(timestamp - running_time_diff));
1043 timestamp -= running_time_diff;
1045 /* That case is invalid for QoS events */
1046 if (diff < 0 && -diff > timestamp) {
1047 LOGW("QOS event from previous group");
1048 ret = GST_PAD_PROBE_DROP;
1052 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1053 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1063 gst_caps_unref(caps);
1067 /* create fakesink for audio or video path witout audiobin or videobin */
1069 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1071 GstElement *pipeline = NULL;
1072 GstElement *fakesink = NULL;
1073 GstPad *sinkpad = NULL;
1076 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1078 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1081 fakesink = gst_element_factory_make("fakesink", NULL);
1082 if (fakesink == NULL) {
1083 LOGE("failed to create fakesink");
1087 /* store it as it's sink element */
1088 __mmplayer_add_sink(player, fakesink);
1090 gst_bin_add(GST_BIN(pipeline), fakesink);
1093 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1095 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1097 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1098 LOGE("failed to link fakesink");
1099 gst_object_unref(GST_OBJECT(fakesink));
1103 if (strstr(name, "video")) {
1104 if (player->v_stream_caps) {
1105 gst_caps_unref(player->v_stream_caps);
1106 player->v_stream_caps = NULL;
1108 if (player->ini.set_dump_element_flag)
1109 __mmplayer_add_dump_buffer_probe(player, fakesink);
1112 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1113 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1117 gst_object_unref(GST_OBJECT(sinkpad));
1124 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1126 GstElement *pipeline = NULL;
1127 GstElement *selector = NULL;
1128 GstPad *srcpad = NULL;
1131 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1133 selector = gst_element_factory_make("input-selector", NULL);
1135 LOGE("failed to create input-selector");
1138 g_object_set(selector, "sync-streams", TRUE, NULL);
1140 player->pipeline->mainbin[elem_idx].id = elem_idx;
1141 player->pipeline->mainbin[elem_idx].gst = selector;
1143 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1145 srcpad = gst_element_get_static_pad(selector, "src");
1147 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1148 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1149 __mmplayer_gst_selector_blocked, NULL, NULL);
1150 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1151 __mmplayer_gst_selector_event_probe, player, NULL);
1153 gst_element_set_state(selector, GST_STATE_PAUSED);
1155 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1156 gst_bin_add(GST_BIN(pipeline), selector);
1158 gst_object_unref(GST_OBJECT(srcpad));
1165 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1167 mmplayer_t *player = (mmplayer_t *)data;
1168 GstElement *selector = NULL;
1169 GstCaps *caps = NULL;
1170 GstStructure *str = NULL;
1171 const gchar *name = NULL;
1172 GstPad *sinkpad = NULL;
1173 gboolean first_track = FALSE;
1174 gboolean caps_ret = TRUE;
1176 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1177 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1180 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1181 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1183 LOGD("pad-added signal handling");
1185 /* get mimetype from caps */
1186 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1190 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1192 LOGD("detected mimetype : %s", name);
1195 if (strstr(name, "video")) {
1197 gchar *caps_str = NULL;
1199 caps_str = gst_caps_to_string(caps);
1200 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1201 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1202 player->set_mode.video_zc = true;
1204 MMPLAYER_FREEIF(caps_str);
1206 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1207 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1209 LOGD("surface type : %d", stype);
1211 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1212 __mmplayer_gst_create_sinkbin(elem, pad, player);
1216 /* in case of exporting video frame, it requires the 360 video filter.
1217 * it will be handled in _no_more_pads(). */
1218 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1219 __mmplayer_gst_make_fakesink(player, pad, name);
1223 LOGD("video selector is required");
1224 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1225 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1226 } else if (strstr(name, "audio")) {
1227 gint samplerate = 0;
1230 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1231 if (player->build_audio_offload)
1232 player->no_more_pad = TRUE; /* remove state holder */
1233 __mmplayer_gst_create_sinkbin(elem, pad, player);
1237 gst_structure_get_int(str, "rate", &samplerate);
1238 gst_structure_get_int(str, "channels", &channels);
1240 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1241 __mmplayer_gst_make_fakesink(player, pad, name);
1245 LOGD("audio selector is required");
1246 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1247 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1249 } else if (strstr(name, "text")) {
1250 LOGD("text selector is required");
1251 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1252 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1254 LOGE("invalid caps info");
1258 /* check selector and create it */
1259 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1260 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1265 LOGD("input-selector is already created.");
1269 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1271 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1273 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1274 LOGE("failed to link selector");
1275 gst_object_unref(GST_OBJECT(selector));
1280 LOGD("this track will be activated");
1281 g_object_set(selector, "active-pad", sinkpad, NULL);
1284 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1290 gst_caps_unref(caps);
1293 gst_object_unref(GST_OBJECT(sinkpad));
1301 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1303 GstPad *srcpad = NULL;
1306 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1308 LOGD("type %d", type);
1311 LOGD("there is no %d track", type);
1315 srcpad = gst_element_get_static_pad(selector, "src");
1317 LOGE("failed to get srcpad from selector");
1321 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1323 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1325 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1326 if (player->selector[type].block_id) {
1327 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1328 player->selector[type].block_id = 0;
1332 gst_object_unref(GST_OBJECT(srcpad));
1341 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1343 gint active_index = 0;
1346 MMPLAYER_RETURN_IF_FAIL(player);
1348 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1350 /* change track to active pad */
1351 active_index = player->selector[type].active_pad_index;
1352 if ((active_index != DEFAULT_TRACK) &&
1353 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1354 LOGW("failed to change %d type track to %d", type, active_index);
1355 player->selector[type].active_pad_index = DEFAULT_TRACK;
1359 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1360 mm_player_set_attribute((MMHandleType)player, NULL,
1361 "content_text_track_num", player->selector[type].total_track_num,
1362 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1369 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1372 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1374 if (!audio_selector) {
1375 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1377 /* in case the source is changed, output can be changed. */
1378 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1379 LOGD("remove previous audiobin if it exist");
1381 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1382 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1384 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1385 MMPLAYER_FREEIF(player->pipeline->audiobin);
1388 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1389 __mmplayer_pipeline_complete(NULL, player);
1394 /* apply the audio track information */
1395 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1397 /* create audio sink path */
1398 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1399 LOGE("failed to create audio sink path");
1408 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1411 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1413 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1414 LOGD("text path is not supproted");
1418 /* apply the text track information */
1419 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1421 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1422 player->has_closed_caption = TRUE;
1424 /* create text decode path */
1425 player->no_more_pad = TRUE;
1427 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1428 LOGE("failed to create text sink path");
1437 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1439 gint64 dur_bytes = 0L;
1442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1443 player->pipeline->mainbin && player->streamer, FALSE);
1445 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1446 LOGE("fail to get duration.");
1448 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1449 * use file information was already set on Q2 when it was created. */
1450 _mm_player_streaming_set_queue2(player->streamer,
1451 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1452 TRUE, /* use_buffering */
1453 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1454 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1461 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1463 mmplayer_t *player = NULL;
1464 GstElement *video_selector = NULL;
1465 GstElement *audio_selector = NULL;
1466 GstElement *text_selector = NULL;
1469 player = (mmplayer_t *)data;
1471 LOGD("no-more-pad signal handling");
1473 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1474 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1475 LOGW("player is shutting down");
1479 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1480 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1481 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1482 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1483 LOGE("failed to set queue2 buffering");
1488 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1489 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1490 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1492 if (!video_selector && !audio_selector && !text_selector) {
1493 LOGW("there is no selector");
1494 player->no_more_pad = TRUE;
1498 /* create video path followed by video-select */
1499 if (video_selector && !audio_selector && !text_selector)
1500 player->no_more_pad = TRUE;
1502 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1505 /* create audio path followed by audio-select */
1506 if (audio_selector && !text_selector)
1507 player->no_more_pad = TRUE;
1509 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1512 /* create text path followed by text-select */
1513 __mmplayer_create_text_sink_path(player, text_selector);
1516 if (player->gapless.reconfigure) {
1517 player->gapless.reconfigure = FALSE;
1518 MMPLAYER_PLAYBACK_UNLOCK(player);
1525 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1527 gboolean ret = FALSE;
1528 GstElement *pipeline = NULL;
1529 GstPad *sinkpad = NULL;
1532 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1533 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1535 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1537 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1539 LOGE("failed to get pad from sinkbin");
1545 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1546 LOGE("failed to link sinkbin for reusing");
1547 goto EXIT; /* exit either pass or fail */
1551 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1552 LOGE("failed to set state(READY) to sinkbin");
1557 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1558 LOGE("failed to add sinkbin to pipeline");
1563 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1564 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1569 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1570 LOGE("failed to set state(PAUSED) to sinkbin");
1579 gst_object_unref(GST_OBJECT(sinkpad));
1587 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1589 mmplayer_t *player = NULL;
1590 GstCaps *caps = NULL;
1591 gchar *caps_str = NULL;
1592 GstStructure *str = NULL;
1593 const gchar *name = NULL;
1594 GstElement *sinkbin = NULL;
1595 gboolean reusing = FALSE;
1596 gboolean caps_ret = TRUE;
1597 gchar *sink_pad_name = "sink";
1600 player = (mmplayer_t *)data;
1603 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1604 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1606 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1610 caps_str = gst_caps_to_string(caps);
1612 LOGD("detected mimetype : %s", name);
1614 if (strstr(name, "audio")) {
1615 if (player->pipeline->audiobin == NULL) {
1616 const gchar *audio_format = gst_structure_get_string(str, "format");
1618 LOGD("original audio format %s", audio_format);
1619 mm_player_set_attribute((MMHandleType)player, NULL,
1620 "content_audio_format", audio_format, strlen(audio_format), NULL);
1623 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1624 LOGE("failed to create audiobin. continuing without audio");
1628 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1629 LOGD("creating audiobin success");
1632 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1633 LOGD("reusing audiobin");
1634 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1636 } else if (strstr(name, "video")) {
1637 /* 1. zero copy is updated at _decode_pad_added()
1638 * 2. NULL surface type is handled in _decode_pad_added() */
1639 LOGD("zero copy %d", player->set_mode.video_zc);
1640 if (player->pipeline->videobin == NULL) {
1641 int surface_type = 0;
1642 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1643 LOGD("display_surface_type (%d)", surface_type);
1645 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1646 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1647 LOGE("failed to acquire video overlay resource");
1651 player->interrupted_by_resource = FALSE;
1653 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1654 LOGE("failed to create videobin. continuing without video");
1658 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1659 LOGD("creating videosink bin success");
1662 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1663 LOGD("re-using videobin");
1664 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1666 } else if (strstr(name, "text")) {
1667 if (player->pipeline->textbin == NULL) {
1668 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1669 LOGE("failed to create text sink bin. continuing without text");
1673 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1674 player->textsink_linked = 1;
1675 LOGD("creating textsink bin success");
1677 if (!player->textsink_linked) {
1678 LOGD("re-using textbin");
1680 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1681 player->textsink_linked = 1;
1683 /* linked textbin exist which means that the external subtitle path exist already */
1684 LOGW("ignoring internal subtutle since external subtitle is available");
1687 sink_pad_name = "text_sink";
1689 LOGW("unknown mime type %s, ignoring it", name);
1693 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1696 LOGD("[handle: %p] success to create and link sink bin", player);
1698 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1699 * streaming task. if the task blocked, then buffer will not flow to the next element
1700 *(autoplugging element). so this is special hack for streaming. please try to remove it
1702 /* dec stream count. we can remove fakesink if it's zero */
1703 if (player->num_dynamic_pad)
1704 player->num_dynamic_pad--;
1706 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1708 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1709 __mmplayer_pipeline_complete(NULL, player);
1713 MMPLAYER_FREEIF(caps_str);
1716 gst_caps_unref(caps);
1722 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1724 int required_angle = 0; /* Angle required for straight view */
1725 int rotation_angle = 0;
1727 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1728 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1730 /* Counter clockwise */
1731 switch (orientation) {
1736 required_angle = 270;
1739 required_angle = 180;
1742 required_angle = 90;
1746 rotation_angle = display_angle + required_angle;
1747 if (rotation_angle >= 360)
1748 rotation_angle -= 360;
1750 /* chech if supported or not */
1751 if (rotation_angle % 90) {
1752 LOGD("not supported rotation angle = %d", rotation_angle);
1756 switch (rotation_angle) {
1758 *value = MM_DISPLAY_ROTATION_NONE;
1761 *value = MM_DISPLAY_ROTATION_90;
1764 *value = MM_DISPLAY_ROTATION_180;
1767 *value = MM_DISPLAY_ROTATION_270;
1771 LOGD("setting rotation property value : %d", *value);
1777 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1779 int display_rotation = 0;
1780 gchar *org_orient = NULL;
1781 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1784 LOGE("cannot get content attribute");
1785 return MM_ERROR_PLAYER_INTERNAL;
1788 if (display_angle) {
1789 /* update user roation */
1790 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1792 /* Counter clockwise */
1793 switch (display_rotation) {
1794 case MM_DISPLAY_ROTATION_NONE:
1797 case MM_DISPLAY_ROTATION_90:
1798 *display_angle = 90;
1800 case MM_DISPLAY_ROTATION_180:
1801 *display_angle = 180;
1803 case MM_DISPLAY_ROTATION_270:
1804 *display_angle = 270;
1807 LOGW("wrong angle type : %d", display_rotation);
1810 LOGD("check user angle: %d", *display_angle);
1814 /* Counter clockwise */
1815 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1818 if (!strcmp(org_orient, "rotate-90"))
1820 else if (!strcmp(org_orient, "rotate-180"))
1822 else if (!strcmp(org_orient, "rotate-270"))
1825 LOGD("original rotation is %s", org_orient);
1827 LOGD("content_video_orientation get fail");
1830 LOGD("check orientation: %d", *orientation);
1833 return MM_ERROR_NONE;
1836 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1838 int rotation_value = 0;
1839 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1840 int display_angle = 0;
1843 /* check video sinkbin is created */
1844 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1847 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1849 /* get rotation value to set */
1850 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1851 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1852 LOGD("set video param : rotate %d", rotation_value);
1855 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1857 MMHandleType attrs = 0;
1861 /* check video sinkbin is created */
1862 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1865 attrs = MMPLAYER_GET_ATTRS(player);
1866 MMPLAYER_RETURN_IF_FAIL(attrs);
1868 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1869 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1870 LOGD("set video param : visible %d", visible);
1873 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1875 MMHandleType attrs = 0;
1876 int display_method = 0;
1879 /* check video sinkbin is created */
1880 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1883 attrs = MMPLAYER_GET_ATTRS(player);
1884 MMPLAYER_RETURN_IF_FAIL(attrs);
1886 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1887 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1888 LOGD("set video param : method %d", display_method);
1891 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1893 MMHandleType attrs = 0;
1897 /* check video sinkbin is created */
1898 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1901 attrs = MMPLAYER_GET_ATTRS(player);
1902 MMPLAYER_RETURN_IF_FAIL(attrs);
1904 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1905 MMPLAYER_RETURN_IF_FAIL(handle);
1907 gst_video_overlay_set_video_roi_area(
1908 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1909 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1910 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1911 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1914 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1916 MMHandleType attrs = 0;
1921 int win_roi_width = 0;
1922 int win_roi_height = 0;
1925 /* check video sinkbin is created */
1926 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1929 attrs = MMPLAYER_GET_ATTRS(player);
1930 MMPLAYER_RETURN_IF_FAIL(attrs);
1932 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1933 MMPLAYER_RETURN_IF_FAIL(handle);
1935 /* It should be set after setting window */
1936 mm_attrs_multiple_get(attrs, NULL,
1937 "display_win_roi_x", &win_roi_x,
1938 "display_win_roi_y", &win_roi_y,
1939 "display_win_roi_width", &win_roi_width,
1940 "display_win_roi_height", &win_roi_height, NULL);
1942 /* After setting window handle, set display roi area */
1943 gst_video_overlay_set_display_roi_area(
1944 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1945 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1946 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1947 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1950 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1952 MMHandleType attrs = 0;
1955 /* check video sinkbin is created */
1956 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1959 attrs = MMPLAYER_GET_ATTRS(player);
1960 MMPLAYER_RETURN_IF_FAIL(attrs);
1962 /* common case if using overlay surface */
1963 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1964 MMPLAYER_RETURN_IF_FAIL(handle);
1966 /* default is using wl_surface_id */
1967 LOGD("set video param : wl_surface_id %d", handle);
1968 gst_video_overlay_set_wl_window_wl_surface_id(
1969 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1974 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1976 gboolean update_all_param = FALSE;
1980 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1981 LOGW("videosink is not ready yet");
1982 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1985 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1986 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1987 return MM_ERROR_PLAYER_INTERNAL;
1990 LOGD("param_name : %s", param_name);
1991 if (!g_strcmp0(param_name, "update_all_param"))
1992 update_all_param = TRUE;
1994 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1995 __mmplayer_video_param_set_display_overlay(player);
1996 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1997 __mmplayer_video_param_set_display_method(player);
1998 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1999 __mmplayer_video_param_set_display_visible(player);
2000 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2001 __mmplayer_video_param_set_display_rotation(player);
2002 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2003 __mmplayer_video_param_set_roi_area(player);
2004 if (update_all_param)
2005 __mmplayer_video_param_set_video_roi_area(player);
2009 return MM_ERROR_NONE;
2013 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2015 gboolean disable_overlay = FALSE;
2016 mmplayer_t *player = (mmplayer_t *)hplayer;
2019 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2020 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2021 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2022 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2024 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2025 LOGW("Display control is not supported");
2026 return MM_ERROR_PLAYER_INTERNAL;
2029 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2031 if (audio_only == (bool)disable_overlay) {
2032 LOGE("It's the same with current setting: (%d)", audio_only);
2033 return MM_ERROR_NONE;
2037 LOGE("disable overlay");
2038 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2040 /* release overlay resource */
2041 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2042 LOGE("failed to release overlay resource");
2046 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2047 LOGE("failed to acquire video overlay resource");
2050 player->interrupted_by_resource = FALSE;
2052 LOGD("enable overlay");
2053 __mmplayer_video_param_set_display_overlay(player);
2054 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2059 return MM_ERROR_NONE;
2063 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2065 mmplayer_t *player = (mmplayer_t *)hplayer;
2066 gboolean disable_overlay = FALSE;
2070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2071 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2072 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2073 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2074 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2076 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2077 LOGW("Display control is not supported");
2078 return MM_ERROR_PLAYER_INTERNAL;
2081 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2083 *paudio_only = (bool)disable_overlay;
2085 LOGD("audio_only : %d", *paudio_only);
2089 return MM_ERROR_NONE;
2093 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2095 GList *bucket = element_bucket;
2096 mmplayer_gst_element_t *element = NULL;
2097 mmplayer_gst_element_t *prv_element = NULL;
2098 GstElement *tee_element = NULL;
2099 gint successful_link_count = 0;
2103 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2105 prv_element = (mmplayer_gst_element_t *)bucket->data;
2106 bucket = bucket->next;
2108 for (; bucket; bucket = bucket->next) {
2109 element = (mmplayer_gst_element_t *)bucket->data;
2111 if (element && element->gst) {
2112 if (prv_element && prv_element->gst) {
2113 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2115 prv_element->gst = tee_element;
2117 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2118 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2119 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2123 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2124 LOGD("linking [%s] to [%s] success",
2125 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2126 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2127 successful_link_count++;
2128 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2129 LOGD("keep audio-tee element for next audio pipeline branch");
2130 tee_element = prv_element->gst;
2133 LOGD("linking [%s] to [%s] failed",
2134 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2135 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2141 prv_element = element;
2146 return successful_link_count;
2150 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2152 GList *bucket = element_bucket;
2153 mmplayer_gst_element_t *element = NULL;
2154 int successful_add_count = 0;
2158 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2159 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2161 for (; bucket; bucket = bucket->next) {
2162 element = (mmplayer_gst_element_t *)bucket->data;
2164 if (element && element->gst) {
2165 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2166 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2167 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2168 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2171 successful_add_count++;
2177 return successful_add_count;
2181 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2183 mmplayer_t *player = (mmplayer_t *)data;
2184 GstCaps *caps = NULL;
2185 GstStructure *str = NULL;
2187 gboolean caps_ret = TRUE;
2191 MMPLAYER_RETURN_IF_FAIL(pad);
2192 MMPLAYER_RETURN_IF_FAIL(unused);
2193 MMPLAYER_RETURN_IF_FAIL(data);
2195 caps = gst_pad_get_current_caps(pad);
2199 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2203 LOGD("name = %s", name);
2205 if (strstr(name, "audio")) {
2206 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2208 if (player->audio_stream_changed_cb) {
2209 LOGE("call the audio stream changed cb");
2210 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2212 } else if (strstr(name, "video")) {
2213 if ((name = gst_structure_get_string(str, "format")))
2214 player->set_mode.video_zc = name[0] == 'S';
2216 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2217 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2219 LOGW("invalid caps info");
2224 gst_caps_unref(caps);
2232 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2237 MMPLAYER_RETURN_IF_FAIL(player);
2239 if (player->audio_stream_buff_list) {
2240 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2241 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2244 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2245 __mmplayer_audio_stream_send_data(player, tmp);
2247 MMPLAYER_FREEIF(tmp->pcm_data);
2248 MMPLAYER_FREEIF(tmp);
2251 g_list_free(player->audio_stream_buff_list);
2252 player->audio_stream_buff_list = NULL;
2259 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2261 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2264 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2266 audio_stream.bitrate = a_buffer->bitrate;
2267 audio_stream.channel = a_buffer->channel;
2268 audio_stream.channel_mask = a_buffer->channel_mask;
2269 audio_stream.data_size = a_buffer->data_size;
2270 audio_stream.data = a_buffer->pcm_data;
2271 audio_stream.pcm_format = a_buffer->pcm_format;
2273 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2275 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2281 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2283 mmplayer_t *player = (mmplayer_t *)data;
2284 const gchar *pcm_format = NULL;
2287 guint64 channel_mask = 0;
2288 void *a_data = NULL;
2290 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2291 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2295 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2297 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2298 a_data = mapinfo.data;
2299 a_size = mapinfo.size;
2301 GstCaps *caps = gst_pad_get_current_caps(pad);
2302 GstStructure *structure = gst_caps_get_structure(caps, 0);
2304 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2306 pcm_format = gst_structure_get_string(structure, "format");
2307 gst_structure_get_int(structure, "rate", &rate);
2308 gst_structure_get_int(structure, "channels", &channel);
2309 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2310 gst_caps_unref(GST_CAPS(caps));
2312 /* In case of the sync is false, use buffer list. *
2313 * The num of buffer list depends on the num of audio channels */
2314 if (player->audio_stream_buff_list) {
2315 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2316 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2318 if (channel_mask == tmp->channel_mask) {
2320 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2322 if (tmp->data_size + a_size < tmp->buff_size) {
2323 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2324 tmp->data_size += a_size;
2326 /* send data to client */
2327 __mmplayer_audio_stream_send_data(player, tmp);
2329 if (a_size > tmp->buff_size) {
2330 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2331 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2332 if (tmp->pcm_data == NULL) {
2333 LOGE("failed to realloc data.");
2336 tmp->buff_size = a_size;
2338 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2339 memcpy(tmp->pcm_data, a_data, a_size);
2340 tmp->data_size = a_size;
2345 LOGE("data is empty in list.");
2351 /* create new audio stream data for newly found audio channel */
2352 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2353 if (a_buffer == NULL) {
2354 LOGE("failed to alloc data.");
2357 a_buffer->bitrate = rate;
2358 a_buffer->channel = channel;
2359 a_buffer->channel_mask = channel_mask;
2360 a_buffer->data_size = a_size;
2361 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2363 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2364 /* If sync is FALSE, use buffer list to reduce the IPC. */
2365 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2366 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2367 if (a_buffer->pcm_data == NULL) {
2368 LOGE("failed to alloc data.");
2369 MMPLAYER_FREEIF(a_buffer);
2372 memcpy(a_buffer->pcm_data, a_data, a_size);
2374 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2376 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2378 /* If sync is TRUE, send data directly. */
2379 a_buffer->pcm_data = a_data;
2380 __mmplayer_audio_stream_send_data(player, a_buffer);
2381 MMPLAYER_FREEIF(a_buffer);
2385 gst_buffer_unmap(buffer, &mapinfo);
2390 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2392 mmplayer_t *player = (mmplayer_t *)data;
2393 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2394 GstPad *sinkpad = NULL;
2395 GstElement *queue = NULL, *sink = NULL;
2398 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2400 queue = gst_element_factory_make("queue", NULL);
2401 if (queue == NULL) {
2402 LOGD("fail make queue");
2406 sink = gst_element_factory_make("fakesink", NULL);
2408 LOGD("fail make fakesink");
2412 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2414 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2415 LOGW("failed to link queue & sink");
2419 sinkpad = gst_element_get_static_pad(queue, "sink");
2421 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2422 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2426 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2428 gst_object_unref(sinkpad);
2429 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2430 g_object_set(sink, "sync", TRUE, NULL);
2431 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2433 /* keep the first sink reference only */
2434 if (!audiobin[MMPLAYER_A_SINK].gst) {
2435 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2436 audiobin[MMPLAYER_A_SINK].gst = sink;
2440 _mmplayer_add_signal_connection(player,
2442 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2444 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2447 __mmplayer_add_sink(player, sink);
2449 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2450 LOGE("failed to sync state");
2454 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2455 LOGE("failed to sync state");
2463 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2465 gst_object_unref(GST_OBJECT(queue));
2469 gst_object_unref(GST_OBJECT(sink));
2473 gst_object_unref(GST_OBJECT(sinkpad));
2481 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2483 mmplayer_t *player = (mmplayer_t *)data;
2486 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2488 player->no_more_pad = TRUE;
2489 __mmplayer_pipeline_complete(NULL, player);
2496 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2498 #define MAX_PROPS_LEN 128
2499 mmplayer_gst_element_t *audiobin = NULL;
2500 gint latency_mode = 0;
2501 gchar *stream_type = NULL;
2502 gchar *latency = NULL;
2504 gchar stream_props[MAX_PROPS_LEN] = {0,};
2505 GstStructure *props = NULL;
2508 * It should be set after player creation through attribute.
2509 * But, it can not be changed during playing.
2512 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2514 audiobin = player->pipeline->audiobin;
2516 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2517 if (player->sound.mute) {
2518 LOGD("mute enabled");
2519 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2522 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2523 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2526 snprintf(stream_props, sizeof(stream_props) - 1,
2527 "props,application.process.id.origin=%d", player->client_pid);
2529 snprintf(stream_props, sizeof(stream_props) - 1,
2530 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2531 stream_type, stream_id, player->client_pid);
2533 props = gst_structure_from_string(stream_props, NULL);
2534 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2535 LOGI("props result[%s].", stream_props);
2536 gst_structure_free(props);
2538 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2540 switch (latency_mode) {
2541 case AUDIO_LATENCY_MODE_LOW:
2542 latency = g_strndup("low", 3);
2544 case AUDIO_LATENCY_MODE_MID:
2545 latency = g_strndup("mid", 3);
2547 case AUDIO_LATENCY_MODE_HIGH:
2548 latency = g_strndup("high", 4);
2552 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2554 LOGD("audiosink property - latency=%s", latency);
2556 MMPLAYER_FREEIF(latency);
2562 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2564 mmplayer_gst_element_t *audiobin = NULL;
2567 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2569 audiobin = player->pipeline->audiobin;
2571 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2572 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2573 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2575 if (player->video360_yaw_radians <= M_PI &&
2576 player->video360_yaw_radians >= -M_PI &&
2577 player->video360_pitch_radians <= M_PI_2 &&
2578 player->video360_pitch_radians >= -M_PI_2) {
2579 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2580 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2581 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2582 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2583 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2584 "source-orientation-y", player->video360_metadata.init_view_heading,
2585 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2592 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2594 mmplayer_gst_element_t *audiobin = NULL;
2595 GstPad *sink_pad = NULL;
2596 GstCaps *acaps = NULL;
2598 int pitch_control = 0;
2599 double pitch_value = 1.0;
2602 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2603 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2605 audiobin = player->pipeline->audiobin;
2607 LOGD("make element for normal audio playback");
2609 /* audio bin structure for playback. {} means optional.
2610 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2612 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2613 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2616 /* for pitch control */
2617 mm_attrs_multiple_get(player->attrs, NULL,
2618 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2619 MM_PLAYER_PITCH_VALUE, &pitch_value,
2622 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2623 if (pitch_control && (player->videodec_linked == 0)) {
2624 GstElementFactory *factory;
2626 factory = gst_element_factory_find("pitch");
2628 gst_object_unref(factory);
2631 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2634 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2635 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2637 LOGW("there is no pitch element");
2642 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2644 /* replaygain volume */
2645 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2646 if (player->sound.rg_enable)
2647 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2649 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2652 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2654 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2655 /* currently, only openalsink uses volume element */
2656 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2659 if (player->sound.mute) {
2660 LOGD("mute enabled");
2661 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2665 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2667 /* audio effect element. if audio effect is enabled */
2668 if ((strcmp(player->ini.audioeffect_element, ""))
2670 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2671 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2673 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2675 if ((!player->bypass_audio_effect)
2676 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2677 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2678 if (!_mmplayer_audio_effect_custom_apply(player))
2679 LOGI("apply audio effect(custom) setting success");
2683 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2684 && (player->set_mode.rich_audio)) {
2685 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2689 /* create audio sink */
2690 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2691 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2692 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2694 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2695 if (player->is_360_feature_enabled &&
2696 player->is_content_spherical &&
2698 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2699 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2700 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2702 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2704 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2706 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2707 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2708 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2709 gst_caps_unref(acaps);
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2713 player->is_openal_plugin_used = TRUE;
2715 if (player->is_360_feature_enabled && player->is_content_spherical)
2716 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2717 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2720 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2721 (player->videodec_linked && player->ini.use_system_clock)) {
2722 LOGD("system clock will be used.");
2723 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2726 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2727 __mmplayer_gst_set_pulsesink_property(player);
2728 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2729 __mmplayer_gst_set_openalsink_property(player);
2732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2735 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2736 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2737 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2738 gst_object_unref(GST_OBJECT(sink_pad));
2740 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2743 return MM_ERROR_NONE;
2745 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2747 return MM_ERROR_PLAYER_INTERNAL;
2751 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2753 mmplayer_gst_element_t *audiobin = NULL;
2754 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2756 gchar *dst_format = NULL;
2758 int dst_samplerate = 0;
2759 int dst_channels = 0;
2760 GstCaps *caps = NULL;
2761 char *caps_str = NULL;
2764 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2765 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2767 audiobin = player->pipeline->audiobin;
2769 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2771 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2773 [case 1] extract interleave audio pcm without playback
2774 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2775 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2777 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2779 [case 2] deinterleave for each channel without playback
2780 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2781 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2783 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2784 - fakesink (sync or not)
2787 [case 3] [case 1(sync only)] + playback
2788 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2790 * src - ... - tee - queue1 - playback path
2791 - queue2 - [case1 pipeline with sync]
2793 [case 4] [case 2(sync only)] + playback
2794 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2796 * src - ... - tee - queue1 - playback path
2797 - queue2 - [case2 pipeline with sync]
2801 /* 1. create tee and playback path
2802 'tee' should be added at first to copy the decoded stream
2804 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2805 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2806 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2808 /* tee - path 1 : for playback path */
2809 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2810 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2812 /* tee - path 2 : for extract path */
2813 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2814 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2817 /* if there is tee, 'tee - path 2' is linked here */
2819 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2822 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2824 /* 2. decide the extract pcm format */
2825 mm_attrs_multiple_get(player->attrs, NULL,
2826 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2827 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2828 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2831 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2832 dst_format, dst_len, dst_samplerate, dst_channels);
2834 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2835 mm_attrs_multiple_get(player->attrs, NULL,
2836 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2837 "content_audio_samplerate", &dst_samplerate,
2838 "content_audio_channels", &dst_channels,
2841 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2842 dst_format, dst_len, dst_samplerate, dst_channels);
2844 /* If there is no enough information, set it to platform default value. */
2845 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2846 LOGD("set platform default format");
2847 dst_format = DEFAULT_PCM_OUT_FORMAT;
2849 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2850 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2853 /* 3. create capsfilter */
2854 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2855 caps = gst_caps_new_simple("audio/x-raw",
2856 "format", G_TYPE_STRING, dst_format,
2857 "rate", G_TYPE_INT, dst_samplerate,
2858 "channels", G_TYPE_INT, dst_channels,
2861 caps_str = gst_caps_to_string(caps);
2862 LOGD("new caps : %s", caps_str);
2864 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2867 gst_caps_unref(caps);
2868 MMPLAYER_FREEIF(caps_str);
2870 /* 4-1. create deinterleave to extract pcm for each channel */
2871 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2872 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2873 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2875 /* audiosink will be added after getting signal for each channel */
2876 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2877 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2878 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2879 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2880 player->no_more_pad = FALSE;
2882 /* 4-2. create fakesink to extract interlevaed pcm */
2883 LOGD("add audio fakesink for interleaved audio");
2884 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2885 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2886 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2887 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2889 _mmplayer_add_signal_connection(player,
2890 G_OBJECT(audiobin[extract_sink_id].gst),
2891 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2893 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2896 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2900 return MM_ERROR_NONE;
2902 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2904 return MM_ERROR_PLAYER_INTERNAL;
2908 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2910 int ret = MM_ERROR_NONE;
2911 mmplayer_gst_element_t *audiobin = NULL;
2912 GList *element_bucket = NULL;
2915 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2916 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2918 audiobin = player->pipeline->audiobin;
2920 if (player->build_audio_offload) { /* skip all the audio filters */
2921 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2923 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2924 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2925 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2927 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2931 /* FIXME: need to mention the supportable condition at API reference */
2932 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2933 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2935 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2937 if (ret != MM_ERROR_NONE)
2940 LOGD("success to make audio bin element");
2941 *bucket = element_bucket;
2944 return MM_ERROR_NONE;
2947 LOGE("failed to make audio bin element");
2948 g_list_free(element_bucket);
2952 return MM_ERROR_PLAYER_INTERNAL;
2956 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2958 mmplayer_gst_element_t *first_element = NULL;
2959 mmplayer_gst_element_t *audiobin = NULL;
2961 GstPad *ghostpad = NULL;
2962 GList *element_bucket = NULL;
2966 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2969 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2971 LOGE("failed to allocate memory for audiobin");
2972 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2976 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2977 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2978 if (!audiobin[MMPLAYER_A_BIN].gst) {
2979 LOGE("failed to create audiobin");
2984 player->pipeline->audiobin = audiobin;
2986 /* create audio filters and audiosink */
2987 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2990 /* adding created elements to bin */
2991 LOGD("adding created elements to bin");
2992 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2995 /* linking elements in the bucket by added order. */
2996 LOGD("Linking elements in the bucket by added order.");
2997 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3000 /* get first element's sinkpad for creating ghostpad */
3001 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3002 if (!first_element) {
3003 LOGE("failed to get first elem");
3007 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3009 LOGE("failed to get pad from first element of audiobin");
3013 ghostpad = gst_ghost_pad_new("sink", pad);
3015 LOGE("failed to create ghostpad");
3019 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3020 LOGE("failed to add ghostpad to audiobin");
3024 gst_object_unref(pad);
3026 g_list_free(element_bucket);
3029 return MM_ERROR_NONE;
3032 LOGD("ERROR : releasing audiobin");
3035 gst_object_unref(GST_OBJECT(pad));
3038 gst_object_unref(GST_OBJECT(ghostpad));
3041 g_list_free(element_bucket);
3043 /* release element which are not added to bin */
3044 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3045 /* NOTE : skip bin */
3046 if (audiobin[i].gst) {
3047 GstObject *parent = NULL;
3048 parent = gst_element_get_parent(audiobin[i].gst);
3051 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3052 audiobin[i].gst = NULL;
3054 gst_object_unref(GST_OBJECT(parent));
3058 /* release audiobin with it's childs */
3059 if (audiobin[MMPLAYER_A_BIN].gst)
3060 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3062 MMPLAYER_FREEIF(audiobin);
3064 player->pipeline->audiobin = NULL;
3066 return MM_ERROR_PLAYER_INTERNAL;
3070 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3072 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3076 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3078 int ret = MM_ERROR_NONE;
3080 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3081 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3083 MMPLAYER_VIDEO_BO_LOCK(player);
3085 if (player->video_bo_list) {
3086 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3087 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3088 if (tmp && tmp->bo == bo) {
3090 LOGD("release bo %p", bo);
3091 tbm_bo_unref(tmp->bo);
3092 MMPLAYER_VIDEO_BO_UNLOCK(player);
3093 MMPLAYER_VIDEO_BO_SIGNAL(player);
3098 /* hw codec is running or the list was reset for DRC. */
3099 LOGW("there is no bo list.");
3101 MMPLAYER_VIDEO_BO_UNLOCK(player);
3103 LOGW("failed to find bo %p", bo);
3108 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3113 MMPLAYER_RETURN_IF_FAIL(player);
3115 MMPLAYER_VIDEO_BO_LOCK(player);
3116 if (player->video_bo_list) {
3117 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3118 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3119 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3122 tbm_bo_unref(tmp->bo);
3126 g_list_free(player->video_bo_list);
3127 player->video_bo_list = NULL;
3129 player->video_bo_size = 0;
3130 MMPLAYER_VIDEO_BO_UNLOCK(player);
3137 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3140 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3141 gboolean ret = TRUE;
3143 /* check DRC, if it is, destroy the prev bo list to create again */
3144 if (player->video_bo_size != size) {
3145 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3146 __mmplayer_video_stream_destroy_bo_list(player);
3147 player->video_bo_size = size;
3150 MMPLAYER_VIDEO_BO_LOCK(player);
3152 if ((!player->video_bo_list) ||
3153 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3155 /* create bo list */
3157 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3159 if (player->video_bo_list) {
3160 /* if bo list did not created all, try it again. */
3161 idx = g_list_length(player->video_bo_list);
3162 LOGD("bo list exist(len: %d)", idx);
3165 for (; idx < player->ini.num_of_video_bo; idx++) {
3166 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3168 LOGE("Fail to alloc bo_info.");
3171 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3173 LOGE("Fail to tbm_bo_alloc.");
3174 MMPLAYER_FREEIF(bo_info);
3177 bo_info->used = FALSE;
3178 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3181 /* update video num buffers */
3182 LOGD("video_num_buffers : %d", idx);
3183 mm_player_set_attribute((MMHandleType)player, NULL,
3184 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3185 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3189 MMPLAYER_VIDEO_BO_UNLOCK(player);
3195 /* get bo from list*/
3196 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3197 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3198 if (tmp && (tmp->used == FALSE)) {
3199 LOGD("found bo %p to use", tmp->bo);
3201 MMPLAYER_VIDEO_BO_UNLOCK(player);
3202 return tbm_bo_ref(tmp->bo);
3206 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3207 MMPLAYER_VIDEO_BO_UNLOCK(player);
3211 if (player->ini.video_bo_timeout <= 0) {
3212 MMPLAYER_VIDEO_BO_WAIT(player);
3214 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3215 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3222 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3224 mmplayer_t *player = (mmplayer_t *)data;
3226 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3228 /* send prerolled pkt */
3229 player->video_stream_prerolled = false;
3231 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3233 /* not to send prerolled pkt again */
3234 player->video_stream_prerolled = true;
3238 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3240 mmplayer_t *player = (mmplayer_t *)data;
3241 mmplayer_video_decoded_data_info_t *stream = NULL;
3242 GstMemory *mem = NULL;
3245 MMPLAYER_RETURN_IF_FAIL(player);
3246 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3248 if (player->video_stream_prerolled) {
3249 player->video_stream_prerolled = false;
3250 LOGD("skip the prerolled pkt not to send it again");
3254 /* clear stream data structure */
3255 stream = __mmplayer_create_stream_from_pad(pad);
3257 LOGE("failed to alloc stream");
3261 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3263 /* set size and timestamp */
3264 mem = gst_buffer_peek_memory(buffer, 0);
3265 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3266 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3268 /* check zero-copy */
3269 if (player->set_mode.video_zc &&
3270 player->set_mode.video_export &&
3271 gst_is_tizen_memory(mem)) {
3272 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3273 stream->internal_buffer = gst_buffer_ref(buffer);
3274 } else { /* sw codec */
3275 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3278 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3282 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3283 LOGE("failed to send video decoded data.");
3290 LOGE("release video stream resource.");
3291 if (gst_is_tizen_memory(mem)) {
3293 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3295 tbm_bo_unref(stream->bo[i]);
3298 /* unref gst buffer */
3299 if (stream->internal_buffer)
3300 gst_buffer_unref(stream->internal_buffer);
3303 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3305 MMPLAYER_FREEIF(stream);
3310 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3312 mmplayer_gst_element_t *videobin = NULL;
3315 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3317 videobin = player->pipeline->videobin;
3319 /* Set spatial media metadata and/or user settings to the element.
3321 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3322 "projection-type", player->video360_metadata.projection_type, NULL);
3324 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3325 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3327 if (player->video360_metadata.full_pano_width_pixels &&
3328 player->video360_metadata.full_pano_height_pixels &&
3329 player->video360_metadata.cropped_area_image_width &&
3330 player->video360_metadata.cropped_area_image_height) {
3331 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3332 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3333 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3334 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3335 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3336 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3337 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3341 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3342 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3343 "horizontal-fov", player->video360_horizontal_fov,
3344 "vertical-fov", player->video360_vertical_fov, NULL);
3347 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3348 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3349 "zoom", 1.0f / player->video360_zoom, NULL);
3352 if (player->video360_yaw_radians <= M_PI &&
3353 player->video360_yaw_radians >= -M_PI &&
3354 player->video360_pitch_radians <= M_PI_2 &&
3355 player->video360_pitch_radians >= -M_PI_2) {
3356 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3357 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3358 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3359 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3360 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3361 "pose-yaw", player->video360_metadata.init_view_heading,
3362 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3365 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3366 "passthrough", !player->is_video360_enabled, NULL);
3373 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3375 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3376 GList *element_bucket = NULL;
3379 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3381 /* create video360 filter */
3382 if (player->is_360_feature_enabled && player->is_content_spherical) {
3383 LOGD("create video360 element");
3384 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3385 __mmplayer_gst_set_video360_property(player);
3389 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3390 LOGD("skip creating the videoconv and rotator");
3391 return MM_ERROR_NONE;
3394 /* in case of sw codec & overlay surface type, except 360 playback.
3395 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3396 LOGD("create video converter: %s", video_csc);
3397 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3400 *bucket = element_bucket;
3402 return MM_ERROR_NONE;
3404 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3405 g_list_free(element_bucket);
3409 return MM_ERROR_PLAYER_INTERNAL;
3413 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3415 gchar *factory_name = NULL;
3417 switch (surface_type) {
3418 case MM_DISPLAY_SURFACE_OVERLAY:
3419 if (strlen(player->ini.videosink_element_overlay) > 0)
3420 factory_name = player->ini.videosink_element_overlay;
3422 case MM_DISPLAY_SURFACE_REMOTE:
3423 case MM_DISPLAY_SURFACE_NULL:
3424 if (strlen(player->ini.videosink_element_fake) > 0)
3425 factory_name = player->ini.videosink_element_fake;
3428 LOGE("unidentified surface type");
3432 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3433 return factory_name;
3437 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3439 gchar *factory_name = NULL;
3440 mmplayer_gst_element_t *videobin = NULL;
3445 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3447 videobin = player->pipeline->videobin;
3448 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3450 attrs = MMPLAYER_GET_ATTRS(player);
3452 LOGE("cannot get content attribute");
3453 return MM_ERROR_PLAYER_INTERNAL;
3456 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3457 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3459 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3460 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3461 "use-tbm", use_tbm, NULL);
3463 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3464 return MM_ERROR_PLAYER_INTERNAL;
3467 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3468 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3470 LOGD("surface type : %d, videosink factory name is %s use-tbm : %d", surface_type, factory_name, use_tbm);
3472 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3474 LOGD("disable last-sample");
3475 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3478 if (player->set_mode.video_export) {
3480 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3481 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3482 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3484 _mmplayer_add_signal_connection(player,
3485 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3486 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3488 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3491 _mmplayer_add_signal_connection(player,
3492 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3493 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3495 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3499 if (videobin[MMPLAYER_V_SINK].gst) {
3500 GstPad *sink_pad = NULL;
3501 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3503 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3504 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3505 gst_object_unref(GST_OBJECT(sink_pad));
3507 LOGE("failed to get sink pad from videosink");
3511 return MM_ERROR_NONE;
3516 * - video overlay surface(arm/x86) : tizenwlsink
3519 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3522 GList *element_bucket = NULL;
3523 mmplayer_gst_element_t *first_element = NULL;
3524 mmplayer_gst_element_t *videobin = NULL;
3525 gchar *videosink_factory_name = NULL;
3528 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3531 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3533 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3535 player->pipeline->videobin = videobin;
3538 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3539 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3540 if (!videobin[MMPLAYER_V_BIN].gst) {
3541 LOGE("failed to create videobin");
3545 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3548 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3549 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3551 /* additional setting for sink plug-in */
3552 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3553 LOGE("failed to set video property");
3557 /* store it as it's sink element */
3558 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3560 /* adding created elements to bin */
3561 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3562 LOGE("failed to add elements");
3566 /* Linking elements in the bucket by added order */
3567 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3568 LOGE("failed to link elements");
3572 /* get first element's sinkpad for creating ghostpad */
3573 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3574 if (!first_element) {
3575 LOGE("failed to get first element from bucket");
3579 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3581 LOGE("failed to get pad from first element");
3585 /* create ghostpad */
3586 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3587 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3588 LOGE("failed to add ghostpad to videobin");
3591 gst_object_unref(pad);
3593 /* done. free allocated variables */
3594 g_list_free(element_bucket);
3598 return MM_ERROR_NONE;
3601 LOGE("ERROR : releasing videobin");
3602 g_list_free(element_bucket);
3605 gst_object_unref(GST_OBJECT(pad));
3607 /* release videobin with it's childs */
3608 if (videobin[MMPLAYER_V_BIN].gst)
3609 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3611 MMPLAYER_FREEIF(videobin);
3612 player->pipeline->videobin = NULL;
3614 return MM_ERROR_PLAYER_INTERNAL;
3618 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3620 GList *element_bucket = NULL;
3621 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3623 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3624 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3625 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3626 "signal-handoffs", FALSE,
3629 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3630 _mmplayer_add_signal_connection(player,
3631 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3632 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3634 G_CALLBACK(__mmplayer_update_subtitle),
3637 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3638 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3640 if (!player->play_subtitle) {
3641 LOGD("add textbin sink as sink element of whole pipeline.");
3642 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3645 /* adding created elements to bin */
3646 LOGD("adding created elements to bin");
3647 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3648 LOGE("failed to add elements");
3652 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3653 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3654 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3656 /* linking elements in the bucket by added order. */
3657 LOGD("Linking elements in the bucket by added order.");
3658 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3659 LOGE("failed to link elements");
3663 /* done. free allocated variables */
3664 g_list_free(element_bucket);
3666 if (textbin[MMPLAYER_T_QUEUE].gst) {
3668 GstPad *ghostpad = NULL;
3670 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3672 LOGE("failed to get sink pad of text queue");
3676 ghostpad = gst_ghost_pad_new("text_sink", pad);
3677 gst_object_unref(pad);
3680 LOGE("failed to create ghostpad of textbin");
3684 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3685 LOGE("failed to add ghostpad to textbin");
3686 gst_object_unref(ghostpad);
3691 return MM_ERROR_NONE;
3694 g_list_free(element_bucket);
3696 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3697 LOGE("remove textbin sink from sink list");
3698 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3701 /* release element at __mmplayer_gst_create_text_sink_bin */
3702 return MM_ERROR_PLAYER_INTERNAL;
3706 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3708 mmplayer_gst_element_t *textbin = NULL;
3709 GList *element_bucket = NULL;
3710 int surface_type = 0;
3715 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3718 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3720 LOGE("failed to allocate memory for textbin");
3721 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3725 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3726 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3727 if (!textbin[MMPLAYER_T_BIN].gst) {
3728 LOGE("failed to create textbin");
3733 player->pipeline->textbin = textbin;
3736 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3737 LOGD("surface type for subtitle : %d", surface_type);
3738 switch (surface_type) {
3739 case MM_DISPLAY_SURFACE_OVERLAY:
3740 case MM_DISPLAY_SURFACE_NULL:
3741 case MM_DISPLAY_SURFACE_REMOTE:
3742 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3743 LOGE("failed to make plain text elements");
3754 return MM_ERROR_NONE;
3758 LOGD("ERROR : releasing textbin");
3760 g_list_free(element_bucket);
3762 /* release signal */
3763 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3765 /* release element which are not added to bin */
3766 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3767 /* NOTE : skip bin */
3768 if (textbin[i].gst) {
3769 GstObject *parent = NULL;
3770 parent = gst_element_get_parent(textbin[i].gst);
3773 gst_object_unref(GST_OBJECT(textbin[i].gst));
3774 textbin[i].gst = NULL;
3776 gst_object_unref(GST_OBJECT(parent));
3781 /* release textbin with it's childs */
3782 if (textbin[MMPLAYER_T_BIN].gst)
3783 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3785 MMPLAYER_FREEIF(player->pipeline->textbin);
3786 player->pipeline->textbin = NULL;
3789 return MM_ERROR_PLAYER_INTERNAL;
3793 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3795 mmplayer_gst_element_t *mainbin = NULL;
3796 mmplayer_gst_element_t *textbin = NULL;
3797 MMHandleType attrs = 0;
3798 GstElement *subsrc = NULL;
3799 GstElement *subparse = NULL;
3800 gchar *subtitle_uri = NULL;
3801 const gchar *charset = NULL;
3807 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3809 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3811 mainbin = player->pipeline->mainbin;
3813 attrs = MMPLAYER_GET_ATTRS(player);
3815 LOGE("cannot get content attribute");
3816 return MM_ERROR_PLAYER_INTERNAL;
3819 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3820 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3821 LOGE("subtitle uri is not proper filepath.");
3822 return MM_ERROR_PLAYER_INVALID_URI;
3825 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3826 LOGE("failed to get storage info of subtitle path");
3827 return MM_ERROR_PLAYER_INVALID_URI;
3830 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3832 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3833 player->subtitle_language_list = NULL;
3834 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3836 /* create the subtitle source */
3837 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3839 LOGE("failed to create filesrc element");
3842 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3844 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3845 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3847 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3848 LOGW("failed to add queue");
3849 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3850 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3851 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3856 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3858 LOGE("failed to create subparse element");
3862 charset = _mmplayer_get_charset(subtitle_uri);
3864 LOGD("detected charset is %s", charset);
3865 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3868 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3869 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3871 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3872 LOGW("failed to add subparse");
3873 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3874 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3875 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3879 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3880 LOGW("failed to link subsrc and subparse");
3884 player->play_subtitle = TRUE;
3885 player->adjust_subtitle_pos = 0;
3887 LOGD("play subtitle using subtitle file");
3889 if (player->pipeline->textbin == NULL) {
3890 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3891 LOGE("failed to create text sink bin. continuing without text");
3895 textbin = player->pipeline->textbin;
3897 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3898 LOGW("failed to add textbin");
3900 /* release signal */
3901 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3903 /* release textbin with it's childs */
3904 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3905 MMPLAYER_FREEIF(player->pipeline->textbin);
3906 player->pipeline->textbin = textbin = NULL;
3910 LOGD("link text input selector and textbin ghost pad");
3912 player->textsink_linked = 1;
3913 player->external_text_idx = 0;
3914 LOGI("textsink is linked");
3916 textbin = player->pipeline->textbin;
3917 LOGD("text bin has been created. reuse it.");
3918 player->external_text_idx = 1;
3921 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3922 LOGW("failed to link subparse and textbin");
3926 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3928 LOGE("failed to get sink pad from textsink to probe data");
3932 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3933 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3935 gst_object_unref(pad);
3938 /* create dot. for debugging */
3939 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3942 return MM_ERROR_NONE;
3945 /* release text pipeline resource */
3946 player->textsink_linked = 0;
3948 /* release signal */
3949 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3951 if (player->pipeline->textbin) {
3952 LOGE("remove textbin");
3954 /* release textbin with it's childs */
3955 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3956 MMPLAYER_FREEIF(player->pipeline->textbin);
3957 player->pipeline->textbin = NULL;
3961 /* release subtitle elem */
3962 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3963 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3965 return MM_ERROR_PLAYER_INTERNAL;
3969 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3971 mmplayer_t *player = (mmplayer_t *)data;
3972 MMMessageParamType msg = {0, };
3973 GstClockTime duration = 0;
3974 gpointer text = NULL;
3975 guint text_size = 0;
3976 gboolean ret = TRUE;
3977 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3981 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3982 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3984 if (player->is_subtitle_force_drop) {
3985 LOGW("subtitle is dropped forcedly.");
3989 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3990 text = mapinfo.data;
3991 text_size = mapinfo.size;
3993 if (player->set_mode.subtitle_off) {
3994 LOGD("subtitle is OFF.");
3998 if (!text || (text_size == 0)) {
3999 LOGD("There is no subtitle to be displayed.");
4003 msg.data = (void *)text;
4005 duration = GST_BUFFER_DURATION(buffer);
4007 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4008 if (player->duration > GST_BUFFER_PTS(buffer))
4009 duration = player->duration - GST_BUFFER_PTS(buffer);
4012 LOGI("subtitle duration is invalid, subtitle duration change "
4013 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4015 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4017 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4019 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4020 gst_buffer_unmap(buffer, &mapinfo);
4027 static GstPadProbeReturn
4028 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4030 mmplayer_t *player = (mmplayer_t *)u_data;
4031 GstClockTime cur_timestamp = 0;
4032 gint64 adjusted_timestamp = 0;
4033 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4035 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4037 if (player->set_mode.subtitle_off) {
4038 LOGD("subtitle is OFF.");
4042 if (player->adjust_subtitle_pos == 0) {
4043 LOGD("nothing to do");
4047 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4048 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4050 if (adjusted_timestamp < 0) {
4051 LOGD("adjusted_timestamp under zero");
4056 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4057 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4058 GST_TIME_ARGS(cur_timestamp),
4059 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4061 return GST_PAD_PROBE_OK;
4065 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4069 /* check player and subtitlebin are created */
4070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4071 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4073 if (position == 0) {
4074 LOGD("nothing to do");
4076 return MM_ERROR_NONE;
4079 /* check current postion */
4080 player->adjust_subtitle_pos = position;
4082 LOGD("save adjust_subtitle_pos in player");
4086 return MM_ERROR_NONE;
4090 * This function is to create audio or video pipeline for playing.
4092 * @param player [in] handle of player
4094 * @return This function returns zero on success.
4099 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4101 int ret = MM_ERROR_NONE;
4102 mmplayer_gst_element_t *mainbin = NULL;
4103 MMHandleType attrs = 0;
4106 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4108 /* get profile attribute */
4109 attrs = MMPLAYER_GET_ATTRS(player);
4111 LOGE("failed to get content attribute");
4115 /* create pipeline handles */
4116 if (player->pipeline) {
4117 LOGE("pipeline should be released before create new one");
4121 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4123 /* create mainbin */
4124 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4125 if (mainbin == NULL)
4128 /* create pipeline */
4129 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4130 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4131 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4132 LOGE("failed to create pipeline");
4137 player->pipeline->mainbin = mainbin;
4139 /* create the source and decoder elements */
4140 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4141 ret = _mmplayer_gst_build_es_pipeline(player);
4143 ret = _mmplayer_gst_build_pipeline(player);
4145 if (ret != MM_ERROR_NONE) {
4146 LOGE("failed to create some elements");
4150 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4151 if (__mmplayer_check_subtitle(player)
4152 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4153 LOGE("failed to create text pipeline");
4156 ret = _mmplayer_gst_add_bus_watch(player);
4157 if (ret != MM_ERROR_NONE) {
4158 LOGE("failed to add bus watch");
4163 return MM_ERROR_NONE;
4166 __mmplayer_gst_destroy_pipeline(player);
4167 return MM_ERROR_PLAYER_INTERNAL;
4171 __mmplayer_reset_gapless_state(mmplayer_t *player)
4174 MMPLAYER_RETURN_IF_FAIL(player
4176 && player->pipeline->audiobin
4177 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4179 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4186 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4189 int ret = MM_ERROR_NONE;
4193 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4195 /* cleanup stuffs */
4196 MMPLAYER_FREEIF(player->type);
4197 player->no_more_pad = FALSE;
4198 player->num_dynamic_pad = 0;
4199 player->demux_pad_index = 0;
4201 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4202 player->subtitle_language_list = NULL;
4203 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4205 __mmplayer_reset_gapless_state(player);
4207 if (player->streamer) {
4208 _mm_player_streaming_initialize(player->streamer, FALSE);
4209 _mm_player_streaming_destroy(player->streamer);
4210 player->streamer = NULL;
4213 /* cleanup unlinked mime type */
4214 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4215 MMPLAYER_FREEIF(player->unlinked_video_mime);
4216 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4218 /* cleanup running stuffs */
4219 _mmplayer_cancel_eos_timer(player);
4221 /* cleanup gst stuffs */
4222 if (player->pipeline) {
4223 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4224 GstTagList *tag_list = player->pipeline->tag_list;
4226 /* first we need to disconnect all signal hander */
4227 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4230 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4231 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4232 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4233 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4234 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4235 gst_object_unref(bus);
4237 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4238 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4239 if (ret != MM_ERROR_NONE) {
4240 LOGE("fail to change state to NULL");
4241 return MM_ERROR_PLAYER_INTERNAL;
4244 LOGW("succeeded in changing state to NULL");
4246 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4249 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4250 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4252 /* free avsysaudiosink
4253 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4254 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4256 MMPLAYER_FREEIF(audiobin);
4257 MMPLAYER_FREEIF(videobin);
4258 MMPLAYER_FREEIF(textbin);
4259 MMPLAYER_FREEIF(mainbin);
4263 gst_tag_list_unref(tag_list);
4265 MMPLAYER_FREEIF(player->pipeline);
4267 MMPLAYER_FREEIF(player->album_art);
4269 if (player->v_stream_caps) {
4270 gst_caps_unref(player->v_stream_caps);
4271 player->v_stream_caps = NULL;
4274 if (player->a_stream_caps) {
4275 gst_caps_unref(player->a_stream_caps);
4276 player->a_stream_caps = NULL;
4279 if (player->s_stream_caps) {
4280 gst_caps_unref(player->s_stream_caps);
4281 player->s_stream_caps = NULL;
4283 _mmplayer_track_destroy(player);
4285 if (player->sink_elements)
4286 g_list_free(player->sink_elements);
4287 player->sink_elements = NULL;
4289 if (player->bufmgr) {
4290 tbm_bufmgr_deinit(player->bufmgr);
4291 player->bufmgr = NULL;
4294 LOGW("finished destroy pipeline");
4302 __mmplayer_gst_realize(mmplayer_t *player)
4305 int ret = MM_ERROR_NONE;
4309 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4311 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4313 ret = __mmplayer_gst_create_pipeline(player);
4315 LOGE("failed to create pipeline");
4319 /* set pipeline state to READY */
4320 /* NOTE : state change to READY must be performed sync. */
4321 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4322 ret = _mmplayer_gst_set_state(player,
4323 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4325 if (ret != MM_ERROR_NONE) {
4326 /* return error if failed to set state */
4327 LOGE("failed to set READY state");
4331 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4333 /* create dot before error-return. for debugging */
4334 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4342 __mmplayer_gst_unrealize(mmplayer_t *player)
4344 int ret = MM_ERROR_NONE;
4348 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4350 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4351 MMPLAYER_PRINT_STATE(player);
4353 /* release miscellaneous information */
4354 __mmplayer_release_misc(player);
4356 /* destroy pipeline */
4357 ret = __mmplayer_gst_destroy_pipeline(player);
4358 if (ret != MM_ERROR_NONE) {
4359 LOGE("failed to destory pipeline");
4363 /* release miscellaneous information.
4364 these info needs to be released after pipeline is destroyed. */
4365 __mmplayer_release_misc_post(player);
4367 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4375 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4380 LOGW("set_message_callback is called with invalid player handle");
4381 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4384 player->msg_cb = callback;
4385 player->msg_cb_param = user_param;
4387 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4391 return MM_ERROR_NONE;
4395 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4397 int ret = MM_ERROR_NONE;
4402 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4403 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4404 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4406 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4408 if (strstr(uri, "es_buff://")) {
4409 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4410 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4411 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4412 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4414 tmp = g_ascii_strdown(uri, strlen(uri));
4415 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4416 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4418 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4420 } else if (strstr(uri, "mms://")) {
4421 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4422 } else if ((path = strstr(uri, "mem://"))) {
4423 ret = __mmplayer_set_mem_uri(data, path, param);
4425 ret = __mmplayer_set_file_uri(data, uri);
4428 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4429 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4430 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4431 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4433 /* dump parse result */
4434 SECURE_LOGW("incoming uri : %s", uri);
4435 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4436 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4444 __mmplayer_can_do_interrupt(mmplayer_t *player)
4446 if (!player || !player->pipeline || !player->attrs) {
4447 LOGW("not initialized");
4451 if (player->audio_decoded_cb) {
4452 LOGW("not support in pcm extraction mode");
4456 /* check if seeking */
4457 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4458 MMMessageParamType msg_param;
4459 memset(&msg_param, 0, sizeof(MMMessageParamType));
4460 msg_param.code = MM_ERROR_PLAYER_SEEK;
4461 player->seek_state = MMPLAYER_SEEK_NONE;
4462 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4466 /* check other thread */
4467 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4468 LOGW("locked already, cmd state : %d", player->cmd);
4470 /* check application command */
4471 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4472 LOGW("playing.. should wait cmd lock then, will be interrupted");
4474 /* lock will be released at mrp_resource_release_cb() */
4475 MMPLAYER_CMD_LOCK(player);
4478 LOGW("nothing to do");
4481 LOGW("can interrupt immediately");
4485 FAILED: /* with CMD UNLOCKED */
4488 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4493 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4496 mmplayer_t *player = NULL;
4497 MMMessageParamType msg = {0, };
4499 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4504 LOGE("user_data is null");
4507 player = (mmplayer_t *)user_data;
4509 if (!__mmplayer_can_do_interrupt(player)) {
4510 LOGW("no need to interrupt, so leave");
4511 /* FIXME: there is no way to avoid releasing resource. */
4515 player->interrupted_by_resource = TRUE;
4517 /* get last play position */
4518 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4519 msg.union_type = MM_MSG_UNION_TIME;
4520 msg.time.elapsed = pos;
4521 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4523 LOGW("failed to get play position.");
4526 LOGD("video resource conflict so, resource will be freed by unrealizing");
4527 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4528 LOGE("failed to unrealize");
4530 /* lock is called in __mmplayer_can_do_interrupt() */
4531 MMPLAYER_CMD_UNLOCK(player);
4533 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4534 player->hw_resource[res_idx] = NULL;
4538 return TRUE; /* release all the resources */
4542 __mmplayer_initialize_video_roi(mmplayer_t *player)
4544 player->video_roi.scale_x = 0.0;
4545 player->video_roi.scale_y = 0.0;
4546 player->video_roi.scale_width = 1.0;
4547 player->video_roi.scale_height = 1.0;
4551 _mmplayer_create_player(MMHandleType handle)
4553 int ret = MM_ERROR_PLAYER_INTERNAL;
4554 bool enabled = false;
4556 mmplayer_t *player = MM_PLAYER_CAST(handle);
4560 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4562 /* initialize player state */
4563 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4564 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4565 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4566 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4568 /* check current state */
4569 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4571 /* construct attributes */
4572 player->attrs = _mmplayer_construct_attribute(handle);
4574 if (!player->attrs) {
4575 LOGE("Failed to construct attributes");
4579 /* initialize gstreamer with configured parameter */
4580 if (!__mmplayer_init_gstreamer(player)) {
4581 LOGE("Initializing gstreamer failed");
4582 _mmplayer_deconstruct_attribute(handle);
4586 /* create lock. note that g_tread_init() has already called in gst_init() */
4587 g_mutex_init(&player->fsink_lock);
4589 /* create update tag lock */
4590 g_mutex_init(&player->update_tag_lock);
4592 /* create gapless play mutex */
4593 g_mutex_init(&player->gapless_play_thread_mutex);
4595 /* create gapless play cond */
4596 g_cond_init(&player->gapless_play_thread_cond);
4598 /* create gapless play thread */
4599 player->gapless_play_thread =
4600 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4601 if (!player->gapless_play_thread) {
4602 LOGE("failed to create gapless play thread");
4603 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4604 g_mutex_clear(&player->gapless_play_thread_mutex);
4605 g_cond_clear(&player->gapless_play_thread_cond);
4609 player->bus_msg_q = g_queue_new();
4610 if (!player->bus_msg_q) {
4611 LOGE("failed to create queue for bus_msg");
4612 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4616 ret = _mmplayer_initialize_video_capture(player);
4617 if (ret != MM_ERROR_NONE) {
4618 LOGE("failed to initialize video capture");
4622 /* initialize resource manager */
4623 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4624 __resource_release_cb, player, &player->resource_manager)
4625 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4626 LOGE("failed to initialize resource manager");
4627 ret = MM_ERROR_PLAYER_INTERNAL;
4631 /* create video bo lock and cond */
4632 g_mutex_init(&player->video_bo_mutex);
4633 g_cond_init(&player->video_bo_cond);
4635 /* create subtitle info lock and cond */
4636 g_mutex_init(&player->subtitle_info_mutex);
4637 g_cond_init(&player->subtitle_info_cond);
4639 player->streaming_type = STREAMING_SERVICE_NONE;
4641 /* give default value of audio effect setting */
4642 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4643 player->sound.rg_enable = false;
4644 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4646 player->play_subtitle = FALSE;
4647 player->has_closed_caption = FALSE;
4648 player->pending_resume = FALSE;
4649 if (player->ini.dump_element_keyword[0][0] == '\0')
4650 player->ini.set_dump_element_flag = FALSE;
4652 player->ini.set_dump_element_flag = TRUE;
4654 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4655 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4656 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4658 /* Set video360 settings to their defaults for just-created player.
4661 player->is_360_feature_enabled = FALSE;
4662 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4663 LOGI("spherical feature info: %d", enabled);
4665 player->is_360_feature_enabled = TRUE;
4667 LOGE("failed to get spherical feature info");
4670 player->is_content_spherical = FALSE;
4671 player->is_video360_enabled = TRUE;
4672 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4673 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4674 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4675 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4676 player->video360_zoom = 1.0f;
4677 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4678 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4680 __mmplayer_initialize_video_roi(player);
4682 /* set player state to null */
4683 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4684 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4688 return MM_ERROR_NONE;
4692 g_mutex_clear(&player->fsink_lock);
4693 /* free update tag lock */
4694 g_mutex_clear(&player->update_tag_lock);
4695 g_queue_free(player->bus_msg_q);
4696 player->bus_msg_q = NULL;
4697 /* free gapless play thread */
4698 if (player->gapless_play_thread) {
4699 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4700 player->gapless_play_thread_exit = TRUE;
4701 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4702 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4704 g_thread_join(player->gapless_play_thread);
4705 player->gapless_play_thread = NULL;
4707 g_mutex_clear(&player->gapless_play_thread_mutex);
4708 g_cond_clear(&player->gapless_play_thread_cond);
4711 /* release attributes */
4712 _mmplayer_deconstruct_attribute(handle);
4720 __mmplayer_init_gstreamer(mmplayer_t *player)
4722 static gboolean initialized = FALSE;
4723 static const int max_argc = 50;
4725 gchar **argv = NULL;
4726 gchar **argv2 = NULL;
4732 LOGD("gstreamer already initialized.");
4737 argc = malloc(sizeof(int));
4738 argv = malloc(sizeof(gchar *) * max_argc);
4739 argv2 = malloc(sizeof(gchar *) * max_argc);
4741 if (!argc || !argv || !argv2)
4744 memset(argv, 0, sizeof(gchar *) * max_argc);
4745 memset(argv2, 0, sizeof(gchar *) * max_argc);
4749 argv[0] = g_strdup("mmplayer");
4752 for (i = 0; i < 5; i++) {
4753 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4754 if (strlen(player->ini.gst_param[i]) > 0) {
4755 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4760 /* we would not do fork for scanning plugins */
4761 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4764 /* check disable registry scan */
4765 if (player->ini.skip_rescan) {
4766 argv[*argc] = g_strdup("--gst-disable-registry-update");
4770 /* check disable segtrap */
4771 if (player->ini.disable_segtrap) {
4772 argv[*argc] = g_strdup("--gst-disable-segtrap");
4776 LOGD("initializing gstreamer with following parameter");
4777 LOGD("argc : %d", *argc);
4780 for (i = 0; i < arg_count; i++) {
4782 LOGD("argv[%d] : %s", i, argv2[i]);
4785 /* initializing gstreamer */
4786 if (!gst_init_check(argc, &argv, &err)) {
4787 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4794 for (i = 0; i < arg_count; i++) {
4796 LOGD("release - argv[%d] : %s", i, argv2[i]);
4798 MMPLAYER_FREEIF(argv2[i]);
4801 MMPLAYER_FREEIF(argv);
4802 MMPLAYER_FREEIF(argv2);
4803 MMPLAYER_FREEIF(argc);
4813 for (i = 0; i < arg_count; i++) {
4814 LOGD("free[%d] : %s", i, argv2[i]);
4815 MMPLAYER_FREEIF(argv2[i]);
4818 MMPLAYER_FREEIF(argv);
4819 MMPLAYER_FREEIF(argv2);
4820 MMPLAYER_FREEIF(argc);
4826 __mmplayer_check_async_state_transition(mmplayer_t *player)
4828 GstState element_state = GST_STATE_VOID_PENDING;
4829 GstState element_pending_state = GST_STATE_VOID_PENDING;
4830 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4831 GstElement *element = NULL;
4832 gboolean async = FALSE;
4834 /* check player handle */
4835 MMPLAYER_RETURN_IF_FAIL(player &&
4837 player->pipeline->mainbin &&
4838 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4841 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4843 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4844 LOGD("don't need to check the pipeline state");
4848 MMPLAYER_PRINT_STATE(player);
4850 /* wait for state transition */
4851 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4852 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4854 if (ret == GST_STATE_CHANGE_FAILURE) {
4855 LOGE(" [%s] state : %s pending : %s",
4856 GST_ELEMENT_NAME(element),
4857 gst_element_state_get_name(element_state),
4858 gst_element_state_get_name(element_pending_state));
4860 /* dump state of all element */
4861 _mmplayer_dump_pipeline_state(player);
4866 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4871 _mmplayer_destroy(MMHandleType handle)
4873 mmplayer_t *player = MM_PLAYER_CAST(handle);
4877 /* check player handle */
4878 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4880 /* destroy can called at anytime */
4881 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4883 /* check async state transition */
4884 __mmplayer_check_async_state_transition(player);
4886 /* release gapless play thread */
4887 if (player->gapless_play_thread) {
4888 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4889 player->gapless_play_thread_exit = TRUE;
4890 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4891 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4893 LOGD("waitting for gapless play thread exit");
4894 g_thread_join(player->gapless_play_thread);
4895 g_mutex_clear(&player->gapless_play_thread_mutex);
4896 g_cond_clear(&player->gapless_play_thread_cond);
4897 LOGD("gapless play thread released");
4900 _mmplayer_release_video_capture(player);
4902 /* de-initialize resource manager */
4903 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4904 player->resource_manager))
4905 LOGE("failed to deinitialize resource manager");
4907 /* release pipeline */
4908 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4909 LOGE("failed to destory pipeline");
4910 return MM_ERROR_PLAYER_INTERNAL;
4913 g_queue_free(player->bus_msg_q);
4915 /* release subtitle info lock and cond */
4916 g_mutex_clear(&player->subtitle_info_mutex);
4917 g_cond_clear(&player->subtitle_info_cond);
4919 __mmplayer_release_dump_list(player->dump_list);
4921 /* release miscellaneous information */
4922 __mmplayer_release_misc(player);
4924 /* release miscellaneous information.
4925 these info needs to be released after pipeline is destroyed. */
4926 __mmplayer_release_misc_post(player);
4928 /* release attributes */
4929 _mmplayer_deconstruct_attribute(handle);
4932 g_mutex_clear(&player->fsink_lock);
4935 g_mutex_clear(&player->update_tag_lock);
4937 /* release video bo lock and cond */
4938 g_mutex_clear(&player->video_bo_mutex);
4939 g_cond_clear(&player->video_bo_cond);
4943 return MM_ERROR_NONE;
4947 _mmplayer_realize(MMHandleType hplayer)
4949 mmplayer_t *player = (mmplayer_t *)hplayer;
4952 MMHandleType attrs = 0;
4953 int ret = MM_ERROR_NONE;
4957 /* check player handle */
4958 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4960 /* check current state */
4961 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4963 attrs = MMPLAYER_GET_ATTRS(player);
4965 LOGE("fail to get attributes.");
4966 return MM_ERROR_PLAYER_INTERNAL;
4968 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4969 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4971 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4972 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4974 if (ret != MM_ERROR_NONE) {
4975 LOGE("failed to parse profile");
4980 if (uri && (strstr(uri, "es_buff://"))) {
4981 if (strstr(uri, "es_buff://push_mode"))
4982 player->es_player_push_mode = TRUE;
4984 player->es_player_push_mode = FALSE;
4987 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4988 LOGW("mms protocol is not supported format.");
4989 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4992 if (MMPLAYER_IS_STREAMING(player))
4993 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4995 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4997 player->smooth_streaming = FALSE;
4998 player->videodec_linked = 0;
4999 player->audiodec_linked = 0;
5000 player->textsink_linked = 0;
5001 player->is_external_subtitle_present = FALSE;
5002 player->is_external_subtitle_added_now = FALSE;
5003 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5004 player->video360_metadata.is_spherical = -1;
5005 player->is_openal_plugin_used = FALSE;
5006 player->demux_pad_index = 0;
5007 player->subtitle_language_list = NULL;
5008 player->is_subtitle_force_drop = FALSE;
5010 _mmplayer_track_initialize(player);
5011 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5013 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5014 gint prebuffer_ms = 0, rebuffer_ms = 0;
5016 player->streamer = _mm_player_streaming_create();
5017 _mm_player_streaming_initialize(player->streamer, TRUE);
5019 mm_attrs_multiple_get(player->attrs, NULL,
5020 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5021 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5023 if (prebuffer_ms > 0) {
5024 prebuffer_ms = MAX(prebuffer_ms, 1000);
5025 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5028 if (rebuffer_ms > 0) {
5029 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5030 rebuffer_ms = MAX(rebuffer_ms, 1000);
5031 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5034 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5035 player->streamer->buffering_req.rebuffer_time);
5038 /* realize pipeline */
5039 ret = __mmplayer_gst_realize(player);
5040 if (ret != MM_ERROR_NONE)
5041 LOGE("fail to realize the player.");
5043 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5051 _mmplayer_unrealize(MMHandleType hplayer)
5053 mmplayer_t *player = (mmplayer_t *)hplayer;
5054 int ret = MM_ERROR_NONE;
5058 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5060 MMPLAYER_CMD_UNLOCK(player);
5061 /* destroy the gst bus msg thread which is created during realize.
5062 this funct have to be called before getting cmd lock. */
5063 _mmplayer_bus_msg_thread_destroy(player);
5064 MMPLAYER_CMD_LOCK(player);
5066 /* check current state */
5067 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5069 /* check async state transition */
5070 __mmplayer_check_async_state_transition(player);
5072 /* unrealize pipeline */
5073 ret = __mmplayer_gst_unrealize(player);
5075 if (!player->interrupted_by_resource) {
5076 int rm_ret = MM_ERROR_NONE;
5077 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5079 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5080 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5081 if (rm_ret != MM_ERROR_NONE)
5082 LOGE("failed to release [%d] resources", res_idx);
5091 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5093 mmplayer_t *player = (mmplayer_t *)hplayer;
5095 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5097 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5101 _mmplayer_get_state(MMHandleType hplayer, int *state)
5103 mmplayer_t *player = (mmplayer_t *)hplayer;
5105 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5107 *state = MMPLAYER_CURRENT_STATE(player);
5109 return MM_ERROR_NONE;
5113 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5115 GstElement *vol_element = NULL;
5116 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5119 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5120 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5122 /* check pipeline handle */
5123 if (!player->pipeline || !player->pipeline->audiobin) {
5124 LOGD("'%s' will be applied when audiobin is created", prop_name);
5126 /* NOTE : stored value will be used in create_audiobin
5127 * returning MM_ERROR_NONE here makes application to able to
5128 * set audio volume or mute at anytime.
5130 return MM_ERROR_NONE;
5133 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5134 volume_elem_id = MMPLAYER_A_SINK;
5136 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5138 LOGE("failed to get vol element %d", volume_elem_id);
5139 return MM_ERROR_PLAYER_INTERNAL;
5142 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5144 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5145 LOGE("there is no '%s' property", prop_name);
5146 return MM_ERROR_PLAYER_INTERNAL;
5149 if (!strcmp(prop_name, "volume")) {
5150 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5151 } else if (!strcmp(prop_name, "mute")) {
5152 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5154 LOGE("invalid property %s", prop_name);
5155 return MM_ERROR_PLAYER_INTERNAL;
5158 return MM_ERROR_NONE;
5162 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5164 int ret = MM_ERROR_NONE;
5165 mmplayer_t *player = (mmplayer_t *)hplayer;
5168 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5170 LOGD("volume = %f", volume);
5172 /* invalid factor range or not */
5173 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5174 LOGE("Invalid volume value");
5175 return MM_ERROR_INVALID_ARGUMENT;
5178 player->sound.volume = volume;
5180 ret = __mmplayer_gst_set_volume_property(player, "volume");
5187 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5189 mmplayer_t *player = (mmplayer_t *)hplayer;
5193 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5194 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5196 *volume = player->sound.volume;
5198 LOGD("current vol = %f", *volume);
5201 return MM_ERROR_NONE;
5205 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5207 int ret = MM_ERROR_NONE;
5208 mmplayer_t *player = (mmplayer_t *)hplayer;
5211 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5213 LOGD("mute = %d", mute);
5215 player->sound.mute = mute;
5217 ret = __mmplayer_gst_set_volume_property(player, "mute");
5224 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5226 mmplayer_t *player = (mmplayer_t *)hplayer;
5230 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5231 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5233 *mute = player->sound.mute;
5235 LOGD("current mute = %d", *mute);
5239 return MM_ERROR_NONE;
5243 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5245 mmplayer_t *player = (mmplayer_t *)hplayer;
5249 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5251 player->audio_stream_changed_cb = callback;
5252 player->audio_stream_changed_cb_user_param = user_param;
5253 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5257 return MM_ERROR_NONE;
5261 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5263 mmplayer_t *player = (mmplayer_t *)hplayer;
5267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5269 player->audio_decoded_cb = callback;
5270 player->audio_decoded_cb_user_param = user_param;
5271 player->audio_extract_opt = opt;
5272 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5276 return MM_ERROR_NONE;
5280 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5282 mmplayer_t *player = (mmplayer_t *)hplayer;
5286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5288 if (callback && !player->bufmgr)
5289 player->bufmgr = tbm_bufmgr_init(-1);
5291 player->set_mode.video_export = (callback) ? true : false;
5292 player->video_decoded_cb = callback;
5293 player->video_decoded_cb_user_param = user_param;
5295 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5299 return MM_ERROR_NONE;
5303 _mmplayer_start(MMHandleType hplayer)
5305 mmplayer_t *player = (mmplayer_t *)hplayer;
5306 gint ret = MM_ERROR_NONE;
5310 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5312 /* check current state */
5313 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5315 /* start pipeline */
5316 ret = _mmplayer_gst_start(player);
5317 if (ret != MM_ERROR_NONE)
5318 LOGE("failed to start player.");
5320 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5321 LOGD("force playing start even during buffering");
5322 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5330 /* NOTE: post "not supported codec message" to application
5331 * when one codec is not found during AUTOPLUGGING in MSL.
5332 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5333 * And, if any codec is not found, don't send message here.
5334 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5337 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5339 MMMessageParamType msg_param;
5340 memset(&msg_param, 0, sizeof(MMMessageParamType));
5341 gboolean post_msg_direct = FALSE;
5345 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5347 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5348 player->not_supported_codec, player->can_support_codec);
5350 if (player->not_found_demuxer) {
5351 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5352 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5354 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5355 MMPLAYER_FREEIF(msg_param.data);
5357 return MM_ERROR_NONE;
5360 if (player->not_supported_codec) {
5361 if (player->can_support_codec) {
5362 // There is one codec to play
5363 post_msg_direct = TRUE;
5365 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5366 post_msg_direct = TRUE;
5369 if (post_msg_direct) {
5370 MMMessageParamType msg_param;
5371 memset(&msg_param, 0, sizeof(MMMessageParamType));
5373 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5374 LOGW("not found AUDIO codec, posting error code to application.");
5376 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5377 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5378 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5379 LOGW("not found VIDEO codec, posting error code to application.");
5381 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5382 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5385 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5387 MMPLAYER_FREEIF(msg_param.data);
5389 return MM_ERROR_NONE;
5391 // no any supported codec case
5392 LOGW("not found any codec, posting error code to application.");
5394 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5395 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5396 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5398 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5399 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5402 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5404 MMPLAYER_FREEIF(msg_param.data);
5410 return MM_ERROR_NONE;
5414 __mmplayer_check_pipeline(mmplayer_t *player)
5416 GstState element_state = GST_STATE_VOID_PENDING;
5417 GstState element_pending_state = GST_STATE_VOID_PENDING;
5419 int ret = MM_ERROR_NONE;
5421 if (!player->gapless.reconfigure)
5424 LOGW("pipeline is under construction.");
5426 MMPLAYER_PLAYBACK_LOCK(player);
5427 MMPLAYER_PLAYBACK_UNLOCK(player);
5429 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5431 /* wait for state transition */
5432 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5433 if (ret == GST_STATE_CHANGE_FAILURE)
5434 LOGE("failed to change pipeline state within %d sec", timeout);
5437 /* NOTE : it should be able to call 'stop' anytime*/
5439 _mmplayer_stop(MMHandleType hplayer)
5441 mmplayer_t *player = (mmplayer_t *)hplayer;
5442 int ret = MM_ERROR_NONE;
5446 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5448 /* check current state */
5449 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5451 /* check pipline building state */
5452 __mmplayer_check_pipeline(player);
5453 __mmplayer_reset_gapless_state(player);
5455 /* NOTE : application should not wait for EOS after calling STOP */
5456 _mmplayer_cancel_eos_timer(player);
5459 player->seek_state = MMPLAYER_SEEK_NONE;
5462 ret = _mmplayer_gst_stop(player);
5464 if (ret != MM_ERROR_NONE)
5465 LOGE("failed to stop player.");
5473 _mmplayer_pause(MMHandleType hplayer)
5475 mmplayer_t *player = (mmplayer_t *)hplayer;
5476 gint64 pos_nsec = 0;
5477 gboolean async = FALSE;
5478 gint ret = MM_ERROR_NONE;
5482 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5484 /* check current state */
5485 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5487 /* check pipline building state */
5488 __mmplayer_check_pipeline(player);
5490 switch (MMPLAYER_CURRENT_STATE(player)) {
5491 case MM_PLAYER_STATE_READY:
5493 /* check prepare async or not.
5494 * In the case of streaming playback, it's recommned to avoid blocking wait.
5496 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5497 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5499 /* Changing back sync of rtspsrc to async */
5500 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5501 LOGD("async prepare working mode for rtsp");
5507 case MM_PLAYER_STATE_PLAYING:
5509 /* NOTE : store current point to overcome some bad operation
5510 *(returning zero when getting current position in paused state) of some
5513 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5514 LOGW("getting current position failed in paused");
5516 player->last_position = pos_nsec;
5518 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5519 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5520 This causes problem is position calculation during normal pause resume scenarios also.
5521 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5522 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5523 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5524 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5530 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5531 LOGD("doing async pause in case of ms buff src");
5535 /* pause pipeline */
5536 ret = _mmplayer_gst_pause(player, async);
5538 if (ret != MM_ERROR_NONE)
5539 LOGE("failed to pause player. ret : 0x%x", ret);
5541 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5542 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5543 LOGE("failed to update display_rotation");
5551 /* in case of streaming, pause could take long time.*/
5553 _mmplayer_abort_pause(MMHandleType hplayer)
5555 mmplayer_t *player = (mmplayer_t *)hplayer;
5556 int ret = MM_ERROR_NONE;
5560 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5562 player->pipeline->mainbin,
5563 MM_ERROR_PLAYER_NOT_INITIALIZED);
5565 LOGD("set the pipeline state to READY");
5567 /* set state to READY */
5568 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5569 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5570 if (ret != MM_ERROR_NONE) {
5571 LOGE("fail to change state to READY");
5572 return MM_ERROR_PLAYER_INTERNAL;
5575 LOGD("succeeded in changing state to READY");
5580 _mmplayer_resume(MMHandleType hplayer)
5582 mmplayer_t *player = (mmplayer_t *)hplayer;
5583 int ret = MM_ERROR_NONE;
5584 gboolean async = FALSE;
5588 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5590 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5591 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5592 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5596 /* Changing back sync mode rtspsrc to async */
5597 LOGD("async resume for rtsp case");
5601 /* check current state */
5602 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5604 ret = _mmplayer_gst_resume(player, async);
5605 if (ret != MM_ERROR_NONE)
5606 LOGE("failed to resume player.");
5608 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5609 LOGD("force resume even during buffering");
5610 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5619 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5621 mmplayer_t *player = (mmplayer_t *)hplayer;
5622 gint64 pos_nsec = 0;
5623 int ret = MM_ERROR_NONE;
5625 signed long long start = 0, stop = 0;
5626 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5629 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5630 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5632 /* The sound of video is not supported under 0.0 and over 2.0. */
5633 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5634 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5637 _mmplayer_set_mute(hplayer, mute);
5639 if (player->playback_rate == rate)
5640 return MM_ERROR_NONE;
5642 /* If the position is reached at start potion during fast backward, EOS is posted.
5643 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5645 player->playback_rate = rate;
5647 current_state = MMPLAYER_CURRENT_STATE(player);
5649 if (current_state != MM_PLAYER_STATE_PAUSED)
5650 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5652 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5654 if ((current_state == MM_PLAYER_STATE_PAUSED)
5655 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5656 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5657 pos_nsec = player->last_position;
5662 stop = GST_CLOCK_TIME_NONE;
5664 start = GST_CLOCK_TIME_NONE;
5668 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5669 player->playback_rate,
5671 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5672 GST_SEEK_TYPE_SET, start,
5673 GST_SEEK_TYPE_SET, stop)) {
5674 LOGE("failed to set speed playback");
5675 return MM_ERROR_PLAYER_SEEK;
5678 LOGD("succeeded to set speed playback as %0.1f", rate);
5682 return MM_ERROR_NONE;;
5686 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5688 mmplayer_t *player = (mmplayer_t *)hplayer;
5689 int ret = MM_ERROR_NONE;
5693 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5695 /* check pipline building state */
5696 __mmplayer_check_pipeline(player);
5698 ret = _mmplayer_gst_set_position(player, position, FALSE);
5706 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5708 mmplayer_t *player = (mmplayer_t *)hplayer;
5709 int ret = MM_ERROR_NONE;
5711 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5712 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5714 if (g_strrstr(player->type, "video/mpegts"))
5715 __mmplayer_update_duration_value(player);
5717 *duration = player->duration;
5722 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5724 mmplayer_t *player = (mmplayer_t *)hplayer;
5725 int ret = MM_ERROR_NONE;
5727 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5729 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5735 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5737 mmplayer_t *player = (mmplayer_t *)hplayer;
5738 int ret = MM_ERROR_NONE;
5742 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5744 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5752 __mmplayer_is_midi_type(gchar *str_caps)
5754 if ((g_strrstr(str_caps, "audio/midi")) ||
5755 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5756 (g_strrstr(str_caps, "application/x-smaf")) ||
5757 (g_strrstr(str_caps, "audio/x-imelody")) ||
5758 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5759 (g_strrstr(str_caps, "audio/xmf")) ||
5760 (g_strrstr(str_caps, "audio/mxmf"))) {
5769 __mmplayer_is_only_mp3_type(gchar *str_caps)
5771 if (g_strrstr(str_caps, "application/x-id3") ||
5772 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5778 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5780 GstStructure *caps_structure = NULL;
5781 gint samplerate = 0;
5785 MMPLAYER_RETURN_IF_FAIL(player && caps);
5787 caps_structure = gst_caps_get_structure(caps, 0);
5789 /* set stream information */
5790 gst_structure_get_int(caps_structure, "rate", &samplerate);
5791 gst_structure_get_int(caps_structure, "channels", &channels);
5793 mm_player_set_attribute((MMHandleType)player, NULL,
5794 "content_audio_samplerate", samplerate,
5795 "content_audio_channels", channels, NULL);
5797 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5801 __mmplayer_update_content_type_info(mmplayer_t *player)
5804 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5806 if (__mmplayer_is_midi_type(player->type)) {
5807 player->bypass_audio_effect = TRUE;
5811 if (!player->streamer) {
5812 LOGD("no need to check streaming type");
5816 if (g_strrstr(player->type, "application/x-hls")) {
5817 /* If it can't know exact type when it parses uri because of redirection case,
5818 * it will be fixed by typefinder or when doing autoplugging.
5820 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5821 player->streamer->is_adaptive_streaming = TRUE;
5822 } else if (g_strrstr(player->type, "application/dash+xml")) {
5823 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5824 player->streamer->is_adaptive_streaming = TRUE;
5827 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5828 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5829 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5831 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5832 if (player->streamer->is_adaptive_streaming)
5833 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5835 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5839 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5844 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5845 GstCaps *caps, gpointer data)
5847 mmplayer_t *player = (mmplayer_t *)data;
5852 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5854 /* store type string */
5855 MMPLAYER_FREEIF(player->type);
5856 player->type = gst_caps_to_string(caps);
5858 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5859 player, player->type, probability, gst_caps_get_size(caps));
5861 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5862 (g_strrstr(player->type, "audio/x-raw-int"))) {
5863 LOGE("not support media format");
5865 if (player->msg_posted == FALSE) {
5866 MMMessageParamType msg_param;
5867 memset(&msg_param, 0, sizeof(MMMessageParamType));
5869 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5870 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5872 /* don't post more if one was sent already */
5873 player->msg_posted = TRUE;
5878 __mmplayer_update_content_type_info(player);
5880 pad = gst_element_get_static_pad(tf, "src");
5882 LOGE("fail to get typefind src pad.");
5886 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5887 gboolean async = FALSE;
5888 LOGE("failed to autoplug %s", player->type);
5890 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5892 if (async && player->msg_posted == FALSE)
5893 __mmplayer_handle_missed_plugin(player);
5897 gst_object_unref(GST_OBJECT(pad));
5905 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5907 GstElement *decodebin = NULL;
5911 /* create decodebin */
5912 decodebin = gst_element_factory_make("decodebin", NULL);
5915 LOGE("fail to create decodebin");
5919 /* raw pad handling signal */
5920 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5921 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5923 /* no-more-pad pad handling signal */
5924 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5925 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5927 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5928 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5930 /* This signal is emitted when a pad for which there is no further possible
5931 decoding is added to the decodebin.*/
5932 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5933 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5935 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5936 before looking for any elements that can handle that stream.*/
5937 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5938 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5940 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5941 before looking for any elements that can handle that stream.*/
5942 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5943 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5945 /* This signal is emitted once decodebin has finished decoding all the data.*/
5946 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5947 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5949 /* This signal is emitted when a element is added to the bin.*/
5950 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5951 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5958 __mmplayer_gst_make_queue2(mmplayer_t *player)
5960 GstElement *queue2 = NULL;
5961 gint64 dur_bytes = 0L;
5962 mmplayer_gst_element_t *mainbin = NULL;
5963 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5966 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5968 mainbin = player->pipeline->mainbin;
5970 queue2 = gst_element_factory_make("queue2", "queue2");
5972 LOGE("failed to create buffering queue element");
5976 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5977 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5979 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5981 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5982 * skip the pull mode(file or ring buffering) setting. */
5983 if (dur_bytes > 0) {
5984 if (!g_strrstr(player->type, "video/mpegts")) {
5985 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5986 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5992 _mm_player_streaming_set_queue2(player->streamer,
5996 (guint64)dur_bytes); /* no meaning at the moment */
6002 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6004 mmplayer_gst_element_t *mainbin = NULL;
6005 GstElement *decodebin = NULL;
6006 GstElement *queue2 = NULL;
6007 GstPad *sinkpad = NULL;
6008 GstPad *qsrcpad = NULL;
6011 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6013 mainbin = player->pipeline->mainbin;
6015 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6017 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6018 LOGW("need to check: muxed buffer is not null");
6021 queue2 = __mmplayer_gst_make_queue2(player);
6023 LOGE("failed to make queue2");
6027 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6028 LOGE("failed to add buffering queue");
6032 sinkpad = gst_element_get_static_pad(queue2, "sink");
6033 qsrcpad = gst_element_get_static_pad(queue2, "src");
6035 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6036 LOGE("failed to link [%s:%s]-[%s:%s]",
6037 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6041 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6042 LOGE("failed to sync queue2 state with parent");
6046 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6047 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6051 gst_object_unref(GST_OBJECT(sinkpad));
6055 /* create decodebin */
6056 decodebin = _mmplayer_gst_make_decodebin(player);
6058 LOGE("failed to make decodebin");
6062 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6063 LOGE("failed to add decodebin");
6067 /* to force caps on the decodebin element and avoid reparsing stuff by
6068 * typefind. It also avoids a deadlock in the way typefind activates pads in
6069 * the state change */
6070 g_object_set(decodebin, "sink-caps", caps, NULL);
6072 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6074 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6075 LOGE("failed to link [%s:%s]-[%s:%s]",
6076 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6080 gst_object_unref(GST_OBJECT(sinkpad));
6082 gst_object_unref(GST_OBJECT(qsrcpad));
6085 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6086 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6088 /* set decodebin property about buffer in streaming playback. *
6089 * in case of HLS/DASH, it does not need to have big buffer *
6090 * because it is kind of adaptive streaming. */
6091 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6092 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6093 gint high_percent = 0;
6095 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6096 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6098 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6100 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6102 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6103 "high-percent", high_percent,
6104 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6105 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6106 "max-size-buffers", 0, NULL); // disable or automatic
6109 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6110 LOGE("failed to sync decodebin state with parent");
6121 gst_object_unref(GST_OBJECT(sinkpad));
6124 gst_object_unref(GST_OBJECT(qsrcpad));
6127 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6128 * You need to explicitly set elements to the NULL state before
6129 * dropping the final reference, to allow them to clean up.
6131 gst_element_set_state(queue2, GST_STATE_NULL);
6133 /* And, it still has a parent "player".
6134 * You need to let the parent manage the object instead of unreffing the object directly.
6136 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6137 gst_object_unref(queue2);
6142 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6143 * You need to explicitly set elements to the NULL state before
6144 * dropping the final reference, to allow them to clean up.
6146 gst_element_set_state(decodebin, GST_STATE_NULL);
6148 /* And, it still has a parent "player".
6149 * You need to let the parent manage the object instead of unreffing the object directly.
6152 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6153 gst_object_unref(decodebin);
6161 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6165 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6166 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6168 LOGD("class : %s, mime : %s", factory_class, mime);
6170 /* add missing plugin */
6171 /* NOTE : msl should check missing plugin for image mime type.
6172 * Some motion jpeg clips can have playable audio track.
6173 * So, msl have to play audio after displaying popup written video format not supported.
6175 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6176 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6177 LOGD("not found demuxer");
6178 player->not_found_demuxer = TRUE;
6179 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6185 if (!g_strrstr(factory_class, "Demuxer")) {
6186 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6187 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6188 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6190 /* check that clip have multi tracks or not */
6191 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6192 LOGD("video plugin is already linked");
6194 LOGW("add VIDEO to missing plugin");
6195 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6196 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6198 } else if (g_str_has_prefix(mime, "audio")) {
6199 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6200 LOGD("audio plugin is already linked");
6202 LOGW("add AUDIO to missing plugin");
6203 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6204 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6212 return MM_ERROR_NONE;
6216 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6218 mmplayer_t *player = (mmplayer_t *)data;
6222 MMPLAYER_RETURN_IF_FAIL(player);
6224 /* remove fakesink. */
6225 if (!_mmplayer_gst_remove_fakesink(player,
6226 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6227 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6228 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6229 * source element are not same. To overcome this situation, this function will called
6230 * several places and several times. Therefore, this is not an error case.
6235 LOGD("[handle: %p] pipeline has completely constructed", player);
6237 if ((player->ini.async_start) &&
6238 (player->msg_posted == FALSE) &&
6239 (player->cmd >= MMPLAYER_COMMAND_START))
6240 __mmplayer_handle_missed_plugin(player);
6242 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6246 __mmplayer_check_profile(void)
6249 static int profile_tv = -1;
6251 if (__builtin_expect(profile_tv != -1, 1))
6254 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6255 switch (*profileName) {
6270 __mmplayer_get_next_uri(mmplayer_t *player)
6272 mmplayer_parse_profile_t profile;
6274 guint num_of_list = 0;
6277 num_of_list = g_list_length(player->uri_info.uri_list);
6278 uri_idx = player->uri_info.uri_idx;
6280 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6281 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6282 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6284 LOGW("next uri does not exist");
6288 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6289 LOGE("failed to parse profile");
6293 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6294 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6295 LOGW("uri type is not supported(%d)", profile.uri_type);
6299 LOGD("success to find next uri %d", uri_idx);
6303 if (!uri || uri_idx == num_of_list) {
6304 LOGE("failed to find next uri");
6308 player->uri_info.uri_idx = uri_idx;
6309 if (mm_player_set_attribute((MMHandleType)player, NULL,
6310 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6311 LOGE("failed to set attribute");
6315 SECURE_LOGD("next playback uri: %s", uri);
6320 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6322 #define REPEAT_COUNT_INFINITE -1
6323 #define REPEAT_COUNT_MIN 2
6324 #define ORIGINAL_URI_ONLY 1
6326 MMHandleType attrs = 0;
6330 guint num_of_uri = 0;
6331 int profile_tv = -1;
6335 LOGD("checking for gapless play option");
6337 if (player->build_audio_offload) {
6338 LOGE("offload path is not supportable.");
6342 if (player->pipeline->textbin) {
6343 LOGE("subtitle path is enabled. gapless play is not supported.");
6347 attrs = MMPLAYER_GET_ATTRS(player);
6349 LOGE("fail to get attributes.");
6353 mm_attrs_multiple_get(player->attrs, NULL,
6354 "content_video_found", &video,
6355 "profile_play_count", &count,
6356 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6358 /* gapless playback is not supported in case of video at TV profile. */
6359 profile_tv = __mmplayer_check_profile();
6360 if (profile_tv && video) {
6361 LOGW("not support video gapless playback");
6365 /* check repeat count in case of audio */
6367 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6368 LOGW("gapless is disabled");
6372 num_of_uri = g_list_length(player->uri_info.uri_list);
6374 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6376 if (num_of_uri == ORIGINAL_URI_ONLY) {
6377 /* audio looping path */
6378 if (count >= REPEAT_COUNT_MIN) {
6379 /* decrease play count */
6380 /* we succeeded to rewind. update play count and then wait for next EOS */
6382 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6383 } else if (count != REPEAT_COUNT_INFINITE) {
6384 LOGD("there is no next uri and no repeat");
6387 LOGD("looping cnt %d", count);
6389 /* gapless playback path */
6390 if (!__mmplayer_get_next_uri(player)) {
6391 LOGE("failed to get next uri");
6398 LOGE("unable to play gapless path. EOS will be posted soon");
6403 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6405 mmplayer_selector_t *selector = &player->selector[type];
6406 mmplayer_gst_element_t *sinkbin = NULL;
6407 main_element_id_e selectorId = MMPLAYER_M_NUM;
6408 main_element_id_e sinkId = MMPLAYER_M_NUM;
6409 GstPad *srcpad = NULL;
6410 GstPad *sinkpad = NULL;
6411 gboolean send_notice = FALSE;
6414 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6416 LOGD("type %d", type);
6419 case MM_PLAYER_TRACK_TYPE_AUDIO:
6420 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6421 sinkId = MMPLAYER_A_BIN;
6422 sinkbin = player->pipeline->audiobin;
6424 case MM_PLAYER_TRACK_TYPE_VIDEO:
6425 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6426 sinkId = MMPLAYER_V_BIN;
6427 sinkbin = player->pipeline->videobin;
6430 case MM_PLAYER_TRACK_TYPE_TEXT:
6431 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6432 sinkId = MMPLAYER_T_BIN;
6433 sinkbin = player->pipeline->textbin;
6436 LOGE("requested type is not supportable");
6441 if (player->pipeline->mainbin[selectorId].gst) {
6444 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6446 if (selector->event_probe_id != 0)
6447 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6448 selector->event_probe_id = 0;
6450 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6451 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6453 if (srcpad && sinkpad) {
6454 /* after getting drained signal there is no data flows, so no need to do pad_block */
6455 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6456 gst_pad_unlink(srcpad, sinkpad);
6458 /* send custom event to sink pad to handle it at video sink */
6460 LOGD("send custom event to sinkpad");
6461 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6462 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6463 gst_pad_send_event(sinkpad, event);
6467 gst_object_unref(sinkpad);
6470 gst_object_unref(srcpad);
6473 LOGD("selector release");
6475 /* release and unref requests pad from the selector */
6476 for (n = 0; n < selector->channels->len; n++) {
6477 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6478 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6480 g_ptr_array_set_size(selector->channels, 0);
6482 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6483 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6485 player->pipeline->mainbin[selectorId].gst = NULL;
6493 __mmplayer_deactivate_old_path(mmplayer_t *player)
6496 MMPLAYER_RETURN_IF_FAIL(player);
6498 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6499 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6500 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6501 LOGE("deactivate selector error");
6505 _mmplayer_track_destroy(player);
6506 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6508 if (player->streamer) {
6509 _mm_player_streaming_initialize(player->streamer, FALSE);
6510 _mm_player_streaming_destroy(player->streamer);
6511 player->streamer = NULL;
6514 MMPLAYER_PLAYBACK_LOCK(player);
6515 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6522 if (!player->msg_posted) {
6523 MMMessageParamType msg = {0,};
6526 msg.code = MM_ERROR_PLAYER_INTERNAL;
6527 LOGE("gapless_uri_play> deactivate error");
6529 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6530 player->msg_posted = TRUE;
6536 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6538 int result = MM_ERROR_NONE;
6539 mmplayer_t *player = (mmplayer_t *)hplayer;
6542 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6543 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6545 if (mm_player_set_attribute(hplayer, NULL,
6546 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6547 LOGE("failed to set attribute");
6548 result = MM_ERROR_PLAYER_INTERNAL;
6550 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6551 LOGE("failed to add the original uri in the uri list.");
6559 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6561 mmplayer_t *player = (mmplayer_t *)hplayer;
6562 guint num_of_list = 0;
6566 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6567 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6569 if (player->pipeline && player->pipeline->textbin) {
6570 LOGE("subtitle path is enabled.");
6571 return MM_ERROR_PLAYER_INVALID_STATE;
6574 num_of_list = g_list_length(player->uri_info.uri_list);
6576 if (is_first_path) {
6577 if (num_of_list == 0) {
6578 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6579 SECURE_LOGD("add original path : %s", uri);
6581 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6582 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6584 SECURE_LOGD("change original path : %s", uri);
6587 MMHandleType attrs = 0;
6588 attrs = MMPLAYER_GET_ATTRS(player);
6590 if (num_of_list == 0) {
6591 char *original_uri = NULL;
6594 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6596 if (!original_uri) {
6597 LOGE("there is no original uri.");
6598 return MM_ERROR_PLAYER_INVALID_STATE;
6601 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6602 player->uri_info.uri_idx = 0;
6604 SECURE_LOGD("add original path at first : %s", original_uri);
6608 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6609 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6613 return MM_ERROR_NONE;
6617 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6619 mmplayer_t *player = (mmplayer_t *)hplayer;
6620 char *next_uri = NULL;
6621 guint num_of_list = 0;
6624 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6626 num_of_list = g_list_length(player->uri_info.uri_list);
6628 if (num_of_list > 0) {
6629 gint uri_idx = player->uri_info.uri_idx;
6631 if (uri_idx < num_of_list-1)
6636 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6637 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6639 *uri = g_strdup(next_uri);
6643 return MM_ERROR_NONE;
6647 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6648 GstCaps *caps, gpointer data)
6650 mmplayer_t *player = (mmplayer_t *)data;
6651 const gchar *klass = NULL;
6652 const gchar *mime = NULL;
6653 gchar *caps_str = NULL;
6655 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6656 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6657 caps_str = gst_caps_to_string(caps);
6659 LOGW("unknown type of caps : %s from %s",
6660 caps_str, GST_ELEMENT_NAME(elem));
6662 MMPLAYER_FREEIF(caps_str);
6664 /* There is no available codec. */
6665 __mmplayer_check_not_supported_codec(player, klass, mime);
6669 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6670 GstCaps *caps, gpointer data)
6672 mmplayer_t *player = (mmplayer_t *)data;
6673 const char *mime = NULL;
6674 gboolean ret = TRUE;
6676 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6677 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6679 if (g_str_has_prefix(mime, "audio")) {
6680 GstStructure *caps_structure = NULL;
6681 gint samplerate = 0;
6683 gchar *caps_str = NULL;
6685 caps_structure = gst_caps_get_structure(caps, 0);
6686 gst_structure_get_int(caps_structure, "rate", &samplerate);
6687 gst_structure_get_int(caps_structure, "channels", &channels);
6689 if ((channels > 0 && samplerate == 0)) {
6690 LOGD("exclude audio...");
6694 caps_str = gst_caps_to_string(caps);
6695 /* set it directly because not sent by TAG */
6696 if (g_strrstr(caps_str, "mobile-xmf"))
6697 mm_player_set_attribute((MMHandleType)player, NULL,
6698 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6700 MMPLAYER_FREEIF(caps_str);
6701 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6702 MMMessageParamType msg_param;
6703 memset(&msg_param, 0, sizeof(MMMessageParamType));
6704 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6705 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6706 LOGD("video file is not supported on this device");
6708 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6709 LOGD("already video linked");
6712 LOGD("found new stream");
6719 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6721 gboolean ret = FALSE;
6722 GDBusConnection *conn = NULL;
6724 GVariant *result = NULL;
6725 const gchar *dbus_device_type = NULL;
6726 const gchar *dbus_ret = NULL;
6729 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6731 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6736 result = g_dbus_connection_call_sync(conn,
6737 "org.pulseaudio.Server",
6738 "/org/pulseaudio/StreamManager",
6739 "org.pulseaudio.StreamManager",
6740 "GetCurrentMediaRoutingPath",
6741 g_variant_new("(s)", "out"),
6742 G_VARIANT_TYPE("(ss)"),
6743 G_DBUS_CALL_FLAGS_NONE,
6747 if (!result || err) {
6748 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6753 /* device type is listed in stream-map.json at mmfw-sysconf */
6754 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6756 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6757 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6760 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6761 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6762 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6763 LOGD("audio offload is supportable");
6769 LOGD("audio offload is not supportable");
6772 g_variant_unref(result);
6774 g_object_unref(conn);
6779 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6781 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6782 gint64 position = 0;
6784 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6785 player->pipeline && player->pipeline->mainbin);
6787 MMPLAYER_CMD_LOCK(player);
6788 current_state = MMPLAYER_CURRENT_STATE(player);
6790 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6791 LOGW("getting current position failed in paused");
6793 _mmplayer_unrealize((MMHandleType)player);
6794 _mmplayer_realize((MMHandleType)player);
6796 _mmplayer_set_position((MMHandleType)player, position);
6798 /* async not to be blocked in streaming case */
6799 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6801 _mmplayer_pause((MMHandleType)player);
6803 if (current_state == MM_PLAYER_STATE_PLAYING)
6804 _mmplayer_start((MMHandleType)player);
6805 MMPLAYER_CMD_UNLOCK(player);
6807 LOGD("rebuilding audio pipeline is completed.");
6810 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6812 mmplayer_t *player = (mmplayer_t *)user_data;
6813 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6814 gboolean is_supportable = FALSE;
6816 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6817 LOGW("failed to get device type");
6819 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6821 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6822 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6823 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6824 LOGD("ignore this dev connected info");
6828 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6829 if (player->build_audio_offload == is_supportable) {
6830 LOGD("keep current pipeline without re-building");
6834 /* rebuild pipeline */
6835 LOGD("re-build pipeline - offload: %d", is_supportable);
6836 player->build_audio_offload = FALSE;
6837 __mmplayer_rebuild_audio_pipeline(player);
6843 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6845 unsigned int id = 0;
6847 if (player->audio_device_cb_id != 0) {
6848 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6852 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6853 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6854 LOGD("added device connected cb (%u)", id);
6855 player->audio_device_cb_id = id;
6857 LOGW("failed to add device connected cb");
6864 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6866 mmplayer_t *player = (mmplayer_t *)hplayer;
6869 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6870 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6872 *activated = player->build_audio_offload;
6874 LOGD("offload activated : %d", (int)*activated);
6877 return MM_ERROR_NONE;
6881 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6884 this function need to be updated according to the supported media format
6885 @see player->ini.audio_offload_media_format */
6887 if (__mmplayer_is_only_mp3_type(player->type)) {
6888 LOGD("offload supportable media format type");
6896 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6898 gboolean ret = FALSE;
6899 GstElementFactory *factory = NULL;
6902 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6904 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6905 if (!__mmplayer_is_offload_supported_type(player))
6908 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6909 LOGD("there is no audio offload sink");
6913 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6914 LOGW("there is no audio device type to support offload");
6918 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6920 LOGW("there is no installed audio offload sink element");
6923 gst_object_unref(factory);
6925 if (__mmplayer_acquire_hw_resource(player,
6926 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6927 LOGE("failed to acquire audio offload decoder resource");
6931 if (!__mmplayer_add_audio_device_connected_cb(player))
6934 if (!__mmplayer_is_audio_offload_device_type(player))
6937 LOGD("audio offload can be built");
6942 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6948 static GstAutoplugSelectResult
6949 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6951 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6953 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6954 int audio_offload = 0;
6956 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6957 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6959 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6960 LOGD("expose audio path to build offload output path");
6961 player->build_audio_offload = TRUE;
6962 /* update codec info */
6963 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6964 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6965 player->audiodec_linked = 1;
6967 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6971 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6973 LOGD("audio codec type: %d", codec_type);
6974 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6975 /* sw codec will be skipped */
6976 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6977 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6978 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6979 ret = GST_AUTOPLUG_SELECT_SKIP;
6983 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6984 /* hw codec will be skipped */
6985 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6986 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6987 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6988 ret = GST_AUTOPLUG_SELECT_SKIP;
6993 /* set stream information */
6994 if (!player->audiodec_linked)
6995 __mmplayer_set_audio_attrs(player, caps);
6997 /* update codec info */
6998 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6999 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7000 player->audiodec_linked = 1;
7002 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7004 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7006 LOGD("video codec type: %d", codec_type);
7007 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7008 /* sw codec is skipped */
7009 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7010 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7011 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7012 ret = GST_AUTOPLUG_SELECT_SKIP;
7016 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7017 /* hw codec is skipped */
7018 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7019 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7020 ret = GST_AUTOPLUG_SELECT_SKIP;
7025 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7026 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7028 /* mark video decoder for acquire */
7029 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7030 LOGW("video decoder resource is already acquired, skip it.");
7031 ret = GST_AUTOPLUG_SELECT_SKIP;
7035 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7036 LOGE("failed to acquire video decoder resource");
7037 ret = GST_AUTOPLUG_SELECT_SKIP;
7040 player->interrupted_by_resource = FALSE;
7043 /* update codec info */
7044 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7045 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7046 player->videodec_linked = 1;
7054 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7055 GstCaps *caps, GstElementFactory *factory, gpointer data)
7057 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7058 mmplayer_t *player = (mmplayer_t *)data;
7060 gchar *factory_name = NULL;
7061 gchar *caps_str = NULL;
7062 const gchar *klass = NULL;
7065 factory_name = GST_OBJECT_NAME(factory);
7066 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7067 caps_str = gst_caps_to_string(caps);
7069 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7071 /* store type string */
7072 if (player->type == NULL) {
7073 player->type = gst_caps_to_string(caps);
7074 __mmplayer_update_content_type_info(player);
7077 /* filtering exclude keyword */
7078 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7079 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7080 LOGW("skipping [%s] by exculde keyword [%s]",
7081 factory_name, player->ini.exclude_element_keyword[idx]);
7083 result = GST_AUTOPLUG_SELECT_SKIP;
7088 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7089 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7090 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7091 factory_name, player->ini.unsupported_codec_keyword[idx]);
7092 result = GST_AUTOPLUG_SELECT_SKIP;
7097 /* exclude webm format */
7098 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7099 * because webm format is not supportable.
7100 * If webm is disabled in "autoplug-continue", there is no state change
7101 * failure or error because the decodebin will expose the pad directly.
7102 * It make MSL invoke _prepare_async_callback.
7103 * So, we need to disable webm format in "autoplug-select" */
7104 if (caps_str && strstr(caps_str, "webm")) {
7105 LOGW("webm is not supported");
7106 result = GST_AUTOPLUG_SELECT_SKIP;
7110 /* check factory class for filtering */
7111 /* NOTE : msl don't need to use image plugins.
7112 * So, those plugins should be skipped for error handling.
7114 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7115 LOGD("skipping [%s] by not required", factory_name);
7116 result = GST_AUTOPLUG_SELECT_SKIP;
7120 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7121 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7122 // TO CHECK : subtitle if needed, add subparse exception.
7123 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7124 result = GST_AUTOPLUG_SELECT_SKIP;
7128 if (g_strrstr(factory_name, "mpegpsdemux")) {
7129 LOGD("skipping PS container - not support");
7130 result = GST_AUTOPLUG_SELECT_SKIP;
7134 if (g_strrstr(factory_name, "mssdemux"))
7135 player->smooth_streaming = TRUE;
7137 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7138 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7141 GstStructure *str = NULL;
7142 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7144 /* don't make video because of not required */
7145 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7146 (!player->set_mode.video_export)) {
7147 LOGD("no need video decoding, expose pad");
7148 result = GST_AUTOPLUG_SELECT_EXPOSE;
7152 /* get w/h for omx state-tune */
7153 /* FIXME: deprecated? */
7154 str = gst_caps_get_structure(caps, 0);
7155 gst_structure_get_int(str, "width", &width);
7158 if (player->v_stream_caps) {
7159 gst_caps_unref(player->v_stream_caps);
7160 player->v_stream_caps = NULL;
7163 player->v_stream_caps = gst_caps_copy(caps);
7164 LOGD("take caps for video state tune");
7165 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7169 if (g_strrstr(klass, "Codec/Decoder")) {
7170 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7171 if (result != GST_AUTOPLUG_SELECT_TRY) {
7172 LOGW("skip add decoder");
7178 MMPLAYER_FREEIF(caps_str);
7184 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7187 //mmplayer_t *player = (mmplayer_t *)data;
7188 GstCaps *caps = NULL;
7190 LOGD("[Decodebin2] pad-removed signal");
7192 caps = gst_pad_query_caps(new_pad, NULL);
7194 LOGW("query caps is NULL");
7198 gchar *caps_str = NULL;
7199 caps_str = gst_caps_to_string(caps);
7201 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7203 MMPLAYER_FREEIF(caps_str);
7204 gst_caps_unref(caps);
7208 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7210 mmplayer_t *player = (mmplayer_t *)data;
7211 GstIterator *iter = NULL;
7212 GValue item = { 0, };
7214 gboolean done = FALSE;
7215 gboolean is_all_drained = TRUE;
7218 MMPLAYER_RETURN_IF_FAIL(player);
7220 LOGD("__mmplayer_gst_decode_drained");
7222 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7223 LOGW("Fail to get cmd lock");
7227 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7228 !__mmplayer_verify_gapless_play_path(player)) {
7229 LOGD("decoding is finished.");
7230 __mmplayer_reset_gapless_state(player);
7231 MMPLAYER_CMD_UNLOCK(player);
7235 player->gapless.reconfigure = TRUE;
7237 /* check decodebin src pads whether they received EOS or not */
7238 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7241 switch (gst_iterator_next(iter, &item)) {
7242 case GST_ITERATOR_OK:
7243 pad = g_value_get_object(&item);
7244 if (pad && !GST_PAD_IS_EOS(pad)) {
7245 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7246 is_all_drained = FALSE;
7249 g_value_reset(&item);
7251 case GST_ITERATOR_RESYNC:
7252 gst_iterator_resync(iter);
7254 case GST_ITERATOR_ERROR:
7255 case GST_ITERATOR_DONE:
7260 g_value_unset(&item);
7261 gst_iterator_free(iter);
7263 if (!is_all_drained) {
7264 LOGD("Wait util the all pads get EOS.");
7265 MMPLAYER_CMD_UNLOCK(player);
7270 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7271 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7273 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7274 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7275 __mmplayer_deactivate_old_path(player);
7276 MMPLAYER_CMD_UNLOCK(player);
7282 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7284 mmplayer_t *player = (mmplayer_t *)data;
7285 const gchar *klass = NULL;
7286 gchar *factory_name = NULL;
7288 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7289 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7291 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7293 if (__mmplayer_add_dump_buffer_probe(player, element))
7294 LOGD("add buffer probe");
7296 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7297 gchar *selected = NULL;
7298 selected = g_strdup(GST_ELEMENT_NAME(element));
7299 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7302 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7303 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7304 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7306 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7307 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7309 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7310 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7311 "max-video-width", player->adaptive_info.limit.width,
7312 "max-video-height", player->adaptive_info.limit.height, NULL);
7314 } else if (g_strrstr(klass, "Demuxer")) {
7316 LOGD("plugged element is demuxer. take it");
7318 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7319 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7322 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7323 int surface_type = 0;
7325 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7328 // to support trust-zone only
7329 if (g_strrstr(factory_name, "asfdemux")) {
7330 LOGD("set file-location %s", player->profile.uri);
7331 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7332 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7333 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7334 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7335 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7336 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7337 (__mmplayer_is_only_mp3_type(player->type))) {
7338 LOGD("[mpegaudioparse] set streaming pull mode.");
7339 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7341 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7342 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7345 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7346 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7347 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7349 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7350 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7352 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7353 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7354 (MMPLAYER_IS_DASH_STREAMING(player))) {
7355 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7356 _mm_player_streaming_set_multiqueue(player->streamer, element);
7357 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7366 __mmplayer_release_misc(mmplayer_t *player)
7369 bool cur_mode = player->set_mode.rich_audio;
7372 MMPLAYER_RETURN_IF_FAIL(player);
7374 player->video_decoded_cb = NULL;
7375 player->video_decoded_cb_user_param = NULL;
7376 player->video_stream_prerolled = false;
7378 player->audio_decoded_cb = NULL;
7379 player->audio_decoded_cb_user_param = NULL;
7380 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7382 player->audio_stream_changed_cb = NULL;
7383 player->audio_stream_changed_cb_user_param = NULL;
7385 player->sent_bos = FALSE;
7386 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7388 player->seek_state = MMPLAYER_SEEK_NONE;
7390 player->total_bitrate = 0;
7391 player->total_maximum_bitrate = 0;
7393 player->not_found_demuxer = 0;
7395 player->last_position = 0;
7396 player->duration = 0;
7397 player->http_content_size = 0;
7398 player->not_supported_codec = MISSING_PLUGIN_NONE;
7399 player->can_support_codec = FOUND_PLUGIN_NONE;
7400 player->pending_seek.is_pending = false;
7401 player->pending_seek.pos = 0;
7402 player->msg_posted = FALSE;
7403 player->has_many_types = FALSE;
7404 player->is_subtitle_force_drop = FALSE;
7405 player->play_subtitle = FALSE;
7406 player->adjust_subtitle_pos = 0;
7407 player->has_closed_caption = FALSE;
7408 player->set_mode.video_export = false;
7409 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7410 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7412 player->set_mode.rich_audio = cur_mode;
7414 if (player->audio_device_cb_id > 0 &&
7415 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7416 LOGW("failed to remove audio device_connected_callback");
7417 player->audio_device_cb_id = 0;
7419 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7420 player->bitrate[i] = 0;
7421 player->maximum_bitrate[i] = 0;
7424 /* free memory related to audio effect */
7425 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7427 if (player->adaptive_info.var_list) {
7428 g_list_free_full(player->adaptive_info.var_list, g_free);
7429 player->adaptive_info.var_list = NULL;
7432 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7433 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7434 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7436 /* Reset video360 settings to their defaults in case if the pipeline is to be
7439 player->video360_metadata.is_spherical = -1;
7440 player->is_openal_plugin_used = FALSE;
7442 player->is_content_spherical = FALSE;
7443 player->is_video360_enabled = TRUE;
7444 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7445 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7446 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7447 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7448 player->video360_zoom = 1.0f;
7449 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7450 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7452 player->sound.rg_enable = false;
7454 __mmplayer_initialize_video_roi(player);
7459 __mmplayer_release_misc_post(mmplayer_t *player)
7461 char *original_uri = NULL;
7464 /* player->pipeline is already released before. */
7466 MMPLAYER_RETURN_IF_FAIL(player);
7468 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7470 /* clean found audio decoders */
7471 if (player->audio_decoders) {
7472 GList *a_dec = player->audio_decoders;
7473 for (; a_dec; a_dec = g_list_next(a_dec)) {
7474 gchar *name = a_dec->data;
7475 MMPLAYER_FREEIF(name);
7477 g_list_free(player->audio_decoders);
7478 player->audio_decoders = NULL;
7481 /* clean the uri list except original uri */
7482 if (player->uri_info.uri_list) {
7483 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7486 LOGW("failed to get original uri info");
7488 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7489 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7491 GList *uri_list = player->uri_info.uri_list;
7492 for (; uri_list; uri_list = g_list_next(uri_list)) {
7493 gchar *uri = uri_list->data;
7494 MMPLAYER_FREEIF(uri);
7496 g_list_free(player->uri_info.uri_list);
7497 player->uri_info.uri_list = NULL;
7500 /* clear the audio stream buffer list */
7501 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7503 /* clear the video stream bo list */
7504 __mmplayer_video_stream_destroy_bo_list(player);
7505 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7507 if (player->profile.input_mem.buf) {
7508 free(player->profile.input_mem.buf);
7509 player->profile.input_mem.buf = NULL;
7511 player->profile.input_mem.len = 0;
7512 player->profile.input_mem.offset = 0;
7514 player->uri_info.uri_idx = 0;
7519 __mmplayer_check_subtitle(mmplayer_t *player)
7521 MMHandleType attrs = 0;
7522 char *subtitle_uri = NULL;
7526 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7528 /* get subtitle attribute */
7529 attrs = MMPLAYER_GET_ATTRS(player);
7533 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7534 if (!subtitle_uri || !strlen(subtitle_uri))
7537 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7538 player->is_external_subtitle_present = TRUE;
7546 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7548 MMPLAYER_RETURN_IF_FAIL(player);
7550 if (player->eos_timer) {
7551 LOGD("cancel eos timer");
7552 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7553 player->eos_timer = 0;
7560 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7564 MMPLAYER_RETURN_IF_FAIL(player);
7565 MMPLAYER_RETURN_IF_FAIL(sink);
7567 player->sink_elements = g_list_append(player->sink_elements, sink);
7573 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7577 MMPLAYER_RETURN_IF_FAIL(player);
7578 MMPLAYER_RETURN_IF_FAIL(sink);
7580 player->sink_elements = g_list_remove(player->sink_elements, sink);
7586 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7587 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7589 mmplayer_signal_item_t *item = NULL;
7592 MMPLAYER_RETURN_IF_FAIL(player);
7594 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7595 LOGE("invalid signal type [%d]", type);
7599 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7601 LOGE("cannot connect signal [%s]", signal);
7606 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7607 player->signals[type] = g_list_append(player->signals[type], item);
7613 /* NOTE : be careful with calling this api. please refer to below glib comment
7614 * glib comment : Note that there is a bug in GObject that makes this function much
7615 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7616 * will no longer be called, but, the signal handler is not currently disconnected.
7617 * If the instance is itself being freed at the same time than this doesn't matter,
7618 * since the signal will automatically be removed, but if instance persists,
7619 * then the signal handler will leak. You should not remove the signal yourself
7620 * because in a future versions of GObject, the handler will automatically be
7623 * It's possible to work around this problem in a way that will continue to work
7624 * with future versions of GObject by checking that the signal handler is still
7625 * connected before disconnected it:
7627 * if (g_signal_handler_is_connected(instance, id))
7628 * g_signal_handler_disconnect(instance, id);
7631 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7633 GList *sig_list = NULL;
7634 mmplayer_signal_item_t *item = NULL;
7638 MMPLAYER_RETURN_IF_FAIL(player);
7640 LOGD("release signals type : %d", type);
7642 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7643 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7644 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7645 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7646 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7647 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7651 sig_list = player->signals[type];
7653 for (; sig_list; sig_list = sig_list->next) {
7654 item = sig_list->data;
7656 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7657 if (g_signal_handler_is_connected(item->obj, item->sig))
7658 g_signal_handler_disconnect(item->obj, item->sig);
7661 MMPLAYER_FREEIF(item);
7664 g_list_free(player->signals[type]);
7665 player->signals[type] = NULL;
7673 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7675 mmplayer_t *player = 0;
7676 int prev_display_surface_type = 0;
7680 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7682 player = MM_PLAYER_CAST(handle);
7684 /* check video sinkbin is created */
7685 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7686 LOGW("Videosink is already created");
7687 return MM_ERROR_NONE;
7690 LOGD("videosink element is not yet ready");
7692 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7693 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7695 return MM_ERROR_INVALID_ARGUMENT;
7698 /* load previous attributes */
7699 if (player->attrs) {
7700 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7701 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7702 if (prev_display_surface_type == surface_type) {
7703 LOGD("incoming display surface type is same as previous one, do nothing..");
7705 return MM_ERROR_NONE;
7708 LOGE("failed to load attributes");
7710 return MM_ERROR_PLAYER_INTERNAL;
7713 /* videobin is not created yet, so we just set attributes related to display surface */
7714 LOGD("store display attribute for given surface type(%d)", surface_type);
7715 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7716 "display_overlay", wl_surface_id, NULL);
7719 return MM_ERROR_NONE;
7722 /* Note : if silent is true, then subtitle would not be displayed. :*/
7724 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7726 mmplayer_t *player = (mmplayer_t *)hplayer;
7730 /* check player handle */
7731 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7733 player->set_mode.subtitle_off = silent;
7735 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7739 return MM_ERROR_NONE;
7743 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7745 mmplayer_gst_element_t *mainbin = NULL;
7746 mmplayer_gst_element_t *textbin = NULL;
7747 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7748 GstState current_state = GST_STATE_VOID_PENDING;
7749 GstState element_state = GST_STATE_VOID_PENDING;
7750 GstState element_pending_state = GST_STATE_VOID_PENDING;
7752 GstEvent *event = NULL;
7753 int result = MM_ERROR_NONE;
7755 GstClock *curr_clock = NULL;
7756 GstClockTime base_time, start_time, curr_time;
7761 /* check player handle */
7762 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7764 player->pipeline->mainbin &&
7765 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7767 mainbin = player->pipeline->mainbin;
7768 textbin = player->pipeline->textbin;
7770 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7772 // sync clock with current pipeline
7773 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7774 curr_time = gst_clock_get_time(curr_clock);
7776 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7777 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7779 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7780 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7782 if (current_state > GST_STATE_READY) {
7783 // sync state with current pipeline
7784 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7785 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7786 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7788 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7789 if (GST_STATE_CHANGE_FAILURE == ret) {
7790 LOGE("fail to state change.");
7791 result = MM_ERROR_PLAYER_INTERNAL;
7795 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7796 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7799 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7800 gst_object_unref(curr_clock);
7803 // seek to current position
7804 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7805 result = MM_ERROR_PLAYER_INVALID_STATE;
7806 LOGE("gst_element_query_position failed, invalid state");
7810 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7811 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);
7813 _mmplayer_gst_send_event_to_sink(player, event);
7815 result = MM_ERROR_PLAYER_INTERNAL;
7816 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7820 /* sync state with current pipeline */
7821 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7822 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7823 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7825 return MM_ERROR_NONE;
7828 /* release text pipeline resource */
7829 player->textsink_linked = 0;
7831 /* release signal */
7832 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7834 /* release textbin with it's childs */
7835 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7836 MMPLAYER_FREEIF(player->pipeline->textbin);
7837 player->pipeline->textbin = NULL;
7839 /* release subtitle elem */
7840 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7841 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7847 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7849 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7850 GstState current_state = GST_STATE_VOID_PENDING;
7852 MMHandleType attrs = 0;
7853 mmplayer_gst_element_t *mainbin = NULL;
7854 mmplayer_gst_element_t *textbin = NULL;
7856 gchar *subtitle_uri = NULL;
7857 int result = MM_ERROR_NONE;
7858 const gchar *charset = NULL;
7862 /* check player handle */
7863 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7865 player->pipeline->mainbin &&
7866 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7867 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7869 mainbin = player->pipeline->mainbin;
7870 textbin = player->pipeline->textbin;
7872 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7873 if (current_state < GST_STATE_READY) {
7874 result = MM_ERROR_PLAYER_INVALID_STATE;
7875 LOGE("Pipeline is not in proper state");
7879 attrs = MMPLAYER_GET_ATTRS(player);
7881 LOGE("cannot get content attribute");
7882 result = MM_ERROR_PLAYER_INTERNAL;
7886 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7887 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7888 LOGE("subtitle uri is not proper filepath");
7889 result = MM_ERROR_PLAYER_INVALID_URI;
7893 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7894 LOGE("failed to get storage info of subtitle path");
7895 result = MM_ERROR_PLAYER_INVALID_URI;
7899 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7900 SECURE_LOGD("new subtitle file path is [%s]", filepath);
7902 if (!strcmp(filepath, subtitle_uri)) {
7903 LOGD("subtitle path is not changed");
7906 if (mm_player_set_attribute((MMHandleType)player, NULL,
7907 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7908 LOGE("failed to set attribute");
7913 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7914 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7915 player->subtitle_language_list = NULL;
7916 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7918 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7919 if (ret != GST_STATE_CHANGE_SUCCESS) {
7920 LOGE("failed to change state of textbin to READY");
7921 result = MM_ERROR_PLAYER_INTERNAL;
7925 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7926 if (ret != GST_STATE_CHANGE_SUCCESS) {
7927 LOGE("failed to change state of subparse to READY");
7928 result = MM_ERROR_PLAYER_INTERNAL;
7932 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7933 if (ret != GST_STATE_CHANGE_SUCCESS) {
7934 LOGE("failed to change state of filesrc to READY");
7935 result = MM_ERROR_PLAYER_INTERNAL;
7939 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7941 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7943 charset = _mmplayer_get_charset(filepath);
7945 LOGD("detected charset is %s", charset);
7946 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7949 result = _mmplayer_sync_subtitle_pipeline(player);
7956 /* API to switch between external subtitles */
7958 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7960 int result = MM_ERROR_NONE;
7961 mmplayer_t *player = (mmplayer_t *)hplayer;
7966 /* check player handle */
7967 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7969 /* filepath can be null in idle state */
7971 /* check file path */
7972 if ((path = strstr(filepath, "file://")))
7973 result = _mmplayer_exist_file_path(path + 7);
7975 result = _mmplayer_exist_file_path(filepath);
7977 if (result != MM_ERROR_NONE) {
7978 LOGE("invalid subtitle path 0x%X", result);
7979 return result; /* file not found or permission denied */
7983 if (!player->pipeline) {
7985 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
7986 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
7987 LOGE("failed to set attribute");
7988 return MM_ERROR_PLAYER_INTERNAL;
7991 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7992 /* check filepath */
7993 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7995 if (!__mmplayer_check_subtitle(player)) {
7996 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
7997 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7998 LOGE("failed to set attribute");
7999 return MM_ERROR_PLAYER_INTERNAL;
8002 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8003 LOGE("fail to create text pipeline");
8004 return MM_ERROR_PLAYER_INTERNAL;
8007 result = _mmplayer_sync_subtitle_pipeline(player);
8009 result = __mmplayer_change_external_subtitle_language(player, filepath);
8012 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8013 player->is_external_subtitle_added_now = TRUE;
8015 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8016 if (!player->subtitle_language_list) {
8017 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8018 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8019 LOGW("subtitle language list is not updated yet");
8021 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8029 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8031 int result = MM_ERROR_NONE;
8032 gchar *change_pad_name = NULL;
8033 GstPad *sinkpad = NULL;
8034 mmplayer_gst_element_t *mainbin = NULL;
8035 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8036 GstCaps *caps = NULL;
8037 gint total_track_num = 0;
8041 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8042 MM_ERROR_PLAYER_NOT_INITIALIZED);
8044 LOGD("Change Track(%d) to %d", type, index);
8046 mainbin = player->pipeline->mainbin;
8048 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8049 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8050 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8051 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8053 /* Changing Video Track is not supported. */
8054 LOGE("Track Type Error");
8058 if (mainbin[elem_idx].gst == NULL) {
8059 result = MM_ERROR_PLAYER_NO_OP;
8060 LOGD("Req track doesn't exist");
8064 total_track_num = player->selector[type].total_track_num;
8065 if (total_track_num <= 0) {
8066 result = MM_ERROR_PLAYER_NO_OP;
8067 LOGD("Language list is not available");
8071 if ((index < 0) || (index >= total_track_num)) {
8072 result = MM_ERROR_INVALID_ARGUMENT;
8073 LOGD("Not a proper index : %d", index);
8077 /*To get the new pad from the selector*/
8078 change_pad_name = g_strdup_printf("sink_%u", index);
8079 if (change_pad_name == NULL) {
8080 result = MM_ERROR_PLAYER_INTERNAL;
8081 LOGD("Pad does not exists");
8085 LOGD("new active pad name: %s", change_pad_name);
8087 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8088 if (sinkpad == NULL) {
8089 LOGD("sinkpad is NULL");
8090 result = MM_ERROR_PLAYER_INTERNAL;
8094 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8095 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8097 caps = gst_pad_get_current_caps(sinkpad);
8098 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8101 gst_object_unref(sinkpad);
8103 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8104 __mmplayer_set_audio_attrs(player, caps);
8107 MMPLAYER_FREEIF(change_pad_name);
8112 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8114 int result = MM_ERROR_NONE;
8115 mmplayer_t *player = NULL;
8116 mmplayer_gst_element_t *mainbin = NULL;
8118 gint current_active_index = 0;
8120 GstState current_state = GST_STATE_VOID_PENDING;
8121 GstEvent *event = NULL;
8126 player = (mmplayer_t *)hplayer;
8127 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8129 if (!player->pipeline) {
8130 LOGE("Track %d pre setting -> %d", type, index);
8132 player->selector[type].active_pad_index = index;
8136 mainbin = player->pipeline->mainbin;
8138 current_active_index = player->selector[type].active_pad_index;
8140 /*If index is same as running index no need to change the pad*/
8141 if (current_active_index == index)
8144 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8145 result = MM_ERROR_PLAYER_INVALID_STATE;
8149 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8150 if (current_state < GST_STATE_PAUSED) {
8151 result = MM_ERROR_PLAYER_INVALID_STATE;
8152 LOGW("Pipeline not in porper state");
8156 result = __mmplayer_change_selector_pad(player, type, index);
8157 if (result != MM_ERROR_NONE) {
8158 LOGE("change selector pad error");
8162 player->selector[type].active_pad_index = index;
8164 if (current_state == GST_STATE_PLAYING) {
8165 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8166 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8167 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8169 _mmplayer_gst_send_event_to_sink(player, event);
8171 result = MM_ERROR_PLAYER_INTERNAL;
8181 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8183 mmplayer_t *player = (mmplayer_t *)hplayer;
8187 /* check player handle */
8188 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8190 *silent = player->set_mode.subtitle_off;
8192 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8196 return MM_ERROR_NONE;
8200 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8202 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8203 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8205 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8206 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8210 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8211 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8212 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8213 mmplayer_dump_t *dump_s;
8214 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8215 if (dump_s == NULL) {
8216 LOGE("malloc fail");
8220 dump_s->dump_element_file = NULL;
8221 dump_s->dump_pad = NULL;
8222 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8224 if (dump_s->dump_pad) {
8225 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8226 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]);
8227 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8228 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);
8229 /* add list for removed buffer probe and close FILE */
8230 player->dump_list = g_list_append(player->dump_list, dump_s);
8231 LOGD("%s sink pad added buffer probe for dump", factory_name);
8234 MMPLAYER_FREEIF(dump_s);
8235 LOGE("failed to get %s sink pad added", factory_name);
8242 static GstPadProbeReturn
8243 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8245 FILE *dump_data = (FILE *)u_data;
8247 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8248 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8250 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8252 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8254 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8256 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8258 gst_buffer_unmap(buffer, &probe_info);
8260 return GST_PAD_PROBE_OK;
8264 __mmplayer_release_dump_list(GList *dump_list)
8266 GList *d_list = dump_list;
8271 for (; d_list; d_list = g_list_next(d_list)) {
8272 mmplayer_dump_t *dump_s = d_list->data;
8273 if (dump_s->dump_pad) {
8274 if (dump_s->probe_handle_id)
8275 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8276 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8278 if (dump_s->dump_element_file) {
8279 fclose(dump_s->dump_element_file);
8280 dump_s->dump_element_file = NULL;
8282 MMPLAYER_FREEIF(dump_s);
8284 g_list_free(dump_list);
8289 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8291 mmplayer_t *player = (mmplayer_t *)hplayer;
8295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8296 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8298 *exist = (bool)player->has_closed_caption;
8302 return MM_ERROR_NONE;
8306 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8311 LOGD("unref internal gst buffer %p", buffer);
8313 gst_buffer_unref((GstBuffer *)buffer);
8320 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8322 mmplayer_t *player = (mmplayer_t *)hplayer;
8326 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8327 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8329 if (MMPLAYER_IS_STREAMING(player))
8330 *timeout = (int)player->ini.live_state_change_timeout;
8332 *timeout = (int)player->ini.localplayback_state_change_timeout;
8334 LOGD("timeout = %d", *timeout);
8337 return MM_ERROR_NONE;
8341 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8345 MMPLAYER_RETURN_IF_FAIL(player);
8347 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8349 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8350 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8351 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8352 player->storage_info[i].id = -1;
8353 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8355 if (path_type != MMPLAYER_PATH_MAX)
8364 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8366 int ret = MM_ERROR_NONE;
8367 mmplayer_t *player = (mmplayer_t *)hplayer;
8368 MMMessageParamType msg_param = {0, };
8371 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8373 LOGW("state changed storage %d:%d", id, state);
8375 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8376 return MM_ERROR_NONE;
8378 /* FIXME: text path should be handled seperately. */
8379 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8380 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8381 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8382 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8383 LOGW("external storage is removed");
8385 if (player->msg_posted == FALSE) {
8386 memset(&msg_param, 0, sizeof(MMMessageParamType));
8387 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8388 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8389 player->msg_posted = TRUE;
8392 /* unrealize the player */
8393 ret = _mmplayer_unrealize(hplayer);
8394 if (ret != MM_ERROR_NONE)
8395 LOGE("failed to unrealize");
8403 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8405 int ret = MM_ERROR_NONE;
8406 mmplayer_t *player = (mmplayer_t *)hplayer;
8407 int idx = 0, total = 0;
8408 gchar *result = NULL, *tmp = NULL;
8411 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8412 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8414 total = *num = g_list_length(player->adaptive_info.var_list);
8416 LOGW("There is no stream variant info.");
8420 result = g_strdup("");
8421 for (idx = 0 ; idx < total ; idx++) {
8422 stream_variant_t *v_data = NULL;
8423 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8426 gchar data[64] = {0};
8427 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8429 tmp = g_strconcat(result, data, NULL);
8433 LOGW("There is no variant data in %d", idx);
8438 *var_info = (char *)result;
8440 LOGD("variant info %d:%s", *num, *var_info);
8446 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8448 int ret = MM_ERROR_NONE;
8449 mmplayer_t *player = (mmplayer_t *)hplayer;
8452 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8454 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8456 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8457 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8458 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8460 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8461 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8462 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8463 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8465 /* FIXME: seek to current position for applying new variant limitation */
8474 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8476 int ret = MM_ERROR_NONE;
8477 mmplayer_t *player = (mmplayer_t *)hplayer;
8480 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8481 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8483 *bandwidth = player->adaptive_info.limit.bandwidth;
8484 *width = player->adaptive_info.limit.width;
8485 *height = player->adaptive_info.limit.height;
8487 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8494 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8496 int ret = MM_ERROR_NONE;
8497 mmplayer_t *player = (mmplayer_t *)hplayer;
8500 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8501 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8502 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8504 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8506 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8507 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8508 else /* live case */
8509 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8511 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8518 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8520 #define IDX_FIRST_SW_CODEC 0
8521 mmplayer_t *player = (mmplayer_t *)hplayer;
8522 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8525 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8527 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8528 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8529 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8531 switch (stream_type) {
8532 case MM_PLAYER_STREAM_TYPE_AUDIO:
8533 /* to support audio codec selection, codec info have to be added in ini file as below.
8534 audio codec element hw = xxxx
8535 audio codec element sw = avdec */
8536 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8537 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8538 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8539 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8540 LOGE("There is no audio codec info for codec_type %d", codec_type);
8541 return MM_ERROR_PLAYER_NO_OP;
8544 case MM_PLAYER_STREAM_TYPE_VIDEO:
8545 /* to support video codec selection, codec info have to be added in ini file as below.
8546 video codec element hw = omx
8547 video codec element sw = avdec */
8548 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8549 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8550 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8551 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8552 LOGE("There is no video codec info for codec_type %d", codec_type);
8553 return MM_ERROR_PLAYER_NO_OP;
8557 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8558 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8562 LOGD("update %s codec_type to %d", attr_name, codec_type);
8563 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8566 return MM_ERROR_NONE;
8570 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8572 mmplayer_t *player = (mmplayer_t *)hplayer;
8573 GstElement *rg_vol_element = NULL;
8577 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8579 player->sound.rg_enable = enabled;
8581 /* just hold rgvolume enable value if pipeline is not ready */
8582 if (!player->pipeline || !player->pipeline->audiobin) {
8583 LOGD("pipeline is not ready. holding rgvolume enable value");
8584 return MM_ERROR_NONE;
8587 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8589 if (!rg_vol_element) {
8590 LOGD("rgvolume element is not created");
8591 return MM_ERROR_PLAYER_INTERNAL;
8595 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8597 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8601 return MM_ERROR_NONE;
8605 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8607 mmplayer_t *player = (mmplayer_t *)hplayer;
8608 GstElement *rg_vol_element = NULL;
8609 gboolean enable = FALSE;
8613 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8614 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8616 /* just hold enable_rg value if pipeline is not ready */
8617 if (!player->pipeline || !player->pipeline->audiobin) {
8618 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8619 *enabled = player->sound.rg_enable;
8620 return MM_ERROR_NONE;
8623 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8625 if (!rg_vol_element) {
8626 LOGD("rgvolume element is not created");
8627 return MM_ERROR_PLAYER_INTERNAL;
8630 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8631 *enabled = (bool)enable;
8635 return MM_ERROR_NONE;
8639 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8641 mmplayer_t *player = (mmplayer_t *)hplayer;
8642 MMHandleType attrs = 0;
8644 int ret = MM_ERROR_NONE;
8648 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8650 attrs = MMPLAYER_GET_ATTRS(player);
8651 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8653 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8655 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8656 return MM_ERROR_PLAYER_INTERNAL;
8659 player->video_roi.scale_x = scale_x;
8660 player->video_roi.scale_y = scale_y;
8661 player->video_roi.scale_width = scale_width;
8662 player->video_roi.scale_height = scale_height;
8664 /* check video sinkbin is created */
8665 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8666 return MM_ERROR_NONE;
8668 if (!gst_video_overlay_set_video_roi_area(
8669 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8670 scale_x, scale_y, scale_width, scale_height))
8671 ret = MM_ERROR_PLAYER_INTERNAL;
8673 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8674 scale_x, scale_y, scale_width, scale_height);
8682 _mmplayer_get_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 int ret = MM_ERROR_NONE;
8689 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8690 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8692 *scale_x = player->video_roi.scale_x;
8693 *scale_y = player->video_roi.scale_y;
8694 *scale_width = player->video_roi.scale_width;
8695 *scale_height = player->video_roi.scale_height;
8697 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8698 *scale_x, *scale_y, *scale_width, *scale_height);
8704 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8706 mmplayer_t* player = (mmplayer_t*)hplayer;
8710 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8712 player->client_pid = pid;
8714 LOGD("client pid[%d] %p", pid, player);
8718 return MM_ERROR_NONE;
8722 __mmplayer_update_duration_value(mmplayer_t *player)
8724 gboolean ret = FALSE;
8725 gint64 dur_nsec = 0;
8726 LOGD("try to update duration");
8728 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8729 player->duration = dur_nsec;
8730 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8734 if (player->duration < 0) {
8735 LOGW("duration is Non-Initialized !!!");
8736 player->duration = 0;
8739 /* update streaming service type */
8740 player->streaming_type = _mmplayer_get_stream_service_type(player);
8742 /* check duration is OK */
8743 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8744 /* FIXIT : find another way to get duration here. */
8745 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8751 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8753 /* update audio params
8754 NOTE : We need original audio params and it can be only obtained from src pad of audio
8755 decoder. Below code only valid when we are not using 'resampler' just before
8756 'audioconverter'. */
8757 GstCaps *caps_a = NULL;
8759 gint samplerate = 0, channels = 0;
8760 GstStructure *p = NULL;
8761 GstElement *aconv = NULL;
8763 LOGD("try to update audio attrs");
8765 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8767 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8768 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8769 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8770 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8772 LOGE("there is no audio converter");
8776 pad = gst_element_get_static_pad(aconv, "sink");
8779 LOGW("failed to get pad from audio converter");
8783 caps_a = gst_pad_get_current_caps(pad);
8785 LOGW("not ready to get audio caps");
8786 gst_object_unref(pad);
8790 p = gst_caps_get_structure(caps_a, 0);
8792 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8794 gst_structure_get_int(p, "rate", &samplerate);
8795 gst_structure_get_int(p, "channels", &channels);
8797 mm_player_set_attribute((MMHandleType)player, NULL,
8798 "content_audio_samplerate", samplerate,
8799 "content_audio_channels", channels, NULL);
8801 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8803 gst_caps_unref(caps_a);
8804 gst_object_unref(pad);
8810 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8812 LOGD("try to update video attrs");
8814 GstCaps *caps_v = NULL;
8818 GstStructure *p = NULL;
8820 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8821 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8823 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8825 LOGD("no videosink sink pad");
8829 caps_v = gst_pad_get_current_caps(pad);
8830 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8831 if (!caps_v && player->v_stream_caps) {
8832 caps_v = player->v_stream_caps;
8833 gst_caps_ref(caps_v);
8837 LOGD("no negitiated caps from videosink");
8838 gst_object_unref(pad);
8842 p = gst_caps_get_structure(caps_v, 0);
8843 gst_structure_get_int(p, "width", &width);
8844 gst_structure_get_int(p, "height", &height);
8846 mm_player_set_attribute((MMHandleType)player, NULL,
8847 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
8849 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8851 SECURE_LOGD("width : %d height : %d", width, height);
8853 gst_caps_unref(caps_v);
8854 gst_object_unref(pad);
8857 mm_player_set_attribute((MMHandleType)player, NULL,
8858 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
8859 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8866 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8868 gboolean ret = FALSE;
8869 guint64 data_size = 0;
8873 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8874 if (!player->duration)
8877 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8878 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8879 if (stat(path, &sb) == 0)
8880 data_size = (guint64)sb.st_size;
8882 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8883 data_size = player->http_content_size;
8886 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8889 guint64 bitrate = 0;
8890 guint64 msec_dur = 0;
8892 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8894 bitrate = data_size * 8 * 1000 / msec_dur;
8895 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
8896 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8897 mm_player_set_attribute((MMHandleType)player, NULL,
8898 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
8901 LOGD("player duration is less than 0");
8905 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8906 if (player->total_bitrate) {
8907 mm_player_set_attribute((MMHandleType)player, NULL,
8908 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
8917 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8919 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8920 data->uri_type = uri_type;
8924 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8926 int ret = MM_ERROR_PLAYER_INVALID_URI;
8928 char *buffer = NULL;
8929 char *seperator = strchr(path, ',');
8930 char ext[100] = {0,}, size[100] = {0,};
8933 if ((buffer = strstr(path, "ext="))) {
8934 buffer += strlen("ext=");
8936 if (strlen(buffer)) {
8937 strncpy(ext, buffer, 99);
8939 if ((seperator = strchr(ext, ','))
8940 || (seperator = strchr(ext, ' '))
8941 || (seperator = strchr(ext, '\0'))) {
8942 seperator[0] = '\0';
8947 if ((buffer = strstr(path, "size="))) {
8948 buffer += strlen("size=");
8950 if (strlen(buffer) > 0) {
8951 strncpy(size, buffer, 99);
8953 if ((seperator = strchr(size, ','))
8954 || (seperator = strchr(size, ' '))
8955 || (seperator = strchr(size, '\0'))) {
8956 seperator[0] = '\0';
8959 mem_size = atoi(size);
8964 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8966 if (mem_size && param) {
8967 if (data->input_mem.buf)
8968 free(data->input_mem.buf);
8969 data->input_mem.buf = malloc(mem_size);
8971 if (data->input_mem.buf) {
8972 memcpy(data->input_mem.buf, param, mem_size);
8973 data->input_mem.len = mem_size;
8974 ret = MM_ERROR_NONE;
8976 LOGE("failed to alloc mem %d", mem_size);
8977 ret = MM_ERROR_PLAYER_INTERNAL;
8980 data->input_mem.offset = 0;
8981 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8988 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
8990 gchar *location = NULL;
8993 int ret = MM_ERROR_NONE;
8995 if ((path = strstr(uri, "file://"))) {
8996 location = g_filename_from_uri(uri, NULL, &err);
8997 if (!location || (err != NULL)) {
8998 LOGE("Invalid URI '%s' for filesrc: %s", path,
8999 (err != NULL) ? err->message : "unknown error");
9003 MMPLAYER_FREEIF(location);
9005 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9006 return MM_ERROR_PLAYER_INVALID_URI;
9008 LOGD("path from uri: %s", location);
9011 path = (location != NULL) ? (location) : ((char *)uri);
9014 ret = _mmplayer_exist_file_path(path);
9016 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9017 if (ret == MM_ERROR_NONE) {
9018 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9019 if (_mmplayer_is_sdp_file(path)) {
9020 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9021 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9023 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9025 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9026 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9028 LOGE("invalid uri, could not play..");
9029 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9032 MMPLAYER_FREEIF(location);
9037 static mmplayer_video_decoded_data_info_t *
9038 __mmplayer_create_stream_from_pad(GstPad *pad)
9040 GstCaps *caps = NULL;
9041 GstStructure *structure = NULL;
9042 unsigned int fourcc = 0;
9043 const gchar *string_format = NULL;
9044 mmplayer_video_decoded_data_info_t *stream = NULL;
9046 MMPixelFormatType format;
9049 caps = gst_pad_get_current_caps(pad);
9051 LOGE("Caps is NULL.");
9056 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9058 structure = gst_caps_get_structure(caps, 0);
9059 gst_structure_get_int(structure, "width", &width);
9060 gst_structure_get_int(structure, "height", &height);
9061 string_format = gst_structure_get_string(structure, "format");
9064 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9065 format = _mmplayer_get_pixtype(fourcc);
9066 gst_video_info_from_caps(&info, caps);
9067 gst_caps_unref(caps);
9070 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9071 LOGE("Wrong condition!!");
9075 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9077 LOGE("failed to alloc mem for video data");
9081 stream->width = width;
9082 stream->height = height;
9083 stream->format = format;
9084 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9090 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9092 unsigned int pitch = 0;
9093 unsigned int size = 0;
9095 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9098 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9099 bo = gst_tizen_memory_get_bos(mem, index);
9101 stream->bo[index] = tbm_bo_ref(bo);
9103 LOGE("failed to get bo for index %d", index);
9106 for (index = 0; index < stream->plane_num; index++) {
9107 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9108 stream->stride[index] = pitch;
9110 stream->elevation[index] = size / pitch;
9112 stream->elevation[index] = stream->height;
9117 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9119 if (stream->format == MM_PIXEL_FORMAT_I420) {
9120 int ret = TBM_SURFACE_ERROR_NONE;
9121 tbm_surface_h surface;
9122 tbm_surface_info_s info;
9124 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9126 ret = tbm_surface_get_info(surface, &info);
9127 if (ret != TBM_SURFACE_ERROR_NONE) {
9128 tbm_surface_destroy(surface);
9132 tbm_surface_destroy(surface);
9133 stream->stride[0] = info.planes[0].stride;
9134 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9135 stream->stride[1] = info.planes[1].stride;
9136 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9137 stream->stride[2] = info.planes[2].stride;
9138 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9139 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9140 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9141 stream->stride[0] = stream->width * 4;
9142 stream->elevation[0] = stream->height;
9143 stream->bo_size = stream->stride[0] * stream->height;
9145 LOGE("Not support format %d", stream->format);
9153 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9155 tbm_bo_handle thandle;
9157 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9158 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9159 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9163 unsigned char *src = NULL;
9164 unsigned char *dest = NULL;
9165 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9167 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9169 LOGE("fail to gst_memory_map");
9173 if (!mapinfo.data) {
9174 LOGE("data pointer is wrong");
9178 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9179 if (!stream->bo[0]) {
9180 LOGE("Fail to tbm_bo_alloc!!");
9184 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9186 LOGE("thandle pointer is wrong");
9190 if (stream->format == MM_PIXEL_FORMAT_I420) {
9191 src_stride[0] = GST_ROUND_UP_4(stream->width);
9192 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9193 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9194 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9197 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9198 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9200 for (i = 0; i < 3; i++) {
9201 src = mapinfo.data + src_offset[i];
9202 dest = thandle.ptr + dest_offset[i];
9207 for (j = 0; j < stream->height >> k; j++) {
9208 memcpy(dest, src, stream->width>>k);
9209 src += src_stride[i];
9210 dest += stream->stride[i];
9213 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9214 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9216 LOGE("Not support format %d", stream->format);
9220 tbm_bo_unmap(stream->bo[0]);
9221 gst_memory_unmap(mem, &mapinfo);
9227 tbm_bo_unmap(stream->bo[0]);
9230 gst_memory_unmap(mem, &mapinfo);
9236 __mmplayer_set_pause_state(mmplayer_t *player)
9238 if (player->sent_bos)
9241 /* rtsp case, get content attrs by GstMessage */
9242 if (MMPLAYER_IS_RTSP_STREAMING(player))
9245 /* it's first time to update all content attrs. */
9246 _mmplayer_update_content_attrs(player, ATTR_ALL);
9250 __mmplayer_set_playing_state(mmplayer_t *player)
9252 gchar *audio_codec = NULL;
9254 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9255 /* initialize because auto resume is done well. */
9256 player->resumed_by_rewind = FALSE;
9257 player->playback_rate = 1.0;
9260 if (player->sent_bos)
9263 /* try to get content metadata */
9265 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9266 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9267 * legacy mmfw-player api
9269 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9271 if ((player->cmd == MMPLAYER_COMMAND_START)
9272 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9273 __mmplayer_handle_missed_plugin(player);
9276 /* check audio codec field is set or not
9277 * we can get it from typefinder or codec's caps.
9279 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9281 /* The codec format can't be sent for audio only case like amr, mid etc.
9282 * Because, parser don't make related TAG.
9283 * So, if it's not set yet, fill it with found data.
9286 if (g_strrstr(player->type, "audio/midi"))
9287 audio_codec = "MIDI";
9288 else if (g_strrstr(player->type, "audio/x-amr"))
9289 audio_codec = "AMR";
9290 else if (g_strrstr(player->type, "audio/mpeg")
9291 && !g_strrstr(player->type, "mpegversion=(int)1"))
9292 audio_codec = "AAC";
9294 audio_codec = "unknown";
9296 if (mm_player_set_attribute((MMHandleType)player, NULL,
9297 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9298 LOGE("failed to set attribute");
9300 LOGD("set audio codec type with caps");