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.depth = a_buffer->depth;
2269 audio_stream.is_little_endian = a_buffer->is_little_endian;
2270 audio_stream.channel_mask = a_buffer->channel_mask;
2271 audio_stream.data_size = a_buffer->data_size;
2272 audio_stream.data = a_buffer->pcm_data;
2273 audio_stream.pcm_format = a_buffer->pcm_format;
2275 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2277 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2283 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2285 mmplayer_t *player = (mmplayer_t *)data;
2286 const gchar *pcm_format = NULL;
2290 gint endianness = 0;
2291 guint64 channel_mask = 0;
2292 void *a_data = NULL;
2294 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2295 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2299 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2301 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2302 a_data = mapinfo.data;
2303 a_size = mapinfo.size;
2305 GstCaps *caps = gst_pad_get_current_caps(pad);
2306 GstStructure *structure = gst_caps_get_structure(caps, 0);
2308 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2310 pcm_format = gst_structure_get_string(structure, "format");
2311 gst_structure_get_int(structure, "rate", &rate);
2312 gst_structure_get_int(structure, "channels", &channel);
2313 gst_structure_get_int(structure, "depth", &depth);
2314 gst_structure_get_int(structure, "endianness", &endianness);
2315 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2316 gst_caps_unref(GST_CAPS(caps));
2318 /* In case of the sync is false, use buffer list. *
2319 * The num of buffer list depends on the num of audio channels */
2320 if (player->audio_stream_buff_list) {
2321 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2322 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2324 if (channel_mask == tmp->channel_mask) {
2326 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2328 if (tmp->data_size + a_size < tmp->buff_size) {
2329 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2330 tmp->data_size += a_size;
2332 /* send data to client */
2333 __mmplayer_audio_stream_send_data(player, tmp);
2335 if (a_size > tmp->buff_size) {
2336 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2337 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2338 if (tmp->pcm_data == NULL) {
2339 LOGE("failed to realloc data.");
2342 tmp->buff_size = a_size;
2344 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2345 memcpy(tmp->pcm_data, a_data, a_size);
2346 tmp->data_size = a_size;
2351 LOGE("data is empty in list.");
2357 /* create new audio stream data for newly found audio channel */
2358 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2359 if (a_buffer == NULL) {
2360 LOGE("failed to alloc data.");
2363 a_buffer->bitrate = rate;
2364 a_buffer->channel = channel;
2365 a_buffer->depth = depth;
2366 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2367 a_buffer->channel_mask = channel_mask;
2368 a_buffer->data_size = a_size;
2369 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2371 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2372 /* If sync is FALSE, use buffer list to reduce the IPC. */
2373 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2374 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2375 if (a_buffer->pcm_data == NULL) {
2376 LOGE("failed to alloc data.");
2377 MMPLAYER_FREEIF(a_buffer);
2380 memcpy(a_buffer->pcm_data, a_data, a_size);
2382 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2384 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2386 /* If sync is TRUE, send data directly. */
2387 a_buffer->pcm_data = a_data;
2388 __mmplayer_audio_stream_send_data(player, a_buffer);
2389 MMPLAYER_FREEIF(a_buffer);
2393 gst_buffer_unmap(buffer, &mapinfo);
2398 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2400 mmplayer_t *player = (mmplayer_t *)data;
2401 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2402 GstPad *sinkpad = NULL;
2403 GstElement *queue = NULL, *sink = NULL;
2406 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2408 queue = gst_element_factory_make("queue", NULL);
2409 if (queue == NULL) {
2410 LOGD("fail make queue");
2414 sink = gst_element_factory_make("fakesink", NULL);
2416 LOGD("fail make fakesink");
2420 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2422 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2423 LOGW("failed to link queue & sink");
2427 sinkpad = gst_element_get_static_pad(queue, "sink");
2429 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2430 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2434 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2436 gst_object_unref(sinkpad);
2437 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2438 g_object_set(sink, "sync", TRUE, NULL);
2439 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2441 /* keep the first sink reference only */
2442 if (!audiobin[MMPLAYER_A_SINK].gst) {
2443 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2444 audiobin[MMPLAYER_A_SINK].gst = sink;
2448 _mmplayer_add_signal_connection(player,
2450 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2452 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2455 __mmplayer_add_sink(player, sink);
2457 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2458 LOGE("failed to sync state");
2462 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2463 LOGE("failed to sync state");
2471 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2473 gst_object_unref(GST_OBJECT(queue));
2477 gst_object_unref(GST_OBJECT(sink));
2481 gst_object_unref(GST_OBJECT(sinkpad));
2489 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2491 mmplayer_t *player = (mmplayer_t *)data;
2494 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2496 player->no_more_pad = TRUE;
2497 __mmplayer_pipeline_complete(NULL, player);
2504 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2506 #define MAX_PROPS_LEN 128
2507 mmplayer_gst_element_t *audiobin = NULL;
2508 gint latency_mode = 0;
2509 gchar *stream_type = NULL;
2510 gchar *latency = NULL;
2512 gchar stream_props[MAX_PROPS_LEN] = {0,};
2513 GstStructure *props = NULL;
2516 * It should be set after player creation through attribute.
2517 * But, it can not be changed during playing.
2520 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2522 audiobin = player->pipeline->audiobin;
2524 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2525 if (player->sound.mute) {
2526 LOGD("mute enabled");
2527 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2530 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2531 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2534 snprintf(stream_props, sizeof(stream_props) - 1,
2535 "props,application.process.id.origin=%d", player->client_pid);
2537 snprintf(stream_props, sizeof(stream_props) - 1,
2538 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2539 stream_type, stream_id, player->client_pid);
2541 props = gst_structure_from_string(stream_props, NULL);
2542 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2543 LOGI("props result[%s].", stream_props);
2544 gst_structure_free(props);
2546 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2548 switch (latency_mode) {
2549 case AUDIO_LATENCY_MODE_LOW:
2550 latency = g_strndup("low", 3);
2552 case AUDIO_LATENCY_MODE_MID:
2553 latency = g_strndup("mid", 3);
2555 case AUDIO_LATENCY_MODE_HIGH:
2556 latency = g_strndup("high", 4);
2560 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2562 LOGD("audiosink property - latency=%s", latency);
2564 MMPLAYER_FREEIF(latency);
2570 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2572 mmplayer_gst_element_t *audiobin = NULL;
2575 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2577 audiobin = player->pipeline->audiobin;
2579 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2580 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2581 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2583 if (player->video360_yaw_radians <= M_PI &&
2584 player->video360_yaw_radians >= -M_PI &&
2585 player->video360_pitch_radians <= M_PI_2 &&
2586 player->video360_pitch_radians >= -M_PI_2) {
2587 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2588 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2589 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2590 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2591 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2592 "source-orientation-y", player->video360_metadata.init_view_heading,
2593 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2600 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2602 mmplayer_gst_element_t *audiobin = NULL;
2603 GstPad *sink_pad = NULL;
2604 GstCaps *acaps = NULL;
2606 int pitch_control = 0;
2607 double pitch_value = 1.0;
2610 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2611 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2613 audiobin = player->pipeline->audiobin;
2615 LOGD("make element for normal audio playback");
2617 /* audio bin structure for playback. {} means optional.
2618 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2620 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2621 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2624 /* for pitch control */
2625 mm_attrs_multiple_get(player->attrs, NULL,
2626 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2627 MM_PLAYER_PITCH_VALUE, &pitch_value,
2630 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2631 if (pitch_control && (player->videodec_linked == 0)) {
2632 GstElementFactory *factory;
2634 factory = gst_element_factory_find("pitch");
2636 gst_object_unref(factory);
2639 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2642 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2643 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2645 LOGW("there is no pitch element");
2650 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2652 /* replaygain volume */
2653 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2654 if (player->sound.rg_enable)
2655 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2660 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2662 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2663 /* currently, only openalsink uses volume element */
2664 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2665 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2667 if (player->sound.mute) {
2668 LOGD("mute enabled");
2669 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2673 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2675 /* audio effect element. if audio effect is enabled */
2676 if ((strcmp(player->ini.audioeffect_element, ""))
2678 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2679 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2681 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2683 if ((!player->bypass_audio_effect)
2684 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2685 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2686 if (!_mmplayer_audio_effect_custom_apply(player))
2687 LOGI("apply audio effect(custom) setting success");
2691 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2692 && (player->set_mode.rich_audio)) {
2693 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2697 /* create audio sink */
2698 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2699 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2700 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2702 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2703 if (player->is_360_feature_enabled &&
2704 player->is_content_spherical &&
2706 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2707 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2708 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2710 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2712 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2715 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2716 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2717 gst_caps_unref(acaps);
2719 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2721 player->is_openal_plugin_used = TRUE;
2723 if (player->is_360_feature_enabled && player->is_content_spherical)
2724 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2725 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2728 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2729 (player->videodec_linked && player->ini.use_system_clock)) {
2730 LOGD("system clock will be used.");
2731 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2734 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2735 __mmplayer_gst_set_pulsesink_property(player);
2736 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2737 __mmplayer_gst_set_openalsink_property(player);
2740 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2741 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2743 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2744 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2745 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2746 gst_object_unref(GST_OBJECT(sink_pad));
2748 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2751 return MM_ERROR_NONE;
2753 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2755 return MM_ERROR_PLAYER_INTERNAL;
2759 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2761 mmplayer_gst_element_t *audiobin = NULL;
2762 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2764 gchar *dst_format = NULL;
2766 int dst_samplerate = 0;
2767 int dst_channels = 0;
2768 GstCaps *caps = NULL;
2769 char *caps_str = NULL;
2772 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2773 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2775 audiobin = player->pipeline->audiobin;
2777 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2779 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2781 [case 1] extract interleave audio pcm without playback
2782 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2783 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2785 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2787 [case 2] deinterleave for each channel without playback
2788 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2789 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2791 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2792 - fakesink (sync or not)
2795 [case 3] [case 1(sync only)] + playback
2796 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2798 * src - ... - tee - queue1 - playback path
2799 - queue2 - [case1 pipeline with sync]
2801 [case 4] [case 2(sync only)] + playback
2802 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2804 * src - ... - tee - queue1 - playback path
2805 - queue2 - [case2 pipeline with sync]
2809 /* 1. create tee and playback path
2810 'tee' should be added at first to copy the decoded stream
2812 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2813 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2814 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2816 /* tee - path 1 : for playback path */
2817 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2818 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2820 /* tee - path 2 : for extract path */
2821 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2822 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2825 /* if there is tee, 'tee - path 2' is linked here */
2827 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2830 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2832 /* 2. decide the extract pcm format */
2833 mm_attrs_multiple_get(player->attrs, NULL,
2834 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2835 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2836 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2839 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2840 dst_format, dst_len, dst_samplerate, dst_channels);
2842 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2843 mm_attrs_multiple_get(player->attrs, NULL,
2844 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2845 "content_audio_samplerate", &dst_samplerate,
2846 "content_audio_channels", &dst_channels,
2849 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2850 dst_format, dst_len, dst_samplerate, dst_channels);
2852 /* If there is no enough information, set it to platform default value. */
2853 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2854 LOGD("set platform default format");
2855 dst_format = DEFAULT_PCM_OUT_FORMAT;
2857 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2858 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2861 /* 3. create capsfilter */
2862 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2863 caps = gst_caps_new_simple("audio/x-raw",
2864 "format", G_TYPE_STRING, dst_format,
2865 "rate", G_TYPE_INT, dst_samplerate,
2866 "channels", G_TYPE_INT, dst_channels,
2869 caps_str = gst_caps_to_string(caps);
2870 LOGD("new caps : %s", caps_str);
2872 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2875 gst_caps_unref(caps);
2876 MMPLAYER_FREEIF(caps_str);
2878 /* 4-1. create deinterleave to extract pcm for each channel */
2879 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2880 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2881 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2883 /* audiosink will be added after getting signal for each channel */
2884 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2885 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2886 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2887 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2888 player->no_more_pad = FALSE;
2890 /* 4-2. create fakesink to extract interlevaed pcm */
2891 LOGD("add audio fakesink for interleaved audio");
2892 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2893 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2894 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2895 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2897 _mmplayer_add_signal_connection(player,
2898 G_OBJECT(audiobin[extract_sink_id].gst),
2899 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2901 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2904 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2908 return MM_ERROR_NONE;
2910 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2912 return MM_ERROR_PLAYER_INTERNAL;
2916 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2918 int ret = MM_ERROR_NONE;
2919 mmplayer_gst_element_t *audiobin = NULL;
2920 GList *element_bucket = NULL;
2923 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2924 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2926 audiobin = player->pipeline->audiobin;
2928 if (player->build_audio_offload) { /* skip all the audio filters */
2929 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2931 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2932 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2933 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2935 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2939 /* FIXME: need to mention the supportable condition at API reference */
2940 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2941 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2943 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2945 if (ret != MM_ERROR_NONE)
2948 LOGD("success to make audio bin element");
2949 *bucket = element_bucket;
2952 return MM_ERROR_NONE;
2955 LOGE("failed to make audio bin element");
2956 g_list_free(element_bucket);
2960 return MM_ERROR_PLAYER_INTERNAL;
2964 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2966 mmplayer_gst_element_t *first_element = NULL;
2967 mmplayer_gst_element_t *audiobin = NULL;
2969 GstPad *ghostpad = NULL;
2970 GList *element_bucket = NULL;
2974 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2977 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2979 LOGE("failed to allocate memory for audiobin");
2980 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2984 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2985 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2986 if (!audiobin[MMPLAYER_A_BIN].gst) {
2987 LOGE("failed to create audiobin");
2992 player->pipeline->audiobin = audiobin;
2994 /* create audio filters and audiosink */
2995 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2998 /* adding created elements to bin */
2999 LOGD("adding created elements to bin");
3000 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3003 /* linking elements in the bucket by added order. */
3004 LOGD("Linking elements in the bucket by added order.");
3005 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3008 /* get first element's sinkpad for creating ghostpad */
3009 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3010 if (!first_element) {
3011 LOGE("failed to get first elem");
3015 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3017 LOGE("failed to get pad from first element of audiobin");
3021 ghostpad = gst_ghost_pad_new("sink", pad);
3023 LOGE("failed to create ghostpad");
3027 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3028 LOGE("failed to add ghostpad to audiobin");
3032 gst_object_unref(pad);
3034 g_list_free(element_bucket);
3037 return MM_ERROR_NONE;
3040 LOGD("ERROR : releasing audiobin");
3043 gst_object_unref(GST_OBJECT(pad));
3046 gst_object_unref(GST_OBJECT(ghostpad));
3049 g_list_free(element_bucket);
3051 /* release element which are not added to bin */
3052 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3053 /* NOTE : skip bin */
3054 if (audiobin[i].gst) {
3055 GstObject *parent = NULL;
3056 parent = gst_element_get_parent(audiobin[i].gst);
3059 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3060 audiobin[i].gst = NULL;
3062 gst_object_unref(GST_OBJECT(parent));
3066 /* release audiobin with it's childs */
3067 if (audiobin[MMPLAYER_A_BIN].gst)
3068 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3070 MMPLAYER_FREEIF(audiobin);
3072 player->pipeline->audiobin = NULL;
3074 return MM_ERROR_PLAYER_INTERNAL;
3078 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3080 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3084 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3086 int ret = MM_ERROR_NONE;
3088 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3089 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3091 MMPLAYER_VIDEO_BO_LOCK(player);
3093 if (player->video_bo_list) {
3094 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3095 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3096 if (tmp && tmp->bo == bo) {
3098 LOGD("release bo %p", bo);
3099 tbm_bo_unref(tmp->bo);
3100 MMPLAYER_VIDEO_BO_UNLOCK(player);
3101 MMPLAYER_VIDEO_BO_SIGNAL(player);
3106 /* hw codec is running or the list was reset for DRC. */
3107 LOGW("there is no bo list.");
3109 MMPLAYER_VIDEO_BO_UNLOCK(player);
3111 LOGW("failed to find bo %p", bo);
3116 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3121 MMPLAYER_RETURN_IF_FAIL(player);
3123 MMPLAYER_VIDEO_BO_LOCK(player);
3124 if (player->video_bo_list) {
3125 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3126 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3127 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3130 tbm_bo_unref(tmp->bo);
3134 g_list_free(player->video_bo_list);
3135 player->video_bo_list = NULL;
3137 player->video_bo_size = 0;
3138 MMPLAYER_VIDEO_BO_UNLOCK(player);
3145 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3148 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3149 gboolean ret = TRUE;
3151 /* check DRC, if it is, destroy the prev bo list to create again */
3152 if (player->video_bo_size != size) {
3153 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3154 __mmplayer_video_stream_destroy_bo_list(player);
3155 player->video_bo_size = size;
3158 MMPLAYER_VIDEO_BO_LOCK(player);
3160 if ((!player->video_bo_list) ||
3161 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3163 /* create bo list */
3165 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3167 if (player->video_bo_list) {
3168 /* if bo list did not created all, try it again. */
3169 idx = g_list_length(player->video_bo_list);
3170 LOGD("bo list exist(len: %d)", idx);
3173 for (; idx < player->ini.num_of_video_bo; idx++) {
3174 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3176 LOGE("Fail to alloc bo_info.");
3179 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3181 LOGE("Fail to tbm_bo_alloc.");
3182 MMPLAYER_FREEIF(bo_info);
3185 bo_info->used = FALSE;
3186 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3189 /* update video num buffers */
3190 LOGD("video_num_buffers : %d", idx);
3191 mm_player_set_attribute((MMHandleType)player, NULL,
3192 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3193 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3197 MMPLAYER_VIDEO_BO_UNLOCK(player);
3203 /* get bo from list*/
3204 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3205 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3206 if (tmp && (tmp->used == FALSE)) {
3207 LOGD("found bo %p to use", tmp->bo);
3209 MMPLAYER_VIDEO_BO_UNLOCK(player);
3210 return tbm_bo_ref(tmp->bo);
3214 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3215 MMPLAYER_VIDEO_BO_UNLOCK(player);
3219 if (player->ini.video_bo_timeout <= 0) {
3220 MMPLAYER_VIDEO_BO_WAIT(player);
3222 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3223 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3230 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3232 mmplayer_t *player = (mmplayer_t *)data;
3234 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3236 /* send prerolled pkt */
3237 player->video_stream_prerolled = false;
3239 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3241 /* not to send prerolled pkt again */
3242 player->video_stream_prerolled = true;
3246 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3248 mmplayer_t *player = (mmplayer_t *)data;
3249 mmplayer_video_decoded_data_info_t *stream = NULL;
3250 GstMemory *mem = NULL;
3253 MMPLAYER_RETURN_IF_FAIL(player);
3254 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3256 if (player->video_stream_prerolled) {
3257 player->video_stream_prerolled = false;
3258 LOGD("skip the prerolled pkt not to send it again");
3262 /* clear stream data structure */
3263 stream = __mmplayer_create_stream_from_pad(pad);
3265 LOGE("failed to alloc stream");
3269 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3271 /* set size and timestamp */
3272 mem = gst_buffer_peek_memory(buffer, 0);
3273 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3274 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3276 /* check zero-copy */
3277 if (player->set_mode.video_zc &&
3278 player->set_mode.video_export &&
3279 gst_is_tizen_memory(mem)) {
3280 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3281 stream->internal_buffer = gst_buffer_ref(buffer);
3282 } else { /* sw codec */
3283 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3286 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3290 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3291 LOGE("failed to send video decoded data.");
3298 LOGE("release video stream resource.");
3299 if (gst_is_tizen_memory(mem)) {
3301 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3303 tbm_bo_unref(stream->bo[i]);
3306 /* unref gst buffer */
3307 if (stream->internal_buffer)
3308 gst_buffer_unref(stream->internal_buffer);
3311 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3313 MMPLAYER_FREEIF(stream);
3318 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3320 mmplayer_gst_element_t *videobin = NULL;
3323 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3325 videobin = player->pipeline->videobin;
3327 /* Set spatial media metadata and/or user settings to the element.
3329 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3330 "projection-type", player->video360_metadata.projection_type, NULL);
3332 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3333 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3335 if (player->video360_metadata.full_pano_width_pixels &&
3336 player->video360_metadata.full_pano_height_pixels &&
3337 player->video360_metadata.cropped_area_image_width &&
3338 player->video360_metadata.cropped_area_image_height) {
3339 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3340 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3341 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3342 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3343 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3344 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3345 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3349 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3350 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3351 "horizontal-fov", player->video360_horizontal_fov,
3352 "vertical-fov", player->video360_vertical_fov, NULL);
3355 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3356 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3357 "zoom", 1.0f / player->video360_zoom, NULL);
3360 if (player->video360_yaw_radians <= M_PI &&
3361 player->video360_yaw_radians >= -M_PI &&
3362 player->video360_pitch_radians <= M_PI_2 &&
3363 player->video360_pitch_radians >= -M_PI_2) {
3364 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3365 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3366 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3367 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3368 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3369 "pose-yaw", player->video360_metadata.init_view_heading,
3370 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3373 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3374 "passthrough", !player->is_video360_enabled, NULL);
3381 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3383 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3384 GList *element_bucket = NULL;
3387 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3389 /* create video360 filter */
3390 if (player->is_360_feature_enabled && player->is_content_spherical) {
3391 LOGD("create video360 element");
3392 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3393 __mmplayer_gst_set_video360_property(player);
3397 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3398 LOGD("skip creating the videoconv and rotator");
3399 return MM_ERROR_NONE;
3402 /* in case of sw codec & overlay surface type, except 360 playback.
3403 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3404 LOGD("create video converter: %s", video_csc);
3405 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3408 *bucket = element_bucket;
3410 return MM_ERROR_NONE;
3412 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3413 g_list_free(element_bucket);
3417 return MM_ERROR_PLAYER_INTERNAL;
3421 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3423 gchar *factory_name = NULL;
3425 switch (surface_type) {
3426 case MM_DISPLAY_SURFACE_OVERLAY:
3427 if (strlen(player->ini.videosink_element_overlay) > 0)
3428 factory_name = player->ini.videosink_element_overlay;
3430 case MM_DISPLAY_SURFACE_REMOTE:
3431 case MM_DISPLAY_SURFACE_NULL:
3432 if (strlen(player->ini.videosink_element_fake) > 0)
3433 factory_name = player->ini.videosink_element_fake;
3436 LOGE("unidentified surface type");
3440 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3441 return factory_name;
3445 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3447 gchar *factory_name = NULL;
3448 mmplayer_gst_element_t *videobin = NULL;
3453 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3455 videobin = player->pipeline->videobin;
3456 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3458 attrs = MMPLAYER_GET_ATTRS(player);
3460 LOGE("cannot get content attribute");
3461 return MM_ERROR_PLAYER_INTERNAL;
3464 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3465 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3466 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3468 /* support shard memory with S/W codec on HawkP */
3469 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3470 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3471 "use-tbm", use_tbm, NULL);
3475 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3476 return MM_ERROR_PLAYER_INTERNAL;
3478 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3479 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3482 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3484 LOGD("disable last-sample");
3485 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3488 if (player->set_mode.video_export) {
3490 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3491 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3492 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3494 _mmplayer_add_signal_connection(player,
3495 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3496 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3498 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3501 _mmplayer_add_signal_connection(player,
3502 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3503 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3505 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3509 if (videobin[MMPLAYER_V_SINK].gst) {
3510 GstPad *sink_pad = NULL;
3511 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3513 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3514 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3515 gst_object_unref(GST_OBJECT(sink_pad));
3517 LOGE("failed to get sink pad from videosink");
3521 return MM_ERROR_NONE;
3526 * - video overlay surface(arm/x86) : tizenwlsink
3529 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3532 GList *element_bucket = NULL;
3533 mmplayer_gst_element_t *first_element = NULL;
3534 mmplayer_gst_element_t *videobin = NULL;
3535 gchar *videosink_factory_name = NULL;
3538 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3541 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3543 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3545 player->pipeline->videobin = videobin;
3548 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3549 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3550 if (!videobin[MMPLAYER_V_BIN].gst) {
3551 LOGE("failed to create videobin");
3555 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3558 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3559 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3561 /* additional setting for sink plug-in */
3562 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3563 LOGE("failed to set video property");
3567 /* store it as it's sink element */
3568 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3570 /* adding created elements to bin */
3571 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3572 LOGE("failed to add elements");
3576 /* Linking elements in the bucket by added order */
3577 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3578 LOGE("failed to link elements");
3582 /* get first element's sinkpad for creating ghostpad */
3583 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3584 if (!first_element) {
3585 LOGE("failed to get first element from bucket");
3589 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3591 LOGE("failed to get pad from first element");
3595 /* create ghostpad */
3596 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3597 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3598 LOGE("failed to add ghostpad to videobin");
3601 gst_object_unref(pad);
3603 /* done. free allocated variables */
3604 g_list_free(element_bucket);
3608 return MM_ERROR_NONE;
3611 LOGE("ERROR : releasing videobin");
3612 g_list_free(element_bucket);
3615 gst_object_unref(GST_OBJECT(pad));
3617 /* release videobin with it's childs */
3618 if (videobin[MMPLAYER_V_BIN].gst)
3619 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3621 MMPLAYER_FREEIF(videobin);
3622 player->pipeline->videobin = NULL;
3624 return MM_ERROR_PLAYER_INTERNAL;
3628 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3630 GList *element_bucket = NULL;
3631 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3633 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3634 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3635 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3636 "signal-handoffs", FALSE,
3639 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3640 _mmplayer_add_signal_connection(player,
3641 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3642 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3644 G_CALLBACK(__mmplayer_update_subtitle),
3647 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3648 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3650 if (!player->play_subtitle) {
3651 LOGD("add textbin sink as sink element of whole pipeline.");
3652 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3655 /* adding created elements to bin */
3656 LOGD("adding created elements to bin");
3657 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3658 LOGE("failed to add elements");
3662 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3663 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3664 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3666 /* linking elements in the bucket by added order. */
3667 LOGD("Linking elements in the bucket by added order.");
3668 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3669 LOGE("failed to link elements");
3673 /* done. free allocated variables */
3674 g_list_free(element_bucket);
3676 if (textbin[MMPLAYER_T_QUEUE].gst) {
3678 GstPad *ghostpad = NULL;
3680 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3682 LOGE("failed to get sink pad of text queue");
3686 ghostpad = gst_ghost_pad_new("text_sink", pad);
3687 gst_object_unref(pad);
3690 LOGE("failed to create ghostpad of textbin");
3694 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3695 LOGE("failed to add ghostpad to textbin");
3696 gst_object_unref(ghostpad);
3701 return MM_ERROR_NONE;
3704 g_list_free(element_bucket);
3706 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3707 LOGE("remove textbin sink from sink list");
3708 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3711 /* release element at __mmplayer_gst_create_text_sink_bin */
3712 return MM_ERROR_PLAYER_INTERNAL;
3716 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3718 mmplayer_gst_element_t *textbin = NULL;
3719 GList *element_bucket = NULL;
3720 int surface_type = 0;
3725 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3728 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3730 LOGE("failed to allocate memory for textbin");
3731 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3735 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3736 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3737 if (!textbin[MMPLAYER_T_BIN].gst) {
3738 LOGE("failed to create textbin");
3743 player->pipeline->textbin = textbin;
3746 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3747 LOGD("surface type for subtitle : %d", surface_type);
3748 switch (surface_type) {
3749 case MM_DISPLAY_SURFACE_OVERLAY:
3750 case MM_DISPLAY_SURFACE_NULL:
3751 case MM_DISPLAY_SURFACE_REMOTE:
3752 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3753 LOGE("failed to make plain text elements");
3764 return MM_ERROR_NONE;
3768 LOGD("ERROR : releasing textbin");
3770 g_list_free(element_bucket);
3772 /* release signal */
3773 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3775 /* release element which are not added to bin */
3776 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3777 /* NOTE : skip bin */
3778 if (textbin[i].gst) {
3779 GstObject *parent = NULL;
3780 parent = gst_element_get_parent(textbin[i].gst);
3783 gst_object_unref(GST_OBJECT(textbin[i].gst));
3784 textbin[i].gst = NULL;
3786 gst_object_unref(GST_OBJECT(parent));
3791 /* release textbin with it's childs */
3792 if (textbin[MMPLAYER_T_BIN].gst)
3793 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3795 MMPLAYER_FREEIF(player->pipeline->textbin);
3796 player->pipeline->textbin = NULL;
3799 return MM_ERROR_PLAYER_INTERNAL;
3803 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3805 mmplayer_gst_element_t *mainbin = NULL;
3806 mmplayer_gst_element_t *textbin = NULL;
3807 MMHandleType attrs = 0;
3808 GstElement *subsrc = NULL;
3809 GstElement *subparse = NULL;
3810 gchar *subtitle_uri = NULL;
3811 const gchar *charset = NULL;
3817 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3819 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3821 mainbin = player->pipeline->mainbin;
3823 attrs = MMPLAYER_GET_ATTRS(player);
3825 LOGE("cannot get content attribute");
3826 return MM_ERROR_PLAYER_INTERNAL;
3829 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3830 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3831 LOGE("subtitle uri is not proper filepath.");
3832 return MM_ERROR_PLAYER_INVALID_URI;
3835 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3836 LOGE("failed to get storage info of subtitle path");
3837 return MM_ERROR_PLAYER_INVALID_URI;
3840 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3842 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3843 player->subtitle_language_list = NULL;
3844 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3846 /* create the subtitle source */
3847 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3849 LOGE("failed to create filesrc element");
3852 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3854 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3855 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3857 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3858 LOGW("failed to add queue");
3859 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3860 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3861 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3866 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3868 LOGE("failed to create subparse element");
3872 charset = _mmplayer_get_charset(subtitle_uri);
3874 LOGD("detected charset is %s", charset);
3875 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3878 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3879 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3881 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3882 LOGW("failed to add subparse");
3883 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3884 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3885 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3889 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3890 LOGW("failed to link subsrc and subparse");
3894 player->play_subtitle = TRUE;
3895 player->adjust_subtitle_pos = 0;
3897 LOGD("play subtitle using subtitle file");
3899 if (player->pipeline->textbin == NULL) {
3900 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3901 LOGE("failed to create text sink bin. continuing without text");
3905 textbin = player->pipeline->textbin;
3907 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3908 LOGW("failed to add textbin");
3910 /* release signal */
3911 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3913 /* release textbin with it's childs */
3914 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3915 MMPLAYER_FREEIF(player->pipeline->textbin);
3916 player->pipeline->textbin = textbin = NULL;
3920 LOGD("link text input selector and textbin ghost pad");
3922 player->textsink_linked = 1;
3923 player->external_text_idx = 0;
3924 LOGI("textsink is linked");
3926 textbin = player->pipeline->textbin;
3927 LOGD("text bin has been created. reuse it.");
3928 player->external_text_idx = 1;
3931 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3932 LOGW("failed to link subparse and textbin");
3936 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3938 LOGE("failed to get sink pad from textsink to probe data");
3942 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3943 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3945 gst_object_unref(pad);
3948 /* create dot. for debugging */
3949 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3952 return MM_ERROR_NONE;
3955 /* release text pipeline resource */
3956 player->textsink_linked = 0;
3958 /* release signal */
3959 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3961 if (player->pipeline->textbin) {
3962 LOGE("remove textbin");
3964 /* release textbin with it's childs */
3965 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3966 MMPLAYER_FREEIF(player->pipeline->textbin);
3967 player->pipeline->textbin = NULL;
3971 /* release subtitle elem */
3972 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3973 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3975 return MM_ERROR_PLAYER_INTERNAL;
3979 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3981 mmplayer_t *player = (mmplayer_t *)data;
3982 MMMessageParamType msg = {0, };
3983 GstClockTime duration = 0;
3984 gpointer text = NULL;
3985 guint text_size = 0;
3986 gboolean ret = TRUE;
3987 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3991 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3992 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3994 if (player->is_subtitle_force_drop) {
3995 LOGW("subtitle is dropped forcedly.");
3999 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4000 text = mapinfo.data;
4001 text_size = mapinfo.size;
4003 if (player->set_mode.subtitle_off) {
4004 LOGD("subtitle is OFF.");
4008 if (!text || (text_size == 0)) {
4009 LOGD("There is no subtitle to be displayed.");
4013 msg.data = (void *)text;
4015 duration = GST_BUFFER_DURATION(buffer);
4017 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4018 if (player->duration > GST_BUFFER_PTS(buffer))
4019 duration = player->duration - GST_BUFFER_PTS(buffer);
4022 LOGI("subtitle duration is invalid, subtitle duration change "
4023 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4025 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4027 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4029 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4030 gst_buffer_unmap(buffer, &mapinfo);
4037 static GstPadProbeReturn
4038 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4040 mmplayer_t *player = (mmplayer_t *)u_data;
4041 GstClockTime cur_timestamp = 0;
4042 gint64 adjusted_timestamp = 0;
4043 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4045 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4047 if (player->set_mode.subtitle_off) {
4048 LOGD("subtitle is OFF.");
4052 if (player->adjust_subtitle_pos == 0) {
4053 LOGD("nothing to do");
4057 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4058 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4060 if (adjusted_timestamp < 0) {
4061 LOGD("adjusted_timestamp under zero");
4066 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4067 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4068 GST_TIME_ARGS(cur_timestamp),
4069 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4071 return GST_PAD_PROBE_OK;
4075 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4079 /* check player and subtitlebin are created */
4080 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4081 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4083 if (position == 0) {
4084 LOGD("nothing to do");
4086 return MM_ERROR_NONE;
4089 /* check current postion */
4090 player->adjust_subtitle_pos = position;
4092 LOGD("save adjust_subtitle_pos in player");
4096 return MM_ERROR_NONE;
4100 * This function is to create audio or video pipeline for playing.
4102 * @param player [in] handle of player
4104 * @return This function returns zero on success.
4109 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4111 int ret = MM_ERROR_NONE;
4112 mmplayer_gst_element_t *mainbin = NULL;
4113 MMHandleType attrs = 0;
4116 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4118 /* get profile attribute */
4119 attrs = MMPLAYER_GET_ATTRS(player);
4121 LOGE("failed to get content attribute");
4125 /* create pipeline handles */
4126 if (player->pipeline) {
4127 LOGE("pipeline should be released before create new one");
4131 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4132 if (player->pipeline == NULL)
4135 /* create mainbin */
4136 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4137 if (mainbin == NULL)
4140 /* create pipeline */
4141 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4142 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4143 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4144 LOGE("failed to create pipeline");
4149 player->pipeline->mainbin = mainbin;
4151 /* create the source and decoder elements */
4152 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4153 ret = _mmplayer_gst_build_es_pipeline(player);
4155 ret = _mmplayer_gst_build_pipeline(player);
4157 if (ret != MM_ERROR_NONE) {
4158 LOGE("failed to create some elements");
4162 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4163 if (__mmplayer_check_subtitle(player)
4164 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4165 LOGE("failed to create text pipeline");
4168 ret = _mmplayer_gst_add_bus_watch(player);
4169 if (ret != MM_ERROR_NONE) {
4170 LOGE("failed to add bus watch");
4175 return MM_ERROR_NONE;
4178 __mmplayer_gst_destroy_pipeline(player);
4179 return MM_ERROR_PLAYER_INTERNAL;
4183 __mmplayer_reset_gapless_state(mmplayer_t *player)
4186 MMPLAYER_RETURN_IF_FAIL(player
4188 && player->pipeline->audiobin
4189 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4191 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4198 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4201 int ret = MM_ERROR_NONE;
4205 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4207 /* cleanup stuffs */
4208 MMPLAYER_FREEIF(player->type);
4209 player->no_more_pad = FALSE;
4210 player->num_dynamic_pad = 0;
4211 player->demux_pad_index = 0;
4213 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4214 player->subtitle_language_list = NULL;
4215 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4217 __mmplayer_reset_gapless_state(player);
4219 if (player->streamer) {
4220 _mm_player_streaming_initialize(player->streamer, FALSE);
4221 _mm_player_streaming_destroy(player->streamer);
4222 player->streamer = NULL;
4225 /* cleanup unlinked mime type */
4226 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4227 MMPLAYER_FREEIF(player->unlinked_video_mime);
4228 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4230 /* cleanup running stuffs */
4231 _mmplayer_cancel_eos_timer(player);
4233 /* cleanup gst stuffs */
4234 if (player->pipeline) {
4235 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4236 GstTagList *tag_list = player->pipeline->tag_list;
4238 /* first we need to disconnect all signal hander */
4239 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4242 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4243 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4244 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4245 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4246 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4247 gst_object_unref(bus);
4249 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4250 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4251 if (ret != MM_ERROR_NONE) {
4252 LOGE("fail to change state to NULL");
4253 return MM_ERROR_PLAYER_INTERNAL;
4256 LOGW("succeeded in changing state to NULL");
4258 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4261 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4262 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4264 /* free avsysaudiosink
4265 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4266 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4268 MMPLAYER_FREEIF(audiobin);
4269 MMPLAYER_FREEIF(videobin);
4270 MMPLAYER_FREEIF(textbin);
4271 MMPLAYER_FREEIF(mainbin);
4275 gst_tag_list_unref(tag_list);
4277 MMPLAYER_FREEIF(player->pipeline);
4279 MMPLAYER_FREEIF(player->album_art);
4281 if (player->v_stream_caps) {
4282 gst_caps_unref(player->v_stream_caps);
4283 player->v_stream_caps = NULL;
4286 if (player->a_stream_caps) {
4287 gst_caps_unref(player->a_stream_caps);
4288 player->a_stream_caps = NULL;
4291 if (player->s_stream_caps) {
4292 gst_caps_unref(player->s_stream_caps);
4293 player->s_stream_caps = NULL;
4295 _mmplayer_track_destroy(player);
4297 if (player->sink_elements)
4298 g_list_free(player->sink_elements);
4299 player->sink_elements = NULL;
4301 if (player->bufmgr) {
4302 tbm_bufmgr_deinit(player->bufmgr);
4303 player->bufmgr = NULL;
4306 LOGW("finished destroy pipeline");
4314 __mmplayer_gst_realize(mmplayer_t *player)
4317 int ret = MM_ERROR_NONE;
4321 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4323 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4325 ret = __mmplayer_gst_create_pipeline(player);
4327 LOGE("failed to create pipeline");
4331 /* set pipeline state to READY */
4332 /* NOTE : state change to READY must be performed sync. */
4333 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4334 ret = _mmplayer_gst_set_state(player,
4335 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4337 if (ret != MM_ERROR_NONE) {
4338 /* return error if failed to set state */
4339 LOGE("failed to set READY state");
4343 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4345 /* create dot before error-return. for debugging */
4346 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4354 __mmplayer_gst_unrealize(mmplayer_t *player)
4356 int ret = MM_ERROR_NONE;
4360 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4362 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4363 MMPLAYER_PRINT_STATE(player);
4365 /* release miscellaneous information */
4366 __mmplayer_release_misc(player);
4368 /* destroy pipeline */
4369 ret = __mmplayer_gst_destroy_pipeline(player);
4370 if (ret != MM_ERROR_NONE) {
4371 LOGE("failed to destory pipeline");
4375 /* release miscellaneous information.
4376 these info needs to be released after pipeline is destroyed. */
4377 __mmplayer_release_misc_post(player);
4379 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4387 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4392 LOGW("set_message_callback is called with invalid player handle");
4393 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4396 player->msg_cb = callback;
4397 player->msg_cb_param = user_param;
4399 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4403 return MM_ERROR_NONE;
4407 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4409 int ret = MM_ERROR_NONE;
4414 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4415 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4416 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4418 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4420 if (strstr(uri, "es_buff://")) {
4421 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4422 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4423 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4424 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4426 tmp = g_ascii_strdown(uri, strlen(uri));
4427 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4428 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4430 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4432 } else if (strstr(uri, "mms://")) {
4433 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4434 } else if ((path = strstr(uri, "mem://"))) {
4435 ret = __mmplayer_set_mem_uri(data, path, param);
4437 ret = __mmplayer_set_file_uri(data, uri);
4440 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4441 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4442 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4443 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4445 /* dump parse result */
4446 SECURE_LOGW("incoming uri : %s", uri);
4447 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4448 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4456 __mmplayer_can_do_interrupt(mmplayer_t *player)
4458 if (!player || !player->pipeline || !player->attrs) {
4459 LOGW("not initialized");
4463 if (player->audio_decoded_cb) {
4464 LOGW("not support in pcm extraction mode");
4468 /* check if seeking */
4469 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4470 MMMessageParamType msg_param;
4471 memset(&msg_param, 0, sizeof(MMMessageParamType));
4472 msg_param.code = MM_ERROR_PLAYER_SEEK;
4473 player->seek_state = MMPLAYER_SEEK_NONE;
4474 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4478 /* check other thread */
4479 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4480 LOGW("locked already, cmd state : %d", player->cmd);
4482 /* check application command */
4483 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4484 LOGW("playing.. should wait cmd lock then, will be interrupted");
4486 /* lock will be released at mrp_resource_release_cb() */
4487 MMPLAYER_CMD_LOCK(player);
4490 LOGW("nothing to do");
4493 LOGW("can interrupt immediately");
4497 FAILED: /* with CMD UNLOCKED */
4500 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4505 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4508 mmplayer_t *player = NULL;
4509 MMMessageParamType msg = {0, };
4511 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4516 LOGE("user_data is null");
4519 player = (mmplayer_t *)user_data;
4521 if (!__mmplayer_can_do_interrupt(player)) {
4522 LOGW("no need to interrupt, so leave");
4523 /* FIXME: there is no way to avoid releasing resource. */
4527 player->interrupted_by_resource = TRUE;
4529 /* get last play position */
4530 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4531 msg.union_type = MM_MSG_UNION_TIME;
4532 msg.time.elapsed = pos;
4533 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4535 LOGW("failed to get play position.");
4538 LOGD("video resource conflict so, resource will be freed by unrealizing");
4539 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4540 LOGE("failed to unrealize");
4542 /* lock is called in __mmplayer_can_do_interrupt() */
4543 MMPLAYER_CMD_UNLOCK(player);
4545 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4546 player->hw_resource[res_idx] = NULL;
4550 return TRUE; /* release all the resources */
4554 __mmplayer_initialize_video_roi(mmplayer_t *player)
4556 player->video_roi.scale_x = 0.0;
4557 player->video_roi.scale_y = 0.0;
4558 player->video_roi.scale_width = 1.0;
4559 player->video_roi.scale_height = 1.0;
4563 _mmplayer_create_player(MMHandleType handle)
4565 int ret = MM_ERROR_PLAYER_INTERNAL;
4566 bool enabled = false;
4568 mmplayer_t *player = MM_PLAYER_CAST(handle);
4572 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4574 /* initialize player state */
4575 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4576 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4577 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4578 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4580 /* check current state */
4581 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4583 /* construct attributes */
4584 player->attrs = _mmplayer_construct_attribute(handle);
4586 if (!player->attrs) {
4587 LOGE("Failed to construct attributes");
4591 /* initialize gstreamer with configured parameter */
4592 if (!__mmplayer_init_gstreamer(player)) {
4593 LOGE("Initializing gstreamer failed");
4594 _mmplayer_deconstruct_attribute(handle);
4598 /* create lock. note that g_tread_init() has already called in gst_init() */
4599 g_mutex_init(&player->fsink_lock);
4601 /* create update tag lock */
4602 g_mutex_init(&player->update_tag_lock);
4604 /* create gapless play mutex */
4605 g_mutex_init(&player->gapless_play_thread_mutex);
4607 /* create gapless play cond */
4608 g_cond_init(&player->gapless_play_thread_cond);
4610 /* create gapless play thread */
4611 player->gapless_play_thread =
4612 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4613 if (!player->gapless_play_thread) {
4614 LOGE("failed to create gapless play thread");
4615 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4616 g_mutex_clear(&player->gapless_play_thread_mutex);
4617 g_cond_clear(&player->gapless_play_thread_cond);
4621 player->bus_msg_q = g_queue_new();
4622 if (!player->bus_msg_q) {
4623 LOGE("failed to create queue for bus_msg");
4624 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4628 ret = _mmplayer_initialize_video_capture(player);
4629 if (ret != MM_ERROR_NONE) {
4630 LOGE("failed to initialize video capture");
4634 /* initialize resource manager */
4635 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4636 __resource_release_cb, player, &player->resource_manager)
4637 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4638 LOGE("failed to initialize resource manager");
4639 ret = MM_ERROR_PLAYER_INTERNAL;
4643 /* create video bo lock and cond */
4644 g_mutex_init(&player->video_bo_mutex);
4645 g_cond_init(&player->video_bo_cond);
4647 /* create subtitle info lock and cond */
4648 g_mutex_init(&player->subtitle_info_mutex);
4649 g_cond_init(&player->subtitle_info_cond);
4651 player->streaming_type = STREAMING_SERVICE_NONE;
4653 /* give default value of audio effect setting */
4654 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4655 player->sound.rg_enable = false;
4656 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4658 player->play_subtitle = FALSE;
4659 player->has_closed_caption = FALSE;
4660 player->pending_resume = FALSE;
4661 if (player->ini.dump_element_keyword[0][0] == '\0')
4662 player->ini.set_dump_element_flag = FALSE;
4664 player->ini.set_dump_element_flag = TRUE;
4666 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4667 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4668 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4670 /* Set video360 settings to their defaults for just-created player.
4673 player->is_360_feature_enabled = FALSE;
4674 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4675 LOGI("spherical feature info: %d", enabled);
4677 player->is_360_feature_enabled = TRUE;
4679 LOGE("failed to get spherical feature info");
4682 player->is_content_spherical = FALSE;
4683 player->is_video360_enabled = TRUE;
4684 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4685 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4686 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4687 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4688 player->video360_zoom = 1.0f;
4689 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4690 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4692 __mmplayer_initialize_video_roi(player);
4694 /* set player state to null */
4695 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4696 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4700 return MM_ERROR_NONE;
4704 g_mutex_clear(&player->fsink_lock);
4705 /* free update tag lock */
4706 g_mutex_clear(&player->update_tag_lock);
4707 g_queue_free(player->bus_msg_q);
4708 player->bus_msg_q = NULL;
4709 /* free gapless play thread */
4710 if (player->gapless_play_thread) {
4711 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4712 player->gapless_play_thread_exit = TRUE;
4713 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4714 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4716 g_thread_join(player->gapless_play_thread);
4717 player->gapless_play_thread = NULL;
4719 g_mutex_clear(&player->gapless_play_thread_mutex);
4720 g_cond_clear(&player->gapless_play_thread_cond);
4723 /* release attributes */
4724 _mmplayer_deconstruct_attribute(handle);
4732 __mmplayer_init_gstreamer(mmplayer_t *player)
4734 static gboolean initialized = FALSE;
4735 static const int max_argc = 50;
4737 gchar **argv = NULL;
4738 gchar **argv2 = NULL;
4744 LOGD("gstreamer already initialized.");
4749 argc = malloc(sizeof(int));
4750 argv = malloc(sizeof(gchar *) * max_argc);
4751 argv2 = malloc(sizeof(gchar *) * max_argc);
4753 if (!argc || !argv || !argv2)
4756 memset(argv, 0, sizeof(gchar *) * max_argc);
4757 memset(argv2, 0, sizeof(gchar *) * max_argc);
4761 argv[0] = g_strdup("mmplayer");
4764 for (i = 0; i < 5; i++) {
4765 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4766 if (strlen(player->ini.gst_param[i]) > 0) {
4767 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4772 /* we would not do fork for scanning plugins */
4773 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4776 /* check disable registry scan */
4777 if (player->ini.skip_rescan) {
4778 argv[*argc] = g_strdup("--gst-disable-registry-update");
4782 /* check disable segtrap */
4783 if (player->ini.disable_segtrap) {
4784 argv[*argc] = g_strdup("--gst-disable-segtrap");
4788 LOGD("initializing gstreamer with following parameter");
4789 LOGD("argc : %d", *argc);
4792 for (i = 0; i < arg_count; i++) {
4794 LOGD("argv[%d] : %s", i, argv2[i]);
4797 /* initializing gstreamer */
4798 if (!gst_init_check(argc, &argv, &err)) {
4799 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4806 for (i = 0; i < arg_count; i++) {
4808 LOGD("release - argv[%d] : %s", i, argv2[i]);
4810 MMPLAYER_FREEIF(argv2[i]);
4813 MMPLAYER_FREEIF(argv);
4814 MMPLAYER_FREEIF(argv2);
4815 MMPLAYER_FREEIF(argc);
4825 for (i = 0; i < arg_count; i++) {
4826 LOGD("free[%d] : %s", i, argv2[i]);
4827 MMPLAYER_FREEIF(argv2[i]);
4830 MMPLAYER_FREEIF(argv);
4831 MMPLAYER_FREEIF(argv2);
4832 MMPLAYER_FREEIF(argc);
4838 __mmplayer_check_async_state_transition(mmplayer_t *player)
4840 GstState element_state = GST_STATE_VOID_PENDING;
4841 GstState element_pending_state = GST_STATE_VOID_PENDING;
4842 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4843 GstElement *element = NULL;
4844 gboolean async = FALSE;
4846 /* check player handle */
4847 MMPLAYER_RETURN_IF_FAIL(player &&
4849 player->pipeline->mainbin &&
4850 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4853 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4855 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4856 LOGD("don't need to check the pipeline state");
4860 MMPLAYER_PRINT_STATE(player);
4862 /* wait for state transition */
4863 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4864 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4866 if (ret == GST_STATE_CHANGE_FAILURE) {
4867 LOGE(" [%s] state : %s pending : %s",
4868 GST_ELEMENT_NAME(element),
4869 gst_element_state_get_name(element_state),
4870 gst_element_state_get_name(element_pending_state));
4872 /* dump state of all element */
4873 _mmplayer_dump_pipeline_state(player);
4878 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4883 _mmplayer_destroy(MMHandleType handle)
4885 mmplayer_t *player = MM_PLAYER_CAST(handle);
4889 /* check player handle */
4890 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4892 /* destroy can called at anytime */
4893 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4895 /* check async state transition */
4896 __mmplayer_check_async_state_transition(player);
4898 /* release gapless play thread */
4899 if (player->gapless_play_thread) {
4900 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4901 player->gapless_play_thread_exit = TRUE;
4902 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4903 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4905 LOGD("waitting for gapless play thread exit");
4906 g_thread_join(player->gapless_play_thread);
4907 g_mutex_clear(&player->gapless_play_thread_mutex);
4908 g_cond_clear(&player->gapless_play_thread_cond);
4909 LOGD("gapless play thread released");
4912 _mmplayer_release_video_capture(player);
4914 /* de-initialize resource manager */
4915 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4916 player->resource_manager))
4917 LOGE("failed to deinitialize resource manager");
4919 /* release pipeline */
4920 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4921 LOGE("failed to destory pipeline");
4922 return MM_ERROR_PLAYER_INTERNAL;
4925 g_queue_free(player->bus_msg_q);
4927 /* release subtitle info lock and cond */
4928 g_mutex_clear(&player->subtitle_info_mutex);
4929 g_cond_clear(&player->subtitle_info_cond);
4931 __mmplayer_release_dump_list(player->dump_list);
4933 /* release miscellaneous information */
4934 __mmplayer_release_misc(player);
4936 /* release miscellaneous information.
4937 these info needs to be released after pipeline is destroyed. */
4938 __mmplayer_release_misc_post(player);
4940 /* release attributes */
4941 _mmplayer_deconstruct_attribute(handle);
4944 g_mutex_clear(&player->fsink_lock);
4947 g_mutex_clear(&player->update_tag_lock);
4949 /* release video bo lock and cond */
4950 g_mutex_clear(&player->video_bo_mutex);
4951 g_cond_clear(&player->video_bo_cond);
4955 return MM_ERROR_NONE;
4959 _mmplayer_realize(MMHandleType hplayer)
4961 mmplayer_t *player = (mmplayer_t *)hplayer;
4964 MMHandleType attrs = 0;
4965 int ret = MM_ERROR_NONE;
4969 /* check player handle */
4970 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4972 /* check current state */
4973 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4975 attrs = MMPLAYER_GET_ATTRS(player);
4977 LOGE("fail to get attributes.");
4978 return MM_ERROR_PLAYER_INTERNAL;
4980 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4981 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4983 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4984 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4986 if (ret != MM_ERROR_NONE) {
4987 LOGE("failed to parse profile");
4992 if (uri && (strstr(uri, "es_buff://"))) {
4993 if (strstr(uri, "es_buff://push_mode"))
4994 player->es_player_push_mode = TRUE;
4996 player->es_player_push_mode = FALSE;
4999 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5000 LOGW("mms protocol is not supported format.");
5001 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5004 if (MMPLAYER_IS_STREAMING(player))
5005 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5007 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5009 player->smooth_streaming = FALSE;
5010 player->videodec_linked = 0;
5011 player->audiodec_linked = 0;
5012 player->textsink_linked = 0;
5013 player->is_external_subtitle_present = FALSE;
5014 player->is_external_subtitle_added_now = FALSE;
5015 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5016 player->video360_metadata.is_spherical = -1;
5017 player->is_openal_plugin_used = FALSE;
5018 player->demux_pad_index = 0;
5019 player->subtitle_language_list = NULL;
5020 player->is_subtitle_force_drop = FALSE;
5022 _mmplayer_track_initialize(player);
5023 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5025 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5026 gint prebuffer_ms = 0, rebuffer_ms = 0;
5028 player->streamer = _mm_player_streaming_create();
5029 _mm_player_streaming_initialize(player->streamer, TRUE);
5031 mm_attrs_multiple_get(player->attrs, NULL,
5032 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5033 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5035 if (prebuffer_ms > 0) {
5036 prebuffer_ms = MAX(prebuffer_ms, 1000);
5037 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5040 if (rebuffer_ms > 0) {
5041 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5042 rebuffer_ms = MAX(rebuffer_ms, 1000);
5043 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5046 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5047 player->streamer->buffering_req.rebuffer_time);
5050 /* realize pipeline */
5051 ret = __mmplayer_gst_realize(player);
5052 if (ret != MM_ERROR_NONE)
5053 LOGE("fail to realize the player.");
5055 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5063 _mmplayer_unrealize(MMHandleType hplayer)
5065 mmplayer_t *player = (mmplayer_t *)hplayer;
5066 int ret = MM_ERROR_NONE;
5070 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5072 MMPLAYER_CMD_UNLOCK(player);
5073 /* destroy the gst bus msg thread which is created during realize.
5074 this funct have to be called before getting cmd lock. */
5075 _mmplayer_bus_msg_thread_destroy(player);
5076 MMPLAYER_CMD_LOCK(player);
5078 /* check current state */
5079 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5081 /* check async state transition */
5082 __mmplayer_check_async_state_transition(player);
5084 /* unrealize pipeline */
5085 ret = __mmplayer_gst_unrealize(player);
5087 if (!player->interrupted_by_resource) {
5088 int rm_ret = MM_ERROR_NONE;
5089 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5091 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5092 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5093 if (rm_ret != MM_ERROR_NONE)
5094 LOGE("failed to release [%d] resources", res_idx);
5103 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5105 mmplayer_t *player = (mmplayer_t *)hplayer;
5107 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5109 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5113 _mmplayer_get_state(MMHandleType hplayer, int *state)
5115 mmplayer_t *player = (mmplayer_t *)hplayer;
5117 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5119 *state = MMPLAYER_CURRENT_STATE(player);
5121 return MM_ERROR_NONE;
5125 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5127 GstElement *vol_element = NULL;
5128 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5131 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5132 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5134 /* check pipeline handle */
5135 if (!player->pipeline || !player->pipeline->audiobin) {
5136 LOGD("'%s' will be applied when audiobin is created", prop_name);
5138 /* NOTE : stored value will be used in create_audiobin
5139 * returning MM_ERROR_NONE here makes application to able to
5140 * set audio volume or mute at anytime.
5142 return MM_ERROR_NONE;
5145 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5146 volume_elem_id = MMPLAYER_A_SINK;
5148 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5150 LOGE("failed to get vol element %d", volume_elem_id);
5151 return MM_ERROR_PLAYER_INTERNAL;
5154 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5156 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5157 LOGE("there is no '%s' property", prop_name);
5158 return MM_ERROR_PLAYER_INTERNAL;
5161 if (!strcmp(prop_name, "volume")) {
5162 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5163 } else if (!strcmp(prop_name, "mute")) {
5164 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5166 LOGE("invalid property %s", prop_name);
5167 return MM_ERROR_PLAYER_INTERNAL;
5170 return MM_ERROR_NONE;
5174 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5176 int ret = MM_ERROR_NONE;
5177 mmplayer_t *player = (mmplayer_t *)hplayer;
5180 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5182 LOGD("volume = %f", volume);
5184 /* invalid factor range or not */
5185 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5186 LOGE("Invalid volume value");
5187 return MM_ERROR_INVALID_ARGUMENT;
5190 player->sound.volume = volume;
5192 ret = __mmplayer_gst_set_volume_property(player, "volume");
5199 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5201 mmplayer_t *player = (mmplayer_t *)hplayer;
5205 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5206 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5208 *volume = player->sound.volume;
5210 LOGD("current vol = %f", *volume);
5213 return MM_ERROR_NONE;
5217 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5219 int ret = MM_ERROR_NONE;
5220 mmplayer_t *player = (mmplayer_t *)hplayer;
5223 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5225 LOGD("mute = %d", mute);
5227 player->sound.mute = mute;
5229 ret = __mmplayer_gst_set_volume_property(player, "mute");
5236 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5238 mmplayer_t *player = (mmplayer_t *)hplayer;
5242 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5243 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5245 *mute = player->sound.mute;
5247 LOGD("current mute = %d", *mute);
5251 return MM_ERROR_NONE;
5255 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5257 mmplayer_t *player = (mmplayer_t *)hplayer;
5261 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5263 player->audio_stream_changed_cb = callback;
5264 player->audio_stream_changed_cb_user_param = user_param;
5265 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5269 return MM_ERROR_NONE;
5273 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5275 mmplayer_t *player = (mmplayer_t *)hplayer;
5279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5281 player->audio_decoded_cb = callback;
5282 player->audio_decoded_cb_user_param = user_param;
5283 player->audio_extract_opt = opt;
5284 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5288 return MM_ERROR_NONE;
5292 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5294 mmplayer_t *player = (mmplayer_t *)hplayer;
5298 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5300 if (callback && !player->bufmgr)
5301 player->bufmgr = tbm_bufmgr_init(-1);
5303 player->set_mode.video_export = (callback) ? true : false;
5304 player->video_decoded_cb = callback;
5305 player->video_decoded_cb_user_param = user_param;
5307 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5311 return MM_ERROR_NONE;
5315 _mmplayer_start(MMHandleType hplayer)
5317 mmplayer_t *player = (mmplayer_t *)hplayer;
5318 gint ret = MM_ERROR_NONE;
5322 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5324 /* check current state */
5325 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5327 /* start pipeline */
5328 ret = _mmplayer_gst_start(player);
5329 if (ret != MM_ERROR_NONE)
5330 LOGE("failed to start player.");
5332 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5333 LOGD("force playing start even during buffering");
5334 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5342 /* NOTE: post "not supported codec message" to application
5343 * when one codec is not found during AUTOPLUGGING in MSL.
5344 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5345 * And, if any codec is not found, don't send message here.
5346 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5349 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5351 MMMessageParamType msg_param;
5352 memset(&msg_param, 0, sizeof(MMMessageParamType));
5353 gboolean post_msg_direct = FALSE;
5357 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5359 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5360 player->not_supported_codec, player->can_support_codec);
5362 if (player->not_found_demuxer) {
5363 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5364 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5366 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5367 MMPLAYER_FREEIF(msg_param.data);
5369 return MM_ERROR_NONE;
5372 if (player->not_supported_codec) {
5373 if (player->can_support_codec) {
5374 // There is one codec to play
5375 post_msg_direct = TRUE;
5377 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5378 post_msg_direct = TRUE;
5381 if (post_msg_direct) {
5382 MMMessageParamType msg_param;
5383 memset(&msg_param, 0, sizeof(MMMessageParamType));
5385 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5386 LOGW("not found AUDIO codec, posting error code to application.");
5388 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5389 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5390 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5391 LOGW("not found VIDEO codec, posting error code to application.");
5393 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5394 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5397 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5399 MMPLAYER_FREEIF(msg_param.data);
5401 return MM_ERROR_NONE;
5403 // no any supported codec case
5404 LOGW("not found any codec, posting error code to application.");
5406 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5407 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5408 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5410 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5411 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5414 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5416 MMPLAYER_FREEIF(msg_param.data);
5422 return MM_ERROR_NONE;
5426 __mmplayer_check_pipeline(mmplayer_t *player)
5428 GstState element_state = GST_STATE_VOID_PENDING;
5429 GstState element_pending_state = GST_STATE_VOID_PENDING;
5431 int ret = MM_ERROR_NONE;
5433 if (!player->gapless.reconfigure)
5436 LOGW("pipeline is under construction.");
5438 MMPLAYER_PLAYBACK_LOCK(player);
5439 MMPLAYER_PLAYBACK_UNLOCK(player);
5441 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5443 /* wait for state transition */
5444 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5445 if (ret == GST_STATE_CHANGE_FAILURE)
5446 LOGE("failed to change pipeline state within %d sec", timeout);
5449 /* NOTE : it should be able to call 'stop' anytime*/
5451 _mmplayer_stop(MMHandleType hplayer)
5453 mmplayer_t *player = (mmplayer_t *)hplayer;
5454 int ret = MM_ERROR_NONE;
5458 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5460 /* check current state */
5461 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5463 /* check pipline building state */
5464 __mmplayer_check_pipeline(player);
5465 __mmplayer_reset_gapless_state(player);
5467 /* NOTE : application should not wait for EOS after calling STOP */
5468 _mmplayer_cancel_eos_timer(player);
5471 player->seek_state = MMPLAYER_SEEK_NONE;
5474 ret = _mmplayer_gst_stop(player);
5476 if (ret != MM_ERROR_NONE)
5477 LOGE("failed to stop player.");
5485 _mmplayer_pause(MMHandleType hplayer)
5487 mmplayer_t *player = (mmplayer_t *)hplayer;
5488 gint64 pos_nsec = 0;
5489 gboolean async = FALSE;
5490 gint ret = MM_ERROR_NONE;
5494 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5496 /* check current state */
5497 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5499 /* check pipline building state */
5500 __mmplayer_check_pipeline(player);
5502 switch (MMPLAYER_CURRENT_STATE(player)) {
5503 case MM_PLAYER_STATE_READY:
5505 /* check prepare async or not.
5506 * In the case of streaming playback, it's recommned to avoid blocking wait.
5508 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5509 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5511 /* Changing back sync of rtspsrc to async */
5512 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5513 LOGD("async prepare working mode for rtsp");
5519 case MM_PLAYER_STATE_PLAYING:
5521 /* NOTE : store current point to overcome some bad operation
5522 *(returning zero when getting current position in paused state) of some
5525 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5526 LOGW("getting current position failed in paused");
5528 player->last_position = pos_nsec;
5530 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5531 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5532 This causes problem is position calculation during normal pause resume scenarios also.
5533 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5534 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5535 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5536 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5542 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5543 LOGD("doing async pause in case of ms buff src");
5547 /* pause pipeline */
5548 ret = _mmplayer_gst_pause(player, async);
5550 if (ret != MM_ERROR_NONE)
5551 LOGE("failed to pause player. ret : 0x%x", ret);
5553 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5554 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5555 LOGE("failed to update display_rotation");
5563 /* in case of streaming, pause could take long time.*/
5565 _mmplayer_abort_pause(MMHandleType hplayer)
5567 mmplayer_t *player = (mmplayer_t *)hplayer;
5568 int ret = MM_ERROR_NONE;
5572 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5574 player->pipeline->mainbin,
5575 MM_ERROR_PLAYER_NOT_INITIALIZED);
5577 LOGD("set the pipeline state to READY");
5579 /* set state to READY */
5580 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5581 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5582 if (ret != MM_ERROR_NONE) {
5583 LOGE("fail to change state to READY");
5584 return MM_ERROR_PLAYER_INTERNAL;
5587 LOGD("succeeded in changing state to READY");
5592 _mmplayer_resume(MMHandleType hplayer)
5594 mmplayer_t *player = (mmplayer_t *)hplayer;
5595 int ret = MM_ERROR_NONE;
5596 gboolean async = FALSE;
5600 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5602 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5603 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5604 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5608 /* Changing back sync mode rtspsrc to async */
5609 LOGD("async resume for rtsp case");
5613 /* check current state */
5614 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5616 ret = _mmplayer_gst_resume(player, async);
5617 if (ret != MM_ERROR_NONE)
5618 LOGE("failed to resume player.");
5620 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5621 LOGD("force resume even during buffering");
5622 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5631 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5633 mmplayer_t *player = (mmplayer_t *)hplayer;
5634 gint64 pos_nsec = 0;
5635 int ret = MM_ERROR_NONE;
5637 signed long long start = 0, stop = 0;
5638 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5641 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5642 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5644 /* The sound of video is not supported under 0.0 and over 2.0. */
5645 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5646 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5649 _mmplayer_set_mute(hplayer, mute);
5651 if (player->playback_rate == rate)
5652 return MM_ERROR_NONE;
5654 /* If the position is reached at start potion during fast backward, EOS is posted.
5655 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5657 player->playback_rate = rate;
5659 current_state = MMPLAYER_CURRENT_STATE(player);
5661 if (current_state != MM_PLAYER_STATE_PAUSED)
5662 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5664 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5666 if ((current_state == MM_PLAYER_STATE_PAUSED)
5667 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5668 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5669 pos_nsec = player->last_position;
5674 stop = GST_CLOCK_TIME_NONE;
5676 start = GST_CLOCK_TIME_NONE;
5680 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5681 player->playback_rate,
5683 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5684 GST_SEEK_TYPE_SET, start,
5685 GST_SEEK_TYPE_SET, stop)) {
5686 LOGE("failed to set speed playback");
5687 return MM_ERROR_PLAYER_SEEK;
5690 LOGD("succeeded to set speed playback as %0.1f", rate);
5694 return MM_ERROR_NONE;;
5698 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5700 mmplayer_t *player = (mmplayer_t *)hplayer;
5701 int ret = MM_ERROR_NONE;
5705 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5707 /* check pipline building state */
5708 __mmplayer_check_pipeline(player);
5710 ret = _mmplayer_gst_set_position(player, position, FALSE);
5718 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5720 mmplayer_t *player = (mmplayer_t *)hplayer;
5721 int ret = MM_ERROR_NONE;
5723 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5724 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5726 if (g_strrstr(player->type, "video/mpegts"))
5727 __mmplayer_update_duration_value(player);
5729 *duration = player->duration;
5734 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5736 mmplayer_t *player = (mmplayer_t *)hplayer;
5737 int ret = MM_ERROR_NONE;
5739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5741 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5747 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5749 mmplayer_t *player = (mmplayer_t *)hplayer;
5750 int ret = MM_ERROR_NONE;
5754 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5756 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5764 __mmplayer_is_midi_type(gchar *str_caps)
5766 if ((g_strrstr(str_caps, "audio/midi")) ||
5767 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5768 (g_strrstr(str_caps, "application/x-smaf")) ||
5769 (g_strrstr(str_caps, "audio/x-imelody")) ||
5770 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5771 (g_strrstr(str_caps, "audio/xmf")) ||
5772 (g_strrstr(str_caps, "audio/mxmf"))) {
5781 __mmplayer_is_only_mp3_type(gchar *str_caps)
5783 if (g_strrstr(str_caps, "application/x-id3") ||
5784 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5790 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5792 GstStructure *caps_structure = NULL;
5793 gint samplerate = 0;
5797 MMPLAYER_RETURN_IF_FAIL(player && caps);
5799 caps_structure = gst_caps_get_structure(caps, 0);
5801 /* set stream information */
5802 gst_structure_get_int(caps_structure, "rate", &samplerate);
5803 gst_structure_get_int(caps_structure, "channels", &channels);
5805 mm_player_set_attribute((MMHandleType)player, NULL,
5806 "content_audio_samplerate", samplerate,
5807 "content_audio_channels", channels, NULL);
5809 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5813 __mmplayer_update_content_type_info(mmplayer_t *player)
5816 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5818 if (__mmplayer_is_midi_type(player->type)) {
5819 player->bypass_audio_effect = TRUE;
5823 if (!player->streamer) {
5824 LOGD("no need to check streaming type");
5828 if (g_strrstr(player->type, "application/x-hls")) {
5829 /* If it can't know exact type when it parses uri because of redirection case,
5830 * it will be fixed by typefinder or when doing autoplugging.
5832 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5833 player->streamer->is_adaptive_streaming = TRUE;
5834 } else if (g_strrstr(player->type, "application/dash+xml")) {
5835 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5836 player->streamer->is_adaptive_streaming = TRUE;
5839 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5840 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5841 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5843 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5844 if (player->streamer->is_adaptive_streaming)
5845 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5847 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5851 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5856 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5857 GstCaps *caps, gpointer data)
5859 mmplayer_t *player = (mmplayer_t *)data;
5864 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5866 /* store type string */
5867 MMPLAYER_FREEIF(player->type);
5868 player->type = gst_caps_to_string(caps);
5870 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5871 player, player->type, probability, gst_caps_get_size(caps));
5873 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5874 (g_strrstr(player->type, "audio/x-raw-int"))) {
5875 LOGE("not support media format");
5877 if (player->msg_posted == FALSE) {
5878 MMMessageParamType msg_param;
5879 memset(&msg_param, 0, sizeof(MMMessageParamType));
5881 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5882 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5884 /* don't post more if one was sent already */
5885 player->msg_posted = TRUE;
5890 __mmplayer_update_content_type_info(player);
5892 pad = gst_element_get_static_pad(tf, "src");
5894 LOGE("fail to get typefind src pad.");
5898 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5899 gboolean async = FALSE;
5900 LOGE("failed to autoplug %s", player->type);
5902 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5904 if (async && player->msg_posted == FALSE)
5905 __mmplayer_handle_missed_plugin(player);
5909 gst_object_unref(GST_OBJECT(pad));
5917 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5919 GstElement *decodebin = NULL;
5923 /* create decodebin */
5924 decodebin = gst_element_factory_make("decodebin", NULL);
5927 LOGE("fail to create decodebin");
5931 /* raw pad handling signal */
5932 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5933 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5935 /* no-more-pad pad handling signal */
5936 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5937 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5939 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5940 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5942 /* This signal is emitted when a pad for which there is no further possible
5943 decoding is added to the decodebin.*/
5944 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5945 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5947 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5948 before looking for any elements that can handle that stream.*/
5949 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5950 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5952 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5953 before looking for any elements that can handle that stream.*/
5954 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5955 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5957 /* This signal is emitted once decodebin has finished decoding all the data.*/
5958 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5959 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5961 /* This signal is emitted when a element is added to the bin.*/
5962 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5963 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5970 __mmplayer_gst_make_queue2(mmplayer_t *player)
5972 GstElement *queue2 = NULL;
5973 gint64 dur_bytes = 0L;
5974 mmplayer_gst_element_t *mainbin = NULL;
5975 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5978 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5980 mainbin = player->pipeline->mainbin;
5982 queue2 = gst_element_factory_make("queue2", "queue2");
5984 LOGE("failed to create buffering queue element");
5988 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5989 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5991 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5993 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5994 * skip the pull mode(file or ring buffering) setting. */
5995 if (dur_bytes > 0) {
5996 if (!g_strrstr(player->type, "video/mpegts")) {
5997 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5998 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6004 _mm_player_streaming_set_queue2(player->streamer,
6008 (guint64)dur_bytes); /* no meaning at the moment */
6014 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6016 mmplayer_gst_element_t *mainbin = NULL;
6017 GstElement *decodebin = NULL;
6018 GstElement *queue2 = NULL;
6019 GstPad *sinkpad = NULL;
6020 GstPad *qsrcpad = NULL;
6023 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6025 mainbin = player->pipeline->mainbin;
6027 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6029 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6030 LOGW("need to check: muxed buffer is not null");
6033 queue2 = __mmplayer_gst_make_queue2(player);
6035 LOGE("failed to make queue2");
6039 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6040 LOGE("failed to add buffering queue");
6044 sinkpad = gst_element_get_static_pad(queue2, "sink");
6045 qsrcpad = gst_element_get_static_pad(queue2, "src");
6047 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6048 LOGE("failed to link [%s:%s]-[%s:%s]",
6049 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6053 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6054 LOGE("failed to sync queue2 state with parent");
6058 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6059 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6063 gst_object_unref(GST_OBJECT(sinkpad));
6067 /* create decodebin */
6068 decodebin = _mmplayer_gst_make_decodebin(player);
6070 LOGE("failed to make decodebin");
6074 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6075 LOGE("failed to add decodebin");
6079 /* to force caps on the decodebin element and avoid reparsing stuff by
6080 * typefind. It also avoids a deadlock in the way typefind activates pads in
6081 * the state change */
6082 g_object_set(decodebin, "sink-caps", caps, NULL);
6084 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6086 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6087 LOGE("failed to link [%s:%s]-[%s:%s]",
6088 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6092 gst_object_unref(GST_OBJECT(sinkpad));
6094 gst_object_unref(GST_OBJECT(qsrcpad));
6097 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6098 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6100 /* set decodebin property about buffer in streaming playback. *
6101 * in case of HLS/DASH, it does not need to have big buffer *
6102 * because it is kind of adaptive streaming. */
6103 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6104 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6105 gint high_percent = 0;
6107 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6108 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6110 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6112 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6114 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6115 "high-percent", high_percent,
6116 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6117 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6118 "max-size-buffers", 0, NULL); // disable or automatic
6121 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6122 LOGE("failed to sync decodebin state with parent");
6133 gst_object_unref(GST_OBJECT(sinkpad));
6136 gst_object_unref(GST_OBJECT(qsrcpad));
6139 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6140 * You need to explicitly set elements to the NULL state before
6141 * dropping the final reference, to allow them to clean up.
6143 gst_element_set_state(queue2, GST_STATE_NULL);
6145 /* And, it still has a parent "player".
6146 * You need to let the parent manage the object instead of unreffing the object directly.
6148 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6149 gst_object_unref(queue2);
6154 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6155 * You need to explicitly set elements to the NULL state before
6156 * dropping the final reference, to allow them to clean up.
6158 gst_element_set_state(decodebin, GST_STATE_NULL);
6160 /* And, it still has a parent "player".
6161 * You need to let the parent manage the object instead of unreffing the object directly.
6164 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6165 gst_object_unref(decodebin);
6173 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6177 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6178 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6180 LOGD("class : %s, mime : %s", factory_class, mime);
6182 /* add missing plugin */
6183 /* NOTE : msl should check missing plugin for image mime type.
6184 * Some motion jpeg clips can have playable audio track.
6185 * So, msl have to play audio after displaying popup written video format not supported.
6187 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6188 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6189 LOGD("not found demuxer");
6190 player->not_found_demuxer = TRUE;
6191 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6197 if (!g_strrstr(factory_class, "Demuxer")) {
6198 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6199 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6200 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6202 /* check that clip have multi tracks or not */
6203 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6204 LOGD("video plugin is already linked");
6206 LOGW("add VIDEO to missing plugin");
6207 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6208 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6210 } else if (g_str_has_prefix(mime, "audio")) {
6211 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6212 LOGD("audio plugin is already linked");
6214 LOGW("add AUDIO to missing plugin");
6215 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6216 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6224 return MM_ERROR_NONE;
6228 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6230 mmplayer_t *player = (mmplayer_t *)data;
6234 MMPLAYER_RETURN_IF_FAIL(player);
6236 /* remove fakesink. */
6237 if (!_mmplayer_gst_remove_fakesink(player,
6238 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6239 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6240 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6241 * source element are not same. To overcome this situation, this function will called
6242 * several places and several times. Therefore, this is not an error case.
6247 LOGD("[handle: %p] pipeline has completely constructed", player);
6249 if ((player->ini.async_start) &&
6250 (player->msg_posted == FALSE) &&
6251 (player->cmd >= MMPLAYER_COMMAND_START))
6252 __mmplayer_handle_missed_plugin(player);
6254 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6258 __mmplayer_check_profile(void)
6261 static int profile_tv = -1;
6263 if (__builtin_expect(profile_tv != -1, 1))
6266 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6267 switch (*profileName) {
6282 __mmplayer_get_next_uri(mmplayer_t *player)
6284 mmplayer_parse_profile_t profile;
6286 guint num_of_list = 0;
6289 num_of_list = g_list_length(player->uri_info.uri_list);
6290 uri_idx = player->uri_info.uri_idx;
6292 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6293 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6294 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6296 LOGW("next uri does not exist");
6300 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6301 LOGE("failed to parse profile");
6305 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6306 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6307 LOGW("uri type is not supported(%d)", profile.uri_type);
6311 LOGD("success to find next uri %d", uri_idx);
6315 if (!uri || uri_idx == num_of_list) {
6316 LOGE("failed to find next uri");
6320 player->uri_info.uri_idx = uri_idx;
6321 if (mm_player_set_attribute((MMHandleType)player, NULL,
6322 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6323 LOGE("failed to set attribute");
6327 SECURE_LOGD("next playback uri: %s", uri);
6332 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6334 #define REPEAT_COUNT_INFINITE -1
6335 #define REPEAT_COUNT_MIN 2
6336 #define ORIGINAL_URI_ONLY 1
6338 MMHandleType attrs = 0;
6342 guint num_of_uri = 0;
6343 int profile_tv = -1;
6347 LOGD("checking for gapless play option");
6349 if (player->build_audio_offload) {
6350 LOGE("offload path is not supportable.");
6354 if (player->pipeline->textbin) {
6355 LOGE("subtitle path is enabled. gapless play is not supported.");
6359 attrs = MMPLAYER_GET_ATTRS(player);
6361 LOGE("fail to get attributes.");
6365 mm_attrs_multiple_get(player->attrs, NULL,
6366 "content_video_found", &video,
6367 "profile_play_count", &count,
6368 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6370 /* gapless playback is not supported in case of video at TV profile. */
6371 profile_tv = __mmplayer_check_profile();
6372 if (profile_tv && video) {
6373 LOGW("not support video gapless playback");
6377 /* check repeat count in case of audio */
6379 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6380 LOGW("gapless is disabled");
6384 num_of_uri = g_list_length(player->uri_info.uri_list);
6386 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6388 if (num_of_uri == ORIGINAL_URI_ONLY) {
6389 /* audio looping path */
6390 if (count >= REPEAT_COUNT_MIN) {
6391 /* decrease play count */
6392 /* we succeeded to rewind. update play count and then wait for next EOS */
6394 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6395 } else if (count != REPEAT_COUNT_INFINITE) {
6396 LOGD("there is no next uri and no repeat");
6399 LOGD("looping cnt %d", count);
6401 /* gapless playback path */
6402 if (!__mmplayer_get_next_uri(player)) {
6403 LOGE("failed to get next uri");
6410 LOGE("unable to play gapless path. EOS will be posted soon");
6415 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6417 mmplayer_selector_t *selector = &player->selector[type];
6418 mmplayer_gst_element_t *sinkbin = NULL;
6419 main_element_id_e selectorId = MMPLAYER_M_NUM;
6420 main_element_id_e sinkId = MMPLAYER_M_NUM;
6421 GstPad *srcpad = NULL;
6422 GstPad *sinkpad = NULL;
6423 gboolean send_notice = FALSE;
6426 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6428 LOGD("type %d", type);
6431 case MM_PLAYER_TRACK_TYPE_AUDIO:
6432 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6433 sinkId = MMPLAYER_A_BIN;
6434 sinkbin = player->pipeline->audiobin;
6436 case MM_PLAYER_TRACK_TYPE_VIDEO:
6437 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6438 sinkId = MMPLAYER_V_BIN;
6439 sinkbin = player->pipeline->videobin;
6442 case MM_PLAYER_TRACK_TYPE_TEXT:
6443 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6444 sinkId = MMPLAYER_T_BIN;
6445 sinkbin = player->pipeline->textbin;
6448 LOGE("requested type is not supportable");
6453 if (player->pipeline->mainbin[selectorId].gst) {
6456 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6458 if (selector->event_probe_id != 0)
6459 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6460 selector->event_probe_id = 0;
6462 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6463 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6465 if (srcpad && sinkpad) {
6466 /* after getting drained signal there is no data flows, so no need to do pad_block */
6467 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6468 gst_pad_unlink(srcpad, sinkpad);
6470 /* send custom event to sink pad to handle it at video sink */
6472 LOGD("send custom event to sinkpad");
6473 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6474 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6475 gst_pad_send_event(sinkpad, event);
6479 gst_object_unref(sinkpad);
6482 gst_object_unref(srcpad);
6485 LOGD("selector release");
6487 /* release and unref requests pad from the selector */
6488 for (n = 0; n < selector->channels->len; n++) {
6489 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6490 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6492 g_ptr_array_set_size(selector->channels, 0);
6494 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6495 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6497 player->pipeline->mainbin[selectorId].gst = NULL;
6505 __mmplayer_deactivate_old_path(mmplayer_t *player)
6508 MMPLAYER_RETURN_IF_FAIL(player);
6510 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6511 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6512 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6513 LOGE("deactivate selector error");
6517 _mmplayer_track_destroy(player);
6518 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6520 if (player->streamer) {
6521 _mm_player_streaming_initialize(player->streamer, FALSE);
6522 _mm_player_streaming_destroy(player->streamer);
6523 player->streamer = NULL;
6526 MMPLAYER_PLAYBACK_LOCK(player);
6527 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6534 if (!player->msg_posted) {
6535 MMMessageParamType msg = {0,};
6538 msg.code = MM_ERROR_PLAYER_INTERNAL;
6539 LOGE("gapless_uri_play> deactivate error");
6541 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6542 player->msg_posted = TRUE;
6548 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6550 int result = MM_ERROR_NONE;
6551 mmplayer_t *player = (mmplayer_t *)hplayer;
6554 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6555 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6557 if (mm_player_set_attribute(hplayer, NULL,
6558 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6559 LOGE("failed to set attribute");
6560 result = MM_ERROR_PLAYER_INTERNAL;
6562 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6563 LOGE("failed to add the original uri in the uri list.");
6571 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6573 mmplayer_t *player = (mmplayer_t *)hplayer;
6574 guint num_of_list = 0;
6578 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6579 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6581 if (player->pipeline && player->pipeline->textbin) {
6582 LOGE("subtitle path is enabled.");
6583 return MM_ERROR_PLAYER_INVALID_STATE;
6586 num_of_list = g_list_length(player->uri_info.uri_list);
6588 if (is_first_path) {
6589 if (num_of_list == 0) {
6590 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6591 SECURE_LOGD("add original path : %s", uri);
6593 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6594 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6596 SECURE_LOGD("change original path : %s", uri);
6599 MMHandleType attrs = 0;
6600 attrs = MMPLAYER_GET_ATTRS(player);
6602 if (num_of_list == 0) {
6603 char *original_uri = NULL;
6606 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6608 if (!original_uri) {
6609 LOGE("there is no original uri.");
6610 return MM_ERROR_PLAYER_INVALID_STATE;
6613 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6614 player->uri_info.uri_idx = 0;
6616 SECURE_LOGD("add original path at first : %s", original_uri);
6620 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6621 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6625 return MM_ERROR_NONE;
6629 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6631 mmplayer_t *player = (mmplayer_t *)hplayer;
6632 char *next_uri = NULL;
6633 guint num_of_list = 0;
6636 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6638 num_of_list = g_list_length(player->uri_info.uri_list);
6640 if (num_of_list > 0) {
6641 gint uri_idx = player->uri_info.uri_idx;
6643 if (uri_idx < num_of_list-1)
6648 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6649 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6651 *uri = g_strdup(next_uri);
6655 return MM_ERROR_NONE;
6659 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6660 GstCaps *caps, gpointer data)
6662 mmplayer_t *player = (mmplayer_t *)data;
6663 const gchar *klass = NULL;
6664 const gchar *mime = NULL;
6665 gchar *caps_str = NULL;
6667 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6668 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6669 caps_str = gst_caps_to_string(caps);
6671 LOGW("unknown type of caps : %s from %s",
6672 caps_str, GST_ELEMENT_NAME(elem));
6674 MMPLAYER_FREEIF(caps_str);
6676 /* There is no available codec. */
6677 __mmplayer_check_not_supported_codec(player, klass, mime);
6681 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6682 GstCaps *caps, gpointer data)
6684 mmplayer_t *player = (mmplayer_t *)data;
6685 const char *mime = NULL;
6686 gboolean ret = TRUE;
6688 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6689 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6691 if (g_str_has_prefix(mime, "audio")) {
6692 GstStructure *caps_structure = NULL;
6693 gint samplerate = 0;
6695 gchar *caps_str = NULL;
6697 caps_structure = gst_caps_get_structure(caps, 0);
6698 gst_structure_get_int(caps_structure, "rate", &samplerate);
6699 gst_structure_get_int(caps_structure, "channels", &channels);
6701 if ((channels > 0 && samplerate == 0)) {
6702 LOGD("exclude audio...");
6706 caps_str = gst_caps_to_string(caps);
6707 /* set it directly because not sent by TAG */
6708 if (g_strrstr(caps_str, "mobile-xmf"))
6709 mm_player_set_attribute((MMHandleType)player, NULL,
6710 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6712 MMPLAYER_FREEIF(caps_str);
6713 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6714 MMMessageParamType msg_param;
6715 memset(&msg_param, 0, sizeof(MMMessageParamType));
6716 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6717 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6718 LOGD("video file is not supported on this device");
6720 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6721 LOGD("already video linked");
6724 LOGD("found new stream");
6731 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6733 gboolean ret = TRUE;
6734 GDBusConnection *conn = NULL;
6736 GVariant *result = NULL;
6737 const gchar *dbus_device_type = NULL;
6738 const gchar *dbus_ret = NULL;
6741 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6743 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6749 result = g_dbus_connection_call_sync(conn,
6750 "org.pulseaudio.Server",
6751 "/org/pulseaudio/StreamManager",
6752 "org.pulseaudio.StreamManager",
6753 "GetCurrentMediaRoutingPath",
6754 g_variant_new("(s)", "out"),
6755 G_VARIANT_TYPE("(ss)"),
6756 G_DBUS_CALL_FLAGS_NONE,
6760 if (!result || err) {
6761 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6767 /* device type is listed in stream-map.json at mmfw-sysconf */
6768 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6770 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6771 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6776 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6777 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6778 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6779 LOGD("audio offload is supportable");
6785 LOGD("audio offload is not supportable");
6789 g_variant_unref(result);
6790 g_object_unref(conn);
6795 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6797 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6798 gint64 position = 0;
6800 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6801 player->pipeline && player->pipeline->mainbin);
6803 MMPLAYER_CMD_LOCK(player);
6804 current_state = MMPLAYER_CURRENT_STATE(player);
6806 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6807 LOGW("getting current position failed in paused");
6809 _mmplayer_unrealize((MMHandleType)player);
6810 _mmplayer_realize((MMHandleType)player);
6812 _mmplayer_set_position((MMHandleType)player, position);
6814 /* async not to be blocked in streaming case */
6815 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6817 _mmplayer_pause((MMHandleType)player);
6819 if (current_state == MM_PLAYER_STATE_PLAYING)
6820 _mmplayer_start((MMHandleType)player);
6821 MMPLAYER_CMD_UNLOCK(player);
6823 LOGD("rebuilding audio pipeline is completed.");
6826 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6828 mmplayer_t *player = (mmplayer_t *)user_data;
6829 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6830 gboolean is_supportable = FALSE;
6832 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6833 LOGW("failed to get device type");
6835 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6837 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6838 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6839 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6840 LOGD("ignore this dev connected info");
6844 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6845 if (player->build_audio_offload == is_supportable) {
6846 LOGD("keep current pipeline without re-building");
6850 /* rebuild pipeline */
6851 LOGD("re-build pipeline - offload: %d", is_supportable);
6852 player->build_audio_offload = FALSE;
6853 __mmplayer_rebuild_audio_pipeline(player);
6859 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6861 unsigned int id = 0;
6863 if (player->audio_device_cb_id != 0) {
6864 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6868 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6869 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6870 LOGD("added device connected cb (%u)", id);
6871 player->audio_device_cb_id = id;
6873 LOGW("failed to add device connected cb");
6880 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6882 mmplayer_t *player = (mmplayer_t *)hplayer;
6885 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6886 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6888 *activated = player->build_audio_offload;
6890 LOGD("offload activated : %d", (int)*activated);
6893 return MM_ERROR_NONE;
6897 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6900 this function need to be updated according to the supported media format
6901 @see player->ini.audio_offload_media_format */
6903 if (__mmplayer_is_only_mp3_type(player->type)) {
6904 LOGD("offload supportable media format type");
6912 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6914 gboolean ret = FALSE;
6915 GstElementFactory *factory = NULL;
6918 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6920 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6921 if (!__mmplayer_is_offload_supported_type(player))
6924 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6925 LOGD("there is no audio offload sink");
6929 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6930 LOGW("there is no audio device type to support offload");
6934 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6936 LOGW("there is no installed audio offload sink element");
6939 gst_object_unref(factory);
6941 if (__mmplayer_acquire_hw_resource(player,
6942 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6943 LOGE("failed to acquire audio offload decoder resource");
6947 if (!__mmplayer_add_audio_device_connected_cb(player))
6950 if (!__mmplayer_is_audio_offload_device_type(player))
6953 LOGD("audio offload can be built");
6958 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6964 static GstAutoplugSelectResult
6965 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6967 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6969 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6970 int audio_offload = 0;
6972 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6973 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6975 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6976 LOGD("expose audio path to build offload output path");
6977 player->build_audio_offload = TRUE;
6978 /* update codec info */
6979 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6980 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6981 player->audiodec_linked = 1;
6983 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6987 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6989 LOGD("audio codec type: %d", codec_type);
6990 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6991 /* sw codec will be skipped */
6992 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6993 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6994 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6995 ret = GST_AUTOPLUG_SELECT_SKIP;
6999 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7000 /* hw codec will be skipped */
7001 if (strcmp(player->ini.audiocodec_element_hw, "") &&
7002 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
7003 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
7004 ret = GST_AUTOPLUG_SELECT_SKIP;
7009 /* set stream information */
7010 if (!player->audiodec_linked)
7011 __mmplayer_set_audio_attrs(player, caps);
7013 /* update codec info */
7014 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7015 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7016 player->audiodec_linked = 1;
7018 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7020 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7022 LOGD("video codec type: %d", codec_type);
7023 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7024 /* sw codec is skipped */
7025 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7026 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7027 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7028 ret = GST_AUTOPLUG_SELECT_SKIP;
7032 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7033 /* hw codec is skipped */
7034 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7035 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7036 ret = GST_AUTOPLUG_SELECT_SKIP;
7041 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7042 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7044 /* mark video decoder for acquire */
7045 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7046 LOGW("video decoder resource is already acquired, skip it.");
7047 ret = GST_AUTOPLUG_SELECT_SKIP;
7051 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7052 LOGE("failed to acquire video decoder resource");
7053 ret = GST_AUTOPLUG_SELECT_SKIP;
7056 player->interrupted_by_resource = FALSE;
7059 /* update codec info */
7060 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7061 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7062 player->videodec_linked = 1;
7070 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7071 GstCaps *caps, GstElementFactory *factory, gpointer data)
7073 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7074 mmplayer_t *player = (mmplayer_t *)data;
7076 gchar *factory_name = NULL;
7077 gchar *caps_str = NULL;
7078 const gchar *klass = NULL;
7081 factory_name = GST_OBJECT_NAME(factory);
7082 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7083 caps_str = gst_caps_to_string(caps);
7085 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7087 /* store type string */
7088 if (player->type == NULL) {
7089 player->type = gst_caps_to_string(caps);
7090 __mmplayer_update_content_type_info(player);
7093 /* filtering exclude keyword */
7094 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7095 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7096 LOGW("skipping [%s] by exculde keyword [%s]",
7097 factory_name, player->ini.exclude_element_keyword[idx]);
7099 result = GST_AUTOPLUG_SELECT_SKIP;
7104 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7105 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7106 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7107 factory_name, player->ini.unsupported_codec_keyword[idx]);
7108 result = GST_AUTOPLUG_SELECT_SKIP;
7113 /* exclude webm format */
7114 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7115 * because webm format is not supportable.
7116 * If webm is disabled in "autoplug-continue", there is no state change
7117 * failure or error because the decodebin will expose the pad directly.
7118 * It make MSL invoke _prepare_async_callback.
7119 * So, we need to disable webm format in "autoplug-select" */
7120 if (caps_str && strstr(caps_str, "webm")) {
7121 LOGW("webm is not supported");
7122 result = GST_AUTOPLUG_SELECT_SKIP;
7126 /* check factory class for filtering */
7127 /* NOTE : msl don't need to use image plugins.
7128 * So, those plugins should be skipped for error handling.
7130 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7131 LOGD("skipping [%s] by not required", factory_name);
7132 result = GST_AUTOPLUG_SELECT_SKIP;
7136 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7137 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7138 // TO CHECK : subtitle if needed, add subparse exception.
7139 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7140 result = GST_AUTOPLUG_SELECT_SKIP;
7144 if (g_strrstr(factory_name, "mpegpsdemux")) {
7145 LOGD("skipping PS container - not support");
7146 result = GST_AUTOPLUG_SELECT_SKIP;
7150 if (g_strrstr(factory_name, "mssdemux"))
7151 player->smooth_streaming = TRUE;
7153 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7154 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7157 GstStructure *str = NULL;
7158 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7160 /* don't make video because of not required */
7161 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7162 (!player->set_mode.video_export)) {
7163 LOGD("no need video decoding, expose pad");
7164 result = GST_AUTOPLUG_SELECT_EXPOSE;
7168 /* get w/h for omx state-tune */
7169 /* FIXME: deprecated? */
7170 str = gst_caps_get_structure(caps, 0);
7171 gst_structure_get_int(str, "width", &width);
7174 if (player->v_stream_caps) {
7175 gst_caps_unref(player->v_stream_caps);
7176 player->v_stream_caps = NULL;
7179 player->v_stream_caps = gst_caps_copy(caps);
7180 LOGD("take caps for video state tune");
7181 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7185 if (g_strrstr(klass, "Codec/Decoder")) {
7186 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7187 if (result != GST_AUTOPLUG_SELECT_TRY) {
7188 LOGW("skip add decoder");
7194 MMPLAYER_FREEIF(caps_str);
7200 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7203 //mmplayer_t *player = (mmplayer_t *)data;
7204 GstCaps *caps = NULL;
7206 LOGD("[Decodebin2] pad-removed signal");
7208 caps = gst_pad_query_caps(new_pad, NULL);
7210 LOGW("query caps is NULL");
7214 gchar *caps_str = NULL;
7215 caps_str = gst_caps_to_string(caps);
7217 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7219 MMPLAYER_FREEIF(caps_str);
7220 gst_caps_unref(caps);
7224 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7226 mmplayer_t *player = (mmplayer_t *)data;
7227 GstIterator *iter = NULL;
7228 GValue item = { 0, };
7230 gboolean done = FALSE;
7231 gboolean is_all_drained = TRUE;
7234 MMPLAYER_RETURN_IF_FAIL(player);
7236 LOGD("__mmplayer_gst_decode_drained");
7238 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7239 LOGW("Fail to get cmd lock");
7243 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7244 !__mmplayer_verify_gapless_play_path(player)) {
7245 LOGD("decoding is finished.");
7246 __mmplayer_reset_gapless_state(player);
7247 MMPLAYER_CMD_UNLOCK(player);
7251 player->gapless.reconfigure = TRUE;
7253 /* check decodebin src pads whether they received EOS or not */
7254 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7257 switch (gst_iterator_next(iter, &item)) {
7258 case GST_ITERATOR_OK:
7259 pad = g_value_get_object(&item);
7260 if (pad && !GST_PAD_IS_EOS(pad)) {
7261 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7262 is_all_drained = FALSE;
7265 g_value_reset(&item);
7267 case GST_ITERATOR_RESYNC:
7268 gst_iterator_resync(iter);
7270 case GST_ITERATOR_ERROR:
7271 case GST_ITERATOR_DONE:
7276 g_value_unset(&item);
7277 gst_iterator_free(iter);
7279 if (!is_all_drained) {
7280 LOGD("Wait util the all pads get EOS.");
7281 MMPLAYER_CMD_UNLOCK(player);
7286 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7287 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7289 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7290 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7291 __mmplayer_deactivate_old_path(player);
7292 MMPLAYER_CMD_UNLOCK(player);
7298 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7300 mmplayer_t *player = (mmplayer_t *)data;
7301 const gchar *klass = NULL;
7302 gchar *factory_name = NULL;
7304 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7305 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7307 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7309 if (__mmplayer_add_dump_buffer_probe(player, element))
7310 LOGD("add buffer probe");
7312 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7313 gchar *selected = NULL;
7314 selected = g_strdup(GST_ELEMENT_NAME(element));
7315 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7318 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7319 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7320 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7322 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7323 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7325 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7326 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7327 "max-video-width", player->adaptive_info.limit.width,
7328 "max-video-height", player->adaptive_info.limit.height, NULL);
7330 } else if (g_strrstr(klass, "Demuxer")) {
7332 LOGD("plugged element is demuxer. take it");
7334 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7335 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7338 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7339 int surface_type = 0;
7341 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7344 // to support trust-zone only
7345 if (g_strrstr(factory_name, "asfdemux")) {
7346 LOGD("set file-location %s", player->profile.uri);
7347 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7348 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7349 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7350 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7351 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7352 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7353 (__mmplayer_is_only_mp3_type(player->type))) {
7354 LOGD("[mpegaudioparse] set streaming pull mode.");
7355 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7357 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7358 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7361 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7362 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7363 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7365 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7366 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7368 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7369 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7370 (MMPLAYER_IS_DASH_STREAMING(player))) {
7371 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7372 _mm_player_streaming_set_multiqueue(player->streamer, element);
7373 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7382 __mmplayer_release_misc(mmplayer_t *player)
7385 bool cur_mode = player->set_mode.rich_audio;
7388 MMPLAYER_RETURN_IF_FAIL(player);
7390 player->video_decoded_cb = NULL;
7391 player->video_decoded_cb_user_param = NULL;
7392 player->video_stream_prerolled = false;
7394 player->audio_decoded_cb = NULL;
7395 player->audio_decoded_cb_user_param = NULL;
7396 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7398 player->audio_stream_changed_cb = NULL;
7399 player->audio_stream_changed_cb_user_param = NULL;
7401 player->sent_bos = FALSE;
7402 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7404 player->seek_state = MMPLAYER_SEEK_NONE;
7406 player->total_bitrate = 0;
7407 player->total_maximum_bitrate = 0;
7409 player->not_found_demuxer = 0;
7411 player->last_position = 0;
7412 player->duration = 0;
7413 player->http_content_size = 0;
7414 player->not_supported_codec = MISSING_PLUGIN_NONE;
7415 player->can_support_codec = FOUND_PLUGIN_NONE;
7416 player->pending_seek.is_pending = false;
7417 player->pending_seek.pos = 0;
7418 player->msg_posted = FALSE;
7419 player->has_many_types = FALSE;
7420 player->is_subtitle_force_drop = FALSE;
7421 player->play_subtitle = FALSE;
7422 player->adjust_subtitle_pos = 0;
7423 player->has_closed_caption = FALSE;
7424 player->set_mode.video_export = false;
7425 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7426 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7428 player->set_mode.rich_audio = cur_mode;
7430 if (player->audio_device_cb_id > 0 &&
7431 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7432 LOGW("failed to remove audio device_connected_callback");
7433 player->audio_device_cb_id = 0;
7435 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7436 player->bitrate[i] = 0;
7437 player->maximum_bitrate[i] = 0;
7440 /* free memory related to audio effect */
7441 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7443 if (player->adaptive_info.var_list) {
7444 g_list_free_full(player->adaptive_info.var_list, g_free);
7445 player->adaptive_info.var_list = NULL;
7448 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7449 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7450 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7452 /* Reset video360 settings to their defaults in case if the pipeline is to be
7455 player->video360_metadata.is_spherical = -1;
7456 player->is_openal_plugin_used = FALSE;
7458 player->is_content_spherical = FALSE;
7459 player->is_video360_enabled = TRUE;
7460 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7461 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7462 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7463 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7464 player->video360_zoom = 1.0f;
7465 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7466 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7468 player->sound.rg_enable = false;
7470 __mmplayer_initialize_video_roi(player);
7475 __mmplayer_release_misc_post(mmplayer_t *player)
7477 char *original_uri = NULL;
7480 /* player->pipeline is already released before. */
7482 MMPLAYER_RETURN_IF_FAIL(player);
7484 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7486 /* clean found audio decoders */
7487 if (player->audio_decoders) {
7488 GList *a_dec = player->audio_decoders;
7489 for (; a_dec; a_dec = g_list_next(a_dec)) {
7490 gchar *name = a_dec->data;
7491 MMPLAYER_FREEIF(name);
7493 g_list_free(player->audio_decoders);
7494 player->audio_decoders = NULL;
7497 /* clean the uri list except original uri */
7498 if (player->uri_info.uri_list) {
7499 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7502 LOGW("failed to get original uri info");
7504 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7505 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7507 GList *uri_list = player->uri_info.uri_list;
7508 for (; uri_list; uri_list = g_list_next(uri_list)) {
7509 gchar *uri = uri_list->data;
7510 MMPLAYER_FREEIF(uri);
7512 g_list_free(player->uri_info.uri_list);
7513 player->uri_info.uri_list = NULL;
7516 /* clear the audio stream buffer list */
7517 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7519 /* clear the video stream bo list */
7520 __mmplayer_video_stream_destroy_bo_list(player);
7521 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7523 if (player->profile.input_mem.buf) {
7524 free(player->profile.input_mem.buf);
7525 player->profile.input_mem.buf = NULL;
7527 player->profile.input_mem.len = 0;
7528 player->profile.input_mem.offset = 0;
7530 player->uri_info.uri_idx = 0;
7535 __mmplayer_check_subtitle(mmplayer_t *player)
7537 MMHandleType attrs = 0;
7538 char *subtitle_uri = NULL;
7542 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7544 /* get subtitle attribute */
7545 attrs = MMPLAYER_GET_ATTRS(player);
7549 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7550 if (!subtitle_uri || !strlen(subtitle_uri))
7553 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7554 player->is_external_subtitle_present = TRUE;
7562 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7564 MMPLAYER_RETURN_IF_FAIL(player);
7566 if (player->eos_timer) {
7567 LOGD("cancel eos timer");
7568 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7569 player->eos_timer = 0;
7576 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7580 MMPLAYER_RETURN_IF_FAIL(player);
7581 MMPLAYER_RETURN_IF_FAIL(sink);
7583 player->sink_elements = g_list_append(player->sink_elements, sink);
7589 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7593 MMPLAYER_RETURN_IF_FAIL(player);
7594 MMPLAYER_RETURN_IF_FAIL(sink);
7596 player->sink_elements = g_list_remove(player->sink_elements, sink);
7602 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7603 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7605 mmplayer_signal_item_t *item = NULL;
7608 MMPLAYER_RETURN_IF_FAIL(player);
7610 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7611 LOGE("invalid signal type [%d]", type);
7615 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7617 LOGE("cannot connect signal [%s]", signal);
7622 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7623 player->signals[type] = g_list_append(player->signals[type], item);
7629 /* NOTE : be careful with calling this api. please refer to below glib comment
7630 * glib comment : Note that there is a bug in GObject that makes this function much
7631 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7632 * will no longer be called, but, the signal handler is not currently disconnected.
7633 * If the instance is itself being freed at the same time than this doesn't matter,
7634 * since the signal will automatically be removed, but if instance persists,
7635 * then the signal handler will leak. You should not remove the signal yourself
7636 * because in a future versions of GObject, the handler will automatically be
7639 * It's possible to work around this problem in a way that will continue to work
7640 * with future versions of GObject by checking that the signal handler is still
7641 * connected before disconnected it:
7643 * if (g_signal_handler_is_connected(instance, id))
7644 * g_signal_handler_disconnect(instance, id);
7647 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7649 GList *sig_list = NULL;
7650 mmplayer_signal_item_t *item = NULL;
7654 MMPLAYER_RETURN_IF_FAIL(player);
7656 LOGD("release signals type : %d", type);
7658 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7659 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7660 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7661 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7662 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7663 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7667 sig_list = player->signals[type];
7669 for (; sig_list; sig_list = sig_list->next) {
7670 item = sig_list->data;
7672 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7673 if (g_signal_handler_is_connected(item->obj, item->sig))
7674 g_signal_handler_disconnect(item->obj, item->sig);
7677 MMPLAYER_FREEIF(item);
7680 g_list_free(player->signals[type]);
7681 player->signals[type] = NULL;
7689 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, unsigned int wl_surface_id)
7691 mmplayer_t *player = 0;
7692 int prev_display_surface_type = 0;
7696 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7698 player = MM_PLAYER_CAST(handle);
7700 /* check video sinkbin is created */
7701 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7702 LOGW("Videosink is already created");
7703 return MM_ERROR_NONE;
7706 LOGD("videosink element is not yet ready");
7708 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7709 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7711 return MM_ERROR_INVALID_ARGUMENT;
7714 /* load previous attributes */
7715 if (player->attrs) {
7716 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7717 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7718 if (prev_display_surface_type == surface_type) {
7719 LOGD("incoming display surface type is same as previous one, do nothing..");
7721 return MM_ERROR_NONE;
7724 LOGE("failed to load attributes");
7726 return MM_ERROR_PLAYER_INTERNAL;
7729 /* videobin is not created yet, so we just set attributes related to display surface */
7730 LOGD("store display attribute for given surface type(%d)", surface_type);
7731 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7732 "display_overlay", (int)wl_surface_id, NULL);
7735 return MM_ERROR_NONE;
7738 /* Note : if silent is true, then subtitle would not be displayed. :*/
7740 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7742 mmplayer_t *player = (mmplayer_t *)hplayer;
7746 /* check player handle */
7747 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7749 player->set_mode.subtitle_off = silent;
7751 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7755 return MM_ERROR_NONE;
7759 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7761 mmplayer_gst_element_t *mainbin = NULL;
7762 mmplayer_gst_element_t *textbin = NULL;
7763 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7764 GstState current_state = GST_STATE_VOID_PENDING;
7765 GstState element_state = GST_STATE_VOID_PENDING;
7766 GstState element_pending_state = GST_STATE_VOID_PENDING;
7768 GstEvent *event = NULL;
7769 int result = MM_ERROR_NONE;
7771 GstClock *curr_clock = NULL;
7772 GstClockTime base_time, start_time, curr_time;
7777 /* check player handle */
7778 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7780 player->pipeline->mainbin &&
7781 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7783 mainbin = player->pipeline->mainbin;
7784 textbin = player->pipeline->textbin;
7786 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7788 // sync clock with current pipeline
7789 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7790 curr_time = gst_clock_get_time(curr_clock);
7792 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7793 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7795 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7796 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7798 if (current_state > GST_STATE_READY) {
7799 // sync state with current pipeline
7800 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7801 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7802 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7804 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7805 if (GST_STATE_CHANGE_FAILURE == ret) {
7806 LOGE("fail to state change.");
7807 result = MM_ERROR_PLAYER_INTERNAL;
7811 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7812 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7815 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7816 gst_object_unref(curr_clock);
7819 // seek to current position
7820 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7821 result = MM_ERROR_PLAYER_INVALID_STATE;
7822 LOGE("gst_element_query_position failed, invalid state");
7826 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7827 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);
7829 _mmplayer_gst_send_event_to_sink(player, event);
7831 result = MM_ERROR_PLAYER_INTERNAL;
7832 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7836 /* sync state with current pipeline */
7837 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7838 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7839 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7841 return MM_ERROR_NONE;
7844 /* release text pipeline resource */
7845 player->textsink_linked = 0;
7847 /* release signal */
7848 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7850 /* release textbin with it's childs */
7851 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7852 MMPLAYER_FREEIF(player->pipeline->textbin);
7853 player->pipeline->textbin = NULL;
7855 /* release subtitle elem */
7856 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7857 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7863 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7865 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7866 GstState current_state = GST_STATE_VOID_PENDING;
7868 MMHandleType attrs = 0;
7869 mmplayer_gst_element_t *mainbin = NULL;
7870 mmplayer_gst_element_t *textbin = NULL;
7872 gchar *subtitle_uri = NULL;
7873 int result = MM_ERROR_NONE;
7874 const gchar *charset = NULL;
7878 /* check player handle */
7879 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7881 player->pipeline->mainbin &&
7882 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7883 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7885 mainbin = player->pipeline->mainbin;
7886 textbin = player->pipeline->textbin;
7888 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7889 if (current_state < GST_STATE_READY) {
7890 result = MM_ERROR_PLAYER_INVALID_STATE;
7891 LOGE("Pipeline is not in proper state");
7895 attrs = MMPLAYER_GET_ATTRS(player);
7897 LOGE("cannot get content attribute");
7898 result = MM_ERROR_PLAYER_INTERNAL;
7902 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7903 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7904 LOGE("subtitle uri is not proper filepath");
7905 result = MM_ERROR_PLAYER_INVALID_URI;
7909 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7910 LOGE("failed to get storage info of subtitle path");
7911 result = MM_ERROR_PLAYER_INVALID_URI;
7915 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7916 SECURE_LOGD("new subtitle file path is [%s]", filepath);
7918 if (!strcmp(filepath, subtitle_uri)) {
7919 LOGD("subtitle path is not changed");
7922 if (mm_player_set_attribute((MMHandleType)player, NULL,
7923 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7924 LOGE("failed to set attribute");
7929 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7930 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7931 player->subtitle_language_list = NULL;
7932 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7934 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7935 if (ret != GST_STATE_CHANGE_SUCCESS) {
7936 LOGE("failed to change state of textbin to READY");
7937 result = MM_ERROR_PLAYER_INTERNAL;
7941 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7942 if (ret != GST_STATE_CHANGE_SUCCESS) {
7943 LOGE("failed to change state of subparse to READY");
7944 result = MM_ERROR_PLAYER_INTERNAL;
7948 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7949 if (ret != GST_STATE_CHANGE_SUCCESS) {
7950 LOGE("failed to change state of filesrc to READY");
7951 result = MM_ERROR_PLAYER_INTERNAL;
7955 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7957 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7959 charset = _mmplayer_get_charset(filepath);
7961 LOGD("detected charset is %s", charset);
7962 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7965 result = _mmplayer_sync_subtitle_pipeline(player);
7972 /* API to switch between external subtitles */
7974 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7976 int result = MM_ERROR_NONE;
7977 mmplayer_t *player = (mmplayer_t *)hplayer;
7982 /* check player handle */
7983 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7985 /* filepath can be null in idle state */
7987 /* check file path */
7988 if ((path = strstr(filepath, "file://")))
7989 result = _mmplayer_exist_file_path(path + 7);
7991 result = _mmplayer_exist_file_path(filepath);
7993 if (result != MM_ERROR_NONE) {
7994 LOGE("invalid subtitle path 0x%X", result);
7995 return result; /* file not found or permission denied */
7999 if (!player->pipeline) {
8001 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8002 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8003 LOGE("failed to set attribute");
8004 return MM_ERROR_PLAYER_INTERNAL;
8007 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8008 /* check filepath */
8009 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8011 if (!__mmplayer_check_subtitle(player)) {
8012 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8013 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8014 LOGE("failed to set attribute");
8015 return MM_ERROR_PLAYER_INTERNAL;
8018 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8019 LOGE("fail to create text pipeline");
8020 return MM_ERROR_PLAYER_INTERNAL;
8023 result = _mmplayer_sync_subtitle_pipeline(player);
8025 result = __mmplayer_change_external_subtitle_language(player, filepath);
8028 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8029 player->is_external_subtitle_added_now = TRUE;
8031 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8032 if (!player->subtitle_language_list) {
8033 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8034 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8035 LOGW("subtitle language list is not updated yet");
8037 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8045 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8047 int result = MM_ERROR_NONE;
8048 gchar *change_pad_name = NULL;
8049 GstPad *sinkpad = NULL;
8050 mmplayer_gst_element_t *mainbin = NULL;
8051 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8052 GstCaps *caps = NULL;
8053 gint total_track_num = 0;
8057 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8058 MM_ERROR_PLAYER_NOT_INITIALIZED);
8060 LOGD("Change Track(%d) to %d", type, index);
8062 mainbin = player->pipeline->mainbin;
8064 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8065 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8066 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8067 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8069 /* Changing Video Track is not supported. */
8070 LOGE("Track Type Error");
8074 if (mainbin[elem_idx].gst == NULL) {
8075 result = MM_ERROR_PLAYER_NO_OP;
8076 LOGD("Req track doesn't exist");
8080 total_track_num = player->selector[type].total_track_num;
8081 if (total_track_num <= 0) {
8082 result = MM_ERROR_PLAYER_NO_OP;
8083 LOGD("Language list is not available");
8087 if ((index < 0) || (index >= total_track_num)) {
8088 result = MM_ERROR_INVALID_ARGUMENT;
8089 LOGD("Not a proper index : %d", index);
8093 /*To get the new pad from the selector*/
8094 change_pad_name = g_strdup_printf("sink_%u", index);
8095 if (change_pad_name == NULL) {
8096 result = MM_ERROR_PLAYER_INTERNAL;
8097 LOGD("Pad does not exists");
8101 LOGD("new active pad name: %s", change_pad_name);
8103 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8104 if (sinkpad == NULL) {
8105 LOGD("sinkpad is NULL");
8106 result = MM_ERROR_PLAYER_INTERNAL;
8110 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8111 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8113 caps = gst_pad_get_current_caps(sinkpad);
8114 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8117 gst_object_unref(sinkpad);
8119 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8120 __mmplayer_set_audio_attrs(player, caps);
8123 MMPLAYER_FREEIF(change_pad_name);
8128 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8130 int result = MM_ERROR_NONE;
8131 mmplayer_t *player = NULL;
8132 mmplayer_gst_element_t *mainbin = NULL;
8134 gint current_active_index = 0;
8136 GstState current_state = GST_STATE_VOID_PENDING;
8137 GstEvent *event = NULL;
8142 player = (mmplayer_t *)hplayer;
8143 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8145 if (!player->pipeline) {
8146 LOGE("Track %d pre setting -> %d", type, index);
8148 player->selector[type].active_pad_index = index;
8152 mainbin = player->pipeline->mainbin;
8154 current_active_index = player->selector[type].active_pad_index;
8156 /*If index is same as running index no need to change the pad*/
8157 if (current_active_index == index)
8160 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8161 result = MM_ERROR_PLAYER_INVALID_STATE;
8165 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8166 if (current_state < GST_STATE_PAUSED) {
8167 result = MM_ERROR_PLAYER_INVALID_STATE;
8168 LOGW("Pipeline not in porper state");
8172 result = __mmplayer_change_selector_pad(player, type, index);
8173 if (result != MM_ERROR_NONE) {
8174 LOGE("change selector pad error");
8178 player->selector[type].active_pad_index = index;
8180 if (current_state == GST_STATE_PLAYING) {
8181 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8182 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8183 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8185 _mmplayer_gst_send_event_to_sink(player, event);
8187 result = MM_ERROR_PLAYER_INTERNAL;
8197 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8199 mmplayer_t *player = (mmplayer_t *)hplayer;
8203 /* check player handle */
8204 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8206 *silent = player->set_mode.subtitle_off;
8208 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8212 return MM_ERROR_NONE;
8216 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8218 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8219 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8221 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8222 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8226 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8227 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8228 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8229 mmplayer_dump_t *dump_s;
8230 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8231 if (dump_s == NULL) {
8232 LOGE("malloc fail");
8236 dump_s->dump_element_file = NULL;
8237 dump_s->dump_pad = NULL;
8238 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8240 if (dump_s->dump_pad) {
8241 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8242 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]);
8243 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8244 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);
8245 /* add list for removed buffer probe and close FILE */
8246 player->dump_list = g_list_append(player->dump_list, dump_s);
8247 LOGD("%s sink pad added buffer probe for dump", factory_name);
8250 MMPLAYER_FREEIF(dump_s);
8251 LOGE("failed to get %s sink pad added", factory_name);
8258 static GstPadProbeReturn
8259 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8261 FILE *dump_data = (FILE *)u_data;
8263 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8264 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8266 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8268 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8270 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8272 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8274 gst_buffer_unmap(buffer, &probe_info);
8276 return GST_PAD_PROBE_OK;
8280 __mmplayer_release_dump_list(GList *dump_list)
8282 GList *d_list = dump_list;
8287 for (; d_list; d_list = g_list_next(d_list)) {
8288 mmplayer_dump_t *dump_s = d_list->data;
8289 if (dump_s->dump_pad) {
8290 if (dump_s->probe_handle_id)
8291 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8292 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8294 if (dump_s->dump_element_file) {
8295 fclose(dump_s->dump_element_file);
8296 dump_s->dump_element_file = NULL;
8298 MMPLAYER_FREEIF(dump_s);
8300 g_list_free(dump_list);
8305 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8307 mmplayer_t *player = (mmplayer_t *)hplayer;
8311 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8312 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8314 *exist = (bool)player->has_closed_caption;
8318 return MM_ERROR_NONE;
8322 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8327 LOGD("unref internal gst buffer %p", buffer);
8329 gst_buffer_unref((GstBuffer *)buffer);
8336 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8338 mmplayer_t *player = (mmplayer_t *)hplayer;
8342 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8343 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8345 if (MMPLAYER_IS_STREAMING(player))
8346 *timeout = (int)player->ini.live_state_change_timeout;
8348 *timeout = (int)player->ini.localplayback_state_change_timeout;
8350 LOGD("timeout = %d", *timeout);
8353 return MM_ERROR_NONE;
8357 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8361 MMPLAYER_RETURN_IF_FAIL(player);
8363 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8365 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8366 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8367 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8368 player->storage_info[i].id = -1;
8369 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8371 if (path_type != MMPLAYER_PATH_MAX)
8380 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8382 int ret = MM_ERROR_NONE;
8383 mmplayer_t *player = (mmplayer_t *)hplayer;
8384 MMMessageParamType msg_param = {0, };
8387 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8389 LOGW("state changed storage %d:%d", id, state);
8391 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8392 return MM_ERROR_NONE;
8394 /* FIXME: text path should be handled seperately. */
8395 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8396 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8397 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8398 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8399 LOGW("external storage is removed");
8401 if (player->msg_posted == FALSE) {
8402 memset(&msg_param, 0, sizeof(MMMessageParamType));
8403 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8404 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8405 player->msg_posted = TRUE;
8408 /* unrealize the player */
8409 ret = _mmplayer_unrealize(hplayer);
8410 if (ret != MM_ERROR_NONE)
8411 LOGE("failed to unrealize");
8419 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8421 int ret = MM_ERROR_NONE;
8422 mmplayer_t *player = (mmplayer_t *)hplayer;
8423 int idx = 0, total = 0;
8424 gchar *result = NULL, *tmp = NULL;
8427 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8428 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8430 total = *num = g_list_length(player->adaptive_info.var_list);
8432 LOGW("There is no stream variant info.");
8436 result = g_strdup("");
8437 for (idx = 0 ; idx < total ; idx++) {
8438 stream_variant_t *v_data = NULL;
8439 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8442 gchar data[64] = {0};
8443 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8445 tmp = g_strconcat(result, data, NULL);
8449 LOGW("There is no variant data in %d", idx);
8454 *var_info = (char *)result;
8456 LOGD("variant info %d:%s", *num, *var_info);
8462 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8464 int ret = MM_ERROR_NONE;
8465 mmplayer_t *player = (mmplayer_t *)hplayer;
8468 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8470 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8472 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8473 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8474 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8476 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8477 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8478 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8479 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8481 /* FIXME: seek to current position for applying new variant limitation */
8490 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8492 int ret = MM_ERROR_NONE;
8493 mmplayer_t *player = (mmplayer_t *)hplayer;
8496 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8497 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8499 *bandwidth = player->adaptive_info.limit.bandwidth;
8500 *width = player->adaptive_info.limit.width;
8501 *height = player->adaptive_info.limit.height;
8503 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8510 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8512 int ret = MM_ERROR_NONE;
8513 mmplayer_t *player = (mmplayer_t *)hplayer;
8516 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8517 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8518 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8520 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8522 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8523 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8524 else /* live case */
8525 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8527 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8534 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8536 #define IDX_FIRST_SW_CODEC 0
8537 mmplayer_t *player = (mmplayer_t *)hplayer;
8538 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8541 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8543 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8544 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8545 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8547 switch (stream_type) {
8548 case MM_PLAYER_STREAM_TYPE_AUDIO:
8549 /* to support audio codec selection, codec info have to be added in ini file as below.
8550 audio codec element hw = xxxx
8551 audio codec element sw = avdec */
8552 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8553 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8554 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8555 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8556 LOGE("There is no audio codec info for codec_type %d", codec_type);
8557 return MM_ERROR_PLAYER_NO_OP;
8560 case MM_PLAYER_STREAM_TYPE_VIDEO:
8561 /* to support video codec selection, codec info have to be added in ini file as below.
8562 video codec element hw = omx
8563 video codec element sw = avdec */
8564 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8565 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8566 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8567 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8568 LOGE("There is no video codec info for codec_type %d", codec_type);
8569 return MM_ERROR_PLAYER_NO_OP;
8573 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8574 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8578 LOGD("update %s codec_type to %d", attr_name, codec_type);
8579 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8582 return MM_ERROR_NONE;
8586 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8588 mmplayer_t *player = (mmplayer_t *)hplayer;
8589 GstElement *rg_vol_element = NULL;
8593 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8595 player->sound.rg_enable = enabled;
8597 /* just hold rgvolume enable value if pipeline is not ready */
8598 if (!player->pipeline || !player->pipeline->audiobin) {
8599 LOGD("pipeline is not ready. holding rgvolume enable value");
8600 return MM_ERROR_NONE;
8603 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8605 if (!rg_vol_element) {
8606 LOGD("rgvolume element is not created");
8607 return MM_ERROR_PLAYER_INTERNAL;
8611 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8613 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8617 return MM_ERROR_NONE;
8621 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8623 mmplayer_t *player = (mmplayer_t *)hplayer;
8624 GstElement *rg_vol_element = NULL;
8625 gboolean enable = FALSE;
8629 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8630 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8632 /* just hold enable_rg value if pipeline is not ready */
8633 if (!player->pipeline || !player->pipeline->audiobin) {
8634 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8635 *enabled = player->sound.rg_enable;
8636 return MM_ERROR_NONE;
8639 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8641 if (!rg_vol_element) {
8642 LOGD("rgvolume element is not created");
8643 return MM_ERROR_PLAYER_INTERNAL;
8646 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8647 *enabled = (bool)enable;
8651 return MM_ERROR_NONE;
8655 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8657 mmplayer_t *player = (mmplayer_t *)hplayer;
8658 MMHandleType attrs = 0;
8660 int ret = MM_ERROR_NONE;
8664 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8666 attrs = MMPLAYER_GET_ATTRS(player);
8667 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8669 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8671 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8672 return MM_ERROR_PLAYER_INTERNAL;
8675 player->video_roi.scale_x = scale_x;
8676 player->video_roi.scale_y = scale_y;
8677 player->video_roi.scale_width = scale_width;
8678 player->video_roi.scale_height = scale_height;
8680 /* check video sinkbin is created */
8681 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8682 return MM_ERROR_NONE;
8684 if (!gst_video_overlay_set_video_roi_area(
8685 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8686 scale_x, scale_y, scale_width, scale_height))
8687 ret = MM_ERROR_PLAYER_INTERNAL;
8689 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8690 scale_x, scale_y, scale_width, scale_height);
8698 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8700 mmplayer_t *player = (mmplayer_t *)hplayer;
8701 int ret = MM_ERROR_NONE;
8705 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8706 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8708 *scale_x = player->video_roi.scale_x;
8709 *scale_y = player->video_roi.scale_y;
8710 *scale_width = player->video_roi.scale_width;
8711 *scale_height = player->video_roi.scale_height;
8713 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8714 *scale_x, *scale_y, *scale_width, *scale_height);
8720 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8722 mmplayer_t* player = (mmplayer_t*)hplayer;
8726 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8728 player->client_pid = pid;
8730 LOGD("client pid[%d] %p", pid, player);
8734 return MM_ERROR_NONE;
8738 __mmplayer_update_duration_value(mmplayer_t *player)
8740 gboolean ret = FALSE;
8741 gint64 dur_nsec = 0;
8742 LOGD("try to update duration");
8744 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8745 player->duration = dur_nsec;
8746 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8750 if (player->duration < 0) {
8751 LOGW("duration is Non-Initialized !!!");
8752 player->duration = 0;
8755 /* update streaming service type */
8756 player->streaming_type = _mmplayer_get_stream_service_type(player);
8758 /* check duration is OK */
8759 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8760 /* FIXIT : find another way to get duration here. */
8761 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8767 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8769 /* update audio params
8770 NOTE : We need original audio params and it can be only obtained from src pad of audio
8771 decoder. Below code only valid when we are not using 'resampler' just before
8772 'audioconverter'. */
8773 GstCaps *caps_a = NULL;
8775 gint samplerate = 0, channels = 0;
8776 GstStructure *p = NULL;
8777 GstElement *aconv = NULL;
8779 LOGD("try to update audio attrs");
8781 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8783 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8784 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8785 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8786 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8788 LOGE("there is no audio converter");
8792 pad = gst_element_get_static_pad(aconv, "sink");
8795 LOGW("failed to get pad from audio converter");
8799 caps_a = gst_pad_get_current_caps(pad);
8801 LOGW("not ready to get audio caps");
8802 gst_object_unref(pad);
8806 p = gst_caps_get_structure(caps_a, 0);
8808 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8810 gst_structure_get_int(p, "rate", &samplerate);
8811 gst_structure_get_int(p, "channels", &channels);
8813 mm_player_set_attribute((MMHandleType)player, NULL,
8814 "content_audio_samplerate", samplerate,
8815 "content_audio_channels", channels, NULL);
8817 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8819 gst_caps_unref(caps_a);
8820 gst_object_unref(pad);
8826 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8828 LOGD("try to update video attrs");
8830 GstCaps *caps_v = NULL;
8834 GstStructure *p = NULL;
8836 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8837 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8839 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8841 LOGD("no videosink sink pad");
8845 caps_v = gst_pad_get_current_caps(pad);
8846 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8847 if (!caps_v && player->v_stream_caps) {
8848 caps_v = player->v_stream_caps;
8849 gst_caps_ref(caps_v);
8853 LOGD("no negitiated caps from videosink");
8854 gst_object_unref(pad);
8858 p = gst_caps_get_structure(caps_v, 0);
8859 gst_structure_get_int(p, "width", &width);
8860 gst_structure_get_int(p, "height", &height);
8862 mm_player_set_attribute((MMHandleType)player, NULL,
8863 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
8865 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8867 SECURE_LOGD("width : %d height : %d", width, height);
8869 gst_caps_unref(caps_v);
8870 gst_object_unref(pad);
8873 mm_player_set_attribute((MMHandleType)player, NULL,
8874 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
8875 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8882 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8884 gboolean ret = FALSE;
8885 guint64 data_size = 0;
8889 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8890 if (!player->duration)
8893 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8894 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8895 if (stat(path, &sb) == 0)
8896 data_size = (guint64)sb.st_size;
8898 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8899 data_size = player->http_content_size;
8902 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8905 guint64 bitrate = 0;
8906 guint64 msec_dur = 0;
8908 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8910 bitrate = data_size * 8 * 1000 / msec_dur;
8911 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
8912 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8913 mm_player_set_attribute((MMHandleType)player, NULL,
8914 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
8917 LOGD("player duration is less than 0");
8921 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8922 if (player->total_bitrate) {
8923 mm_player_set_attribute((MMHandleType)player, NULL,
8924 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
8933 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8935 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8936 data->uri_type = uri_type;
8940 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8942 int ret = MM_ERROR_PLAYER_INVALID_URI;
8944 char *buffer = NULL;
8945 char *seperator = strchr(path, ',');
8946 char ext[100] = {0,}, size[100] = {0,};
8949 if ((buffer = strstr(path, "ext="))) {
8950 buffer += strlen("ext=");
8952 if (strlen(buffer)) {
8953 strncpy(ext, buffer, 99);
8955 if ((seperator = strchr(ext, ','))
8956 || (seperator = strchr(ext, ' '))
8957 || (seperator = strchr(ext, '\0'))) {
8958 seperator[0] = '\0';
8963 if ((buffer = strstr(path, "size="))) {
8964 buffer += strlen("size=");
8966 if (strlen(buffer) > 0) {
8967 strncpy(size, buffer, 99);
8969 if ((seperator = strchr(size, ','))
8970 || (seperator = strchr(size, ' '))
8971 || (seperator = strchr(size, '\0'))) {
8972 seperator[0] = '\0';
8975 mem_size = atoi(size);
8980 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8982 if (mem_size && param) {
8983 if (data->input_mem.buf)
8984 free(data->input_mem.buf);
8985 data->input_mem.buf = malloc(mem_size);
8987 if (data->input_mem.buf) {
8988 memcpy(data->input_mem.buf, param, mem_size);
8989 data->input_mem.len = mem_size;
8990 ret = MM_ERROR_NONE;
8992 LOGE("failed to alloc mem %d", mem_size);
8993 ret = MM_ERROR_PLAYER_INTERNAL;
8996 data->input_mem.offset = 0;
8997 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9004 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9006 gchar *location = NULL;
9009 int ret = MM_ERROR_NONE;
9011 if ((path = strstr(uri, "file://"))) {
9012 location = g_filename_from_uri(uri, NULL, &err);
9013 if (!location || (err != NULL)) {
9014 LOGE("Invalid URI '%s' for filesrc: %s", path,
9015 (err != NULL) ? err->message : "unknown error");
9019 MMPLAYER_FREEIF(location);
9021 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9022 return MM_ERROR_PLAYER_INVALID_URI;
9024 LOGD("path from uri: %s", location);
9027 path = (location != NULL) ? (location) : ((char *)uri);
9030 ret = _mmplayer_exist_file_path(path);
9032 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9033 if (ret == MM_ERROR_NONE) {
9034 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9035 if (_mmplayer_is_sdp_file(path)) {
9036 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9037 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9039 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9041 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9042 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9044 LOGE("invalid uri, could not play..");
9045 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9048 MMPLAYER_FREEIF(location);
9053 static mmplayer_video_decoded_data_info_t *
9054 __mmplayer_create_stream_from_pad(GstPad *pad)
9056 GstCaps *caps = NULL;
9057 GstStructure *structure = NULL;
9058 unsigned int fourcc = 0;
9059 const gchar *string_format = NULL;
9060 mmplayer_video_decoded_data_info_t *stream = NULL;
9062 MMPixelFormatType format;
9065 caps = gst_pad_get_current_caps(pad);
9067 LOGE("Caps is NULL.");
9072 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9074 structure = gst_caps_get_structure(caps, 0);
9075 gst_structure_get_int(structure, "width", &width);
9076 gst_structure_get_int(structure, "height", &height);
9077 string_format = gst_structure_get_string(structure, "format");
9080 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9081 format = _mmplayer_get_pixtype(fourcc);
9082 gst_video_info_from_caps(&info, caps);
9083 gst_caps_unref(caps);
9086 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9087 LOGE("Wrong condition!!");
9091 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9093 LOGE("failed to alloc mem for video data");
9097 stream->width = width;
9098 stream->height = height;
9099 stream->format = format;
9100 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9106 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9108 unsigned int pitch = 0;
9109 unsigned int size = 0;
9111 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9114 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9115 bo = gst_tizen_memory_get_bos(mem, index);
9117 stream->bo[index] = tbm_bo_ref(bo);
9119 LOGE("failed to get bo for index %d", index);
9122 for (index = 0; index < stream->plane_num; index++) {
9123 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9124 stream->stride[index] = pitch;
9126 stream->elevation[index] = size / pitch;
9128 stream->elevation[index] = stream->height;
9133 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9135 if (stream->format == MM_PIXEL_FORMAT_I420) {
9136 int ret = TBM_SURFACE_ERROR_NONE;
9137 tbm_surface_h surface;
9138 tbm_surface_info_s info;
9140 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9142 ret = tbm_surface_get_info(surface, &info);
9143 if (ret != TBM_SURFACE_ERROR_NONE) {
9144 tbm_surface_destroy(surface);
9148 tbm_surface_destroy(surface);
9149 stream->stride[0] = info.planes[0].stride;
9150 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9151 stream->stride[1] = info.planes[1].stride;
9152 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9153 stream->stride[2] = info.planes[2].stride;
9154 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9155 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9156 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9157 stream->stride[0] = stream->width * 4;
9158 stream->elevation[0] = stream->height;
9159 stream->bo_size = stream->stride[0] * stream->height;
9161 LOGE("Not support format %d", stream->format);
9169 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9171 tbm_bo_handle thandle;
9173 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9174 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9175 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9179 unsigned char *src = NULL;
9180 unsigned char *dest = NULL;
9181 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9183 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9185 LOGE("fail to gst_memory_map");
9189 if (!mapinfo.data) {
9190 LOGE("data pointer is wrong");
9194 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9195 if (!stream->bo[0]) {
9196 LOGE("Fail to tbm_bo_alloc!!");
9200 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9202 LOGE("thandle pointer is wrong");
9206 if (stream->format == MM_PIXEL_FORMAT_I420) {
9207 src_stride[0] = GST_ROUND_UP_4(stream->width);
9208 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9209 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9210 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9213 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9214 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9216 for (i = 0; i < 3; i++) {
9217 src = mapinfo.data + src_offset[i];
9218 dest = thandle.ptr + dest_offset[i];
9223 for (j = 0; j < stream->height >> k; j++) {
9224 memcpy(dest, src, stream->width>>k);
9225 src += src_stride[i];
9226 dest += stream->stride[i];
9229 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9230 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9232 LOGE("Not support format %d", stream->format);
9236 tbm_bo_unmap(stream->bo[0]);
9237 gst_memory_unmap(mem, &mapinfo);
9243 tbm_bo_unmap(stream->bo[0]);
9246 gst_memory_unmap(mem, &mapinfo);
9252 __mmplayer_set_pause_state(mmplayer_t *player)
9254 if (player->sent_bos)
9257 /* rtsp case, get content attrs by GstMessage */
9258 if (MMPLAYER_IS_RTSP_STREAMING(player))
9261 /* it's first time to update all content attrs. */
9262 _mmplayer_update_content_attrs(player, ATTR_ALL);
9266 __mmplayer_set_playing_state(mmplayer_t *player)
9268 gchar *audio_codec = NULL;
9270 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9271 /* initialize because auto resume is done well. */
9272 player->resumed_by_rewind = FALSE;
9273 player->playback_rate = 1.0;
9276 if (player->sent_bos)
9279 /* try to get content metadata */
9281 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9282 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9283 * legacy mmfw-player api
9285 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9287 if ((player->cmd == MMPLAYER_COMMAND_START)
9288 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9289 __mmplayer_handle_missed_plugin(player);
9292 /* check audio codec field is set or not
9293 * we can get it from typefinder or codec's caps.
9295 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9297 /* The codec format can't be sent for audio only case like amr, mid etc.
9298 * Because, parser don't make related TAG.
9299 * So, if it's not set yet, fill it with found data.
9302 if (g_strrstr(player->type, "audio/midi"))
9303 audio_codec = "MIDI";
9304 else if (g_strrstr(player->type, "audio/x-amr"))
9305 audio_codec = "AMR";
9306 else if (g_strrstr(player->type, "audio/mpeg")
9307 && !g_strrstr(player->type, "mpegversion=(int)1"))
9308 audio_codec = "AAC";
9310 audio_codec = "unknown";
9312 if (mm_player_set_attribute((MMHandleType)player, NULL,
9313 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9314 LOGE("failed to set attribute");
9316 LOGD("set audio codec type with caps");