4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
212 /* This function should be called after the pipeline goes PAUSED or higher
215 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
217 static gboolean has_duration = FALSE;
218 static gboolean has_video_attrs = FALSE;
219 static gboolean has_audio_attrs = FALSE;
220 static gboolean has_bitrate = FALSE;
221 gboolean missing_only = FALSE;
222 gboolean all = FALSE;
223 MMHandleType attrs = 0;
227 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
229 /* check player state here */
230 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
231 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
232 /* give warning now only */
233 LOGW("be careful. content attributes may not available in this state ");
236 /* get content attribute first */
237 attrs = MMPLAYER_GET_ATTRS(player);
239 LOGE("cannot get content attribute");
243 /* get update flag */
245 if (flag & ATTR_MISSING_ONLY) {
247 LOGD("updating missed attr only");
250 if (flag & ATTR_ALL) {
252 has_duration = FALSE;
253 has_video_attrs = FALSE;
254 has_audio_attrs = FALSE;
257 LOGD("updating all attrs");
260 if (missing_only && all) {
261 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
262 missing_only = FALSE;
265 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
266 has_duration = __mmplayer_update_duration_value(player);
268 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
269 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
271 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
272 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
274 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
275 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
283 _mmplayer_get_stream_service_type(mmplayer_t *player)
285 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
289 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
291 player->pipeline->mainbin &&
292 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
293 STREAMING_SERVICE_NONE);
295 /* streaming service type if streaming */
296 if (!MMPLAYER_IS_STREAMING(player))
297 return STREAMING_SERVICE_NONE;
299 streaming_type = (player->duration == 0) ?
300 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
302 switch (streaming_type) {
303 case STREAMING_SERVICE_LIVE:
304 LOGD("it's live streaming");
306 case STREAMING_SERVICE_VOD:
307 LOGD("it's vod streaming");
310 LOGE("should not get here");
316 return streaming_type;
319 /* this function sets the player state and also report
320 * it to applicaton by calling callback function
323 _mmplayer_set_state(mmplayer_t *player, int state)
325 MMMessageParamType msg = {0, };
327 MMPLAYER_RETURN_IF_FAIL(player);
329 if (MMPLAYER_CURRENT_STATE(player) == state) {
330 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
331 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
335 /* update player states */
336 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
337 MMPLAYER_CURRENT_STATE(player) = state;
339 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
340 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
343 MMPLAYER_PRINT_STATE(player);
345 switch (MMPLAYER_CURRENT_STATE(player)) {
346 case MM_PLAYER_STATE_NULL:
347 case MM_PLAYER_STATE_READY:
349 case MM_PLAYER_STATE_PAUSED:
350 __mmplayer_set_pause_state(player);
352 case MM_PLAYER_STATE_PLAYING:
353 __mmplayer_set_playing_state(player);
355 case MM_PLAYER_STATE_NONE:
357 LOGW("invalid target state, there is nothing to do.");
362 /* post message to application */
363 if (MMPLAYER_TARGET_STATE(player) == state) {
364 /* fill the message with state of player */
365 msg.union_type = MM_MSG_UNION_STATE;
366 msg.state.previous = MMPLAYER_PREV_STATE(player);
367 msg.state.current = MMPLAYER_CURRENT_STATE(player);
369 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
371 /* state changed by resource callback */
372 if (player->interrupted_by_resource)
373 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
374 else /* state changed by usecase */
375 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
378 LOGD("intermediate state, do nothing.");
379 MMPLAYER_PRINT_STATE(player);
383 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
384 && !player->sent_bos) {
385 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
386 player->sent_bos = TRUE;
393 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
395 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
396 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
398 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
400 LOGD("incomming command : %d ", command);
402 current_state = MMPLAYER_CURRENT_STATE(player);
403 pending_state = MMPLAYER_PENDING_STATE(player);
405 MMPLAYER_PRINT_STATE(player);
408 case MMPLAYER_COMMAND_CREATE:
410 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
412 if (current_state == MM_PLAYER_STATE_NULL ||
413 current_state == MM_PLAYER_STATE_READY ||
414 current_state == MM_PLAYER_STATE_PAUSED ||
415 current_state == MM_PLAYER_STATE_PLAYING)
420 case MMPLAYER_COMMAND_DESTROY:
422 /* destroy can called anytime */
424 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
428 case MMPLAYER_COMMAND_REALIZE:
430 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
432 if (pending_state != MM_PLAYER_STATE_NONE) {
435 /* need ready state to realize */
436 if (current_state == MM_PLAYER_STATE_READY)
439 if (current_state != MM_PLAYER_STATE_NULL)
445 case MMPLAYER_COMMAND_UNREALIZE:
447 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
449 if (current_state == MM_PLAYER_STATE_NULL)
454 case MMPLAYER_COMMAND_START:
456 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
458 if (pending_state == MM_PLAYER_STATE_NONE) {
459 if (current_state == MM_PLAYER_STATE_PLAYING)
461 else if (current_state != MM_PLAYER_STATE_READY &&
462 current_state != MM_PLAYER_STATE_PAUSED)
464 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
466 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
467 LOGD("player is going to paused state, just change the pending state as playing");
474 case MMPLAYER_COMMAND_STOP:
476 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
478 if (current_state == MM_PLAYER_STATE_READY)
481 /* need playing/paused state to stop */
482 if (current_state != MM_PLAYER_STATE_PLAYING &&
483 current_state != MM_PLAYER_STATE_PAUSED)
488 case MMPLAYER_COMMAND_PAUSE:
490 if (MMPLAYER_IS_LIVE_STREAMING(player))
493 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
494 goto NOT_COMPLETED_SEEK;
496 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
498 if (pending_state == MM_PLAYER_STATE_NONE) {
499 if (current_state == MM_PLAYER_STATE_PAUSED)
501 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
503 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
505 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
506 if (current_state == MM_PLAYER_STATE_PAUSED)
507 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
514 case MMPLAYER_COMMAND_RESUME:
516 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
517 goto NOT_COMPLETED_SEEK;
519 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
521 if (pending_state == MM_PLAYER_STATE_NONE) {
522 if (current_state == MM_PLAYER_STATE_PLAYING)
524 else if (current_state != MM_PLAYER_STATE_PAUSED)
526 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
528 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
529 LOGD("player is going to paused state, just change the pending state as playing");
539 player->cmd = command;
541 return MM_ERROR_NONE;
544 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
545 MMPLAYER_STATE_GET_NAME(current_state), command);
546 return MM_ERROR_PLAYER_INVALID_STATE;
549 LOGW("not completed seek");
550 return MM_ERROR_PLAYER_DOING_SEEK;
553 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
554 return MM_ERROR_PLAYER_NO_OP;
557 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
558 return MM_ERROR_PLAYER_NO_OP;
561 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
563 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
564 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
567 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
568 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
570 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
571 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
573 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
574 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
577 LOGE("invalid mmplayer resource type %d", type);
578 return MM_ERROR_PLAYER_INTERNAL;
581 if (player->hw_resource[type] != NULL) {
582 LOGD("[%d type] resource was already acquired", type);
583 return MM_ERROR_NONE;
586 LOGD("mark for acquire [%d type] resource", type);
587 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
588 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
589 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
590 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
591 return MM_ERROR_PLAYER_INTERNAL;
594 rm_ret = mm_resource_manager_commit(player->resource_manager);
595 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
596 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
597 return MM_ERROR_PLAYER_INTERNAL;
601 return MM_ERROR_NONE;
604 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
606 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
610 if (player->hw_resource[type] == NULL) {
611 LOGD("there is no acquired [%d type] resource", type);
612 return MM_ERROR_NONE;
615 LOGD("mark for release [%d type] resource", type);
616 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
617 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
618 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
619 return MM_ERROR_PLAYER_INTERNAL;
622 player->hw_resource[type] = NULL;
624 rm_ret = mm_resource_manager_commit(player->resource_manager);
625 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
626 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
627 return MM_ERROR_PLAYER_INTERNAL;
631 return MM_ERROR_NONE;
635 __mmplayer_initialize_gapless_play(mmplayer_t *player)
641 player->smooth_streaming = FALSE;
642 player->videodec_linked = 0;
643 player->audiodec_linked = 0;
644 player->textsink_linked = 0;
645 player->is_external_subtitle_present = FALSE;
646 player->is_external_subtitle_added_now = FALSE;
647 player->not_supported_codec = MISSING_PLUGIN_NONE;
648 player->can_support_codec = FOUND_PLUGIN_NONE;
649 player->pending_seek.is_pending = false;
650 player->pending_seek.pos = 0;
651 player->msg_posted = FALSE;
652 player->has_many_types = FALSE;
653 player->no_more_pad = FALSE;
654 player->not_found_demuxer = 0;
655 player->seek_state = MMPLAYER_SEEK_NONE;
656 player->is_subtitle_force_drop = FALSE;
657 player->play_subtitle = FALSE;
658 player->adjust_subtitle_pos = 0;
660 player->total_bitrate = 0;
661 player->total_maximum_bitrate = 0;
663 _mmplayer_track_initialize(player);
664 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
666 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
667 player->bitrate[i] = 0;
668 player->maximum_bitrate[i] = 0;
671 if (player->v_stream_caps) {
672 gst_caps_unref(player->v_stream_caps);
673 player->v_stream_caps = NULL;
676 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
678 /* clean found audio decoders */
679 if (player->audio_decoders) {
680 GList *a_dec = player->audio_decoders;
681 for (; a_dec; a_dec = g_list_next(a_dec)) {
682 gchar *name = a_dec->data;
683 MMPLAYER_FREEIF(name);
685 g_list_free(player->audio_decoders);
686 player->audio_decoders = NULL;
689 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
695 __mmplayer_gapless_play_thread(gpointer data)
697 mmplayer_t *player = (mmplayer_t *)data;
698 mmplayer_gst_element_t *mainbin = NULL;
700 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
702 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
703 while (!player->gapless_play_thread_exit) {
704 LOGD("gapless play thread started. waiting for signal.");
705 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
707 LOGD("reconfigure pipeline for gapless play.");
709 if (player->gapless_play_thread_exit) {
710 if (player->gapless.reconfigure) {
711 player->gapless.reconfigure = false;
712 MMPLAYER_PLAYBACK_UNLOCK(player);
714 LOGD("exiting gapless play thread");
718 mainbin = player->pipeline->mainbin;
720 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
721 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
722 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
723 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
724 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
726 /* Initialize Player values */
727 __mmplayer_initialize_gapless_play(player);
729 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
731 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
737 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
739 GSource *source = NULL;
743 source = g_main_context_find_source_by_id(context, source_id);
744 if (source != NULL) {
745 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
746 g_source_destroy(source);
753 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
755 mmplayer_t *player = (mmplayer_t *)hplayer;
756 GstMessage *msg = NULL;
757 GQueue *queue = NULL;
760 MMPLAYER_RETURN_IF_FAIL(player);
762 /* disconnecting bus watch */
763 if (player->bus_watcher)
764 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
765 player->bus_watcher = 0;
767 /* destroy the gst bus msg thread */
768 if (player->bus_msg_thread) {
769 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
770 player->bus_msg_thread_exit = TRUE;
771 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
772 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
774 LOGD("gst bus msg thread exit.");
775 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
776 player->bus_msg_thread = NULL;
778 g_mutex_clear(&player->bus_msg_thread_mutex);
779 g_cond_clear(&player->bus_msg_thread_cond);
782 g_mutex_lock(&player->bus_msg_q_lock);
783 queue = player->bus_msg_q;
784 while (!g_queue_is_empty(queue)) {
785 msg = (GstMessage *)g_queue_pop_head(queue);
790 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
791 gst_message_unref(msg);
793 g_mutex_unlock(&player->bus_msg_q_lock);
799 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
801 GstElement *parent = NULL;
803 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
804 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
807 MMPLAYER_FSINK_LOCK(player);
809 /* get parent of fakesink */
810 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
812 LOGD("fakesink already removed");
816 gst_element_set_locked_state(fakesink->gst, TRUE);
818 /* setting the state to NULL never returns async
819 * so no need to wait for completion of state transiton
821 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
822 LOGE("fakesink state change failure!");
823 /* FIXIT : should I return here? or try to proceed to next? */
826 /* remove fakesink from it's parent */
827 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
828 LOGE("failed to remove fakesink");
830 gst_object_unref(parent);
835 gst_object_unref(parent);
837 LOGD("state-holder removed");
839 gst_element_set_locked_state(fakesink->gst, FALSE);
841 MMPLAYER_FSINK_UNLOCK(player);
846 gst_element_set_locked_state(fakesink->gst, FALSE);
848 MMPLAYER_FSINK_UNLOCK(player);
852 static GstPadProbeReturn
853 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
855 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
856 return GST_PAD_PROBE_OK;
860 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
862 gint64 stop_running_time = 0;
863 gint64 position_running_time = 0;
867 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
868 if ((player->gapless.update_segment[idx] == TRUE) ||
869 !(player->selector[idx].event_probe_id)) {
871 LOGW("[%d] skip", idx);
876 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
878 gst_segment_to_running_time(&player->gapless.segment[idx],
879 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
880 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
882 gst_segment_to_running_time(&player->gapless.segment[idx],
883 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
885 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
887 gst_segment_to_running_time(&player->gapless.segment[idx],
888 GST_FORMAT_TIME, player->duration);
891 position_running_time =
892 gst_segment_to_running_time(&player->gapless.segment[idx],
893 GST_FORMAT_TIME, player->gapless.segment[idx].position);
895 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
896 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
898 GST_TIME_ARGS(stop_running_time),
899 GST_TIME_ARGS(position_running_time),
900 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
901 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
903 position_running_time = MAX(position_running_time, stop_running_time);
904 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
905 GST_FORMAT_TIME, player->gapless.segment[idx].start);
906 position_running_time = MAX(0, position_running_time);
907 position = MAX(position, position_running_time);
911 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
912 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
913 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
915 player->gapless.start_time[stream_type] += position;
921 static GstPadProbeReturn
922 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
924 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
925 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
926 mmplayer_t *player = (mmplayer_t *)data;
927 GstCaps *caps = NULL;
928 GstStructure *str = NULL;
929 const gchar *name = NULL;
930 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
931 gboolean caps_ret = TRUE;
933 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
934 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
935 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
936 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
937 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
940 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
944 if (strstr(name, "audio")) {
945 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
946 } else if (strstr(name, "video")) {
947 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
949 /* text track is not supportable */
950 LOGE("invalid name %s", name);
954 switch (GST_EVENT_TYPE(event)) {
957 /* in case of gapless, drop eos event not to send it to sink */
958 if (player->gapless.reconfigure && !player->msg_posted) {
959 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
960 ret = GST_PAD_PROBE_DROP;
964 case GST_EVENT_STREAM_START:
966 __mmplayer_gst_selector_update_start_time(player, stream_type);
969 case GST_EVENT_FLUSH_STOP:
971 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
972 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
973 player->gapless.start_time[stream_type] = 0;
976 case GST_EVENT_SEGMENT:
981 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
982 gst_event_copy_segment(event, &segment);
984 if (segment.format != GST_FORMAT_TIME)
987 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
988 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
989 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
990 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
991 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
992 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
994 /* keep the all the segment ev to cover the seeking */
995 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
996 player->gapless.update_segment[stream_type] = TRUE;
998 if (!player->gapless.running)
1001 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1003 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1005 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1006 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1007 gst_event_unref(event);
1008 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1014 gdouble proportion = 0.0;
1015 GstClockTimeDiff diff = 0;
1016 GstClockTime timestamp = 0;
1017 gint64 running_time_diff = -1;
1018 GstQOSType type = 0;
1019 GstEvent *tmpev = NULL;
1021 running_time_diff = player->gapless.segment[stream_type].base;
1023 if (running_time_diff <= 0) /* don't need to adjust */
1026 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1027 gst_event_unref(event);
1029 if (timestamp < running_time_diff) {
1030 LOGW("QOS event from previous group");
1031 ret = GST_PAD_PROBE_DROP;
1036 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1037 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1038 stream_type, GST_TIME_ARGS(timestamp),
1039 GST_TIME_ARGS(running_time_diff),
1040 GST_TIME_ARGS(timestamp - running_time_diff));
1043 timestamp -= running_time_diff;
1045 /* That case is invalid for QoS events */
1046 if (diff < 0 && -diff > timestamp) {
1047 LOGW("QOS event from previous group");
1048 ret = GST_PAD_PROBE_DROP;
1052 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1053 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1063 gst_caps_unref(caps);
1067 /* create fakesink for audio or video path witout audiobin or videobin */
1069 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1071 GstElement *pipeline = NULL;
1072 GstElement *fakesink = NULL;
1073 GstPad *sinkpad = NULL;
1076 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1078 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1081 fakesink = gst_element_factory_make("fakesink", NULL);
1082 if (fakesink == NULL) {
1083 LOGE("failed to create fakesink");
1087 /* store it as it's sink element */
1088 __mmplayer_add_sink(player, fakesink);
1090 gst_bin_add(GST_BIN(pipeline), fakesink);
1093 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1095 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1097 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1098 LOGE("failed to link fakesink");
1099 gst_object_unref(GST_OBJECT(fakesink));
1103 if (strstr(name, "video")) {
1104 if (player->v_stream_caps) {
1105 gst_caps_unref(player->v_stream_caps);
1106 player->v_stream_caps = NULL;
1108 if (player->ini.set_dump_element_flag)
1109 __mmplayer_add_dump_buffer_probe(player, fakesink);
1112 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1113 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1117 gst_object_unref(GST_OBJECT(sinkpad));
1124 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1126 GstElement *pipeline = NULL;
1127 GstElement *selector = NULL;
1128 GstPad *srcpad = NULL;
1131 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1133 selector = gst_element_factory_make("input-selector", NULL);
1135 LOGE("failed to create input-selector");
1138 g_object_set(selector, "sync-streams", TRUE, NULL);
1140 player->pipeline->mainbin[elem_idx].id = elem_idx;
1141 player->pipeline->mainbin[elem_idx].gst = selector;
1143 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1145 srcpad = gst_element_get_static_pad(selector, "src");
1147 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1148 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1149 __mmplayer_gst_selector_blocked, NULL, NULL);
1150 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1151 __mmplayer_gst_selector_event_probe, player, NULL);
1153 gst_element_set_state(selector, GST_STATE_PAUSED);
1155 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1156 gst_bin_add(GST_BIN(pipeline), selector);
1158 gst_object_unref(GST_OBJECT(srcpad));
1165 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1167 mmplayer_t *player = (mmplayer_t *)data;
1168 GstElement *selector = NULL;
1169 GstCaps *caps = NULL;
1170 GstStructure *str = NULL;
1171 const gchar *name = NULL;
1172 GstPad *sinkpad = NULL;
1173 gboolean first_track = FALSE;
1174 gboolean caps_ret = TRUE;
1176 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1177 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1180 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1181 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1183 LOGD("pad-added signal handling");
1185 /* get mimetype from caps */
1186 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1190 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1192 LOGD("detected mimetype : %s", name);
1195 if (strstr(name, "video")) {
1197 gchar *caps_str = NULL;
1199 caps_str = gst_caps_to_string(caps);
1200 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1201 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1202 player->set_mode.video_zc = true;
1204 MMPLAYER_FREEIF(caps_str);
1206 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1207 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1209 LOGD("surface type : %d", stype);
1211 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1212 __mmplayer_gst_create_sinkbin(elem, pad, player);
1216 /* in case of exporting video frame, it requires the 360 video filter.
1217 * it will be handled in _no_more_pads(). */
1218 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1219 __mmplayer_gst_make_fakesink(player, pad, name);
1223 LOGD("video selector is required");
1224 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1225 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1226 } else if (strstr(name, "audio")) {
1227 gint samplerate = 0;
1230 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1231 if (player->build_audio_offload)
1232 player->no_more_pad = TRUE; /* remove state holder */
1233 __mmplayer_gst_create_sinkbin(elem, pad, player);
1237 gst_structure_get_int(str, "rate", &samplerate);
1238 gst_structure_get_int(str, "channels", &channels);
1240 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1241 __mmplayer_gst_make_fakesink(player, pad, name);
1245 LOGD("audio selector is required");
1246 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1247 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1249 } else if (strstr(name, "text")) {
1250 LOGD("text selector is required");
1251 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1252 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1254 LOGE("invalid caps info");
1258 /* check selector and create it */
1259 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1260 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1265 LOGD("input-selector is already created.");
1269 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1271 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1273 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1274 LOGE("failed to link selector");
1275 gst_object_unref(GST_OBJECT(selector));
1280 LOGD("this track will be activated");
1281 g_object_set(selector, "active-pad", sinkpad, NULL);
1284 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1290 gst_caps_unref(caps);
1293 gst_object_unref(GST_OBJECT(sinkpad));
1301 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1303 GstPad *srcpad = NULL;
1306 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1308 LOGD("type %d", type);
1311 LOGD("there is no %d track", type);
1315 srcpad = gst_element_get_static_pad(selector, "src");
1317 LOGE("failed to get srcpad from selector");
1321 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1323 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1325 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1326 if (player->selector[type].block_id) {
1327 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1328 player->selector[type].block_id = 0;
1332 gst_object_unref(GST_OBJECT(srcpad));
1341 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1343 gint active_index = 0;
1346 MMPLAYER_RETURN_IF_FAIL(player);
1348 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1350 /* change track to active pad */
1351 active_index = player->selector[type].active_pad_index;
1352 if ((active_index != DEFAULT_TRACK) &&
1353 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1354 LOGW("failed to change %d type track to %d", type, active_index);
1355 player->selector[type].active_pad_index = DEFAULT_TRACK;
1359 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1360 mm_player_set_attribute((MMHandleType)player, NULL,
1361 "content_text_track_num", player->selector[type].total_track_num,
1362 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1369 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1372 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1374 if (!audio_selector) {
1375 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1377 /* in case the source is changed, output can be changed. */
1378 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1379 LOGD("remove previous audiobin if it exist");
1381 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1382 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1384 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1385 MMPLAYER_FREEIF(player->pipeline->audiobin);
1388 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1389 __mmplayer_pipeline_complete(NULL, player);
1394 /* apply the audio track information */
1395 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1397 /* create audio sink path */
1398 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1399 LOGE("failed to create audio sink path");
1408 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1411 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1413 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1414 LOGD("text path is not supproted");
1418 /* apply the text track information */
1419 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1421 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1422 player->has_closed_caption = TRUE;
1424 /* create text decode path */
1425 player->no_more_pad = TRUE;
1427 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1428 LOGE("failed to create text sink path");
1437 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1439 gint64 dur_bytes = 0L;
1442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1443 player->pipeline->mainbin && player->streamer, FALSE);
1445 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1446 LOGE("fail to get duration.");
1448 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1449 * use file information was already set on Q2 when it was created. */
1450 _mm_player_streaming_set_queue2(player->streamer,
1451 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1452 TRUE, /* use_buffering */
1453 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1454 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1461 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1463 mmplayer_t *player = NULL;
1464 GstElement *video_selector = NULL;
1465 GstElement *audio_selector = NULL;
1466 GstElement *text_selector = NULL;
1469 player = (mmplayer_t *)data;
1471 LOGD("no-more-pad signal handling");
1473 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1474 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1475 LOGW("player is shutting down");
1479 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1480 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1481 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1482 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1483 LOGE("failed to set queue2 buffering");
1488 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1489 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1490 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1492 if (!video_selector && !audio_selector && !text_selector) {
1493 LOGW("there is no selector");
1494 player->no_more_pad = TRUE;
1498 /* create video path followed by video-select */
1499 if (video_selector && !audio_selector && !text_selector)
1500 player->no_more_pad = TRUE;
1502 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1505 /* create audio path followed by audio-select */
1506 if (audio_selector && !text_selector)
1507 player->no_more_pad = TRUE;
1509 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1512 /* create text path followed by text-select */
1513 __mmplayer_create_text_sink_path(player, text_selector);
1516 if (player->gapless.reconfigure) {
1517 player->gapless.reconfigure = FALSE;
1518 MMPLAYER_PLAYBACK_UNLOCK(player);
1525 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1527 gboolean ret = FALSE;
1528 GstElement *pipeline = NULL;
1529 GstPad *sinkpad = NULL;
1532 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1533 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1535 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1537 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1539 LOGE("failed to get pad from sinkbin");
1545 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1546 LOGE("failed to link sinkbin for reusing");
1547 goto EXIT; /* exit either pass or fail */
1551 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1552 LOGE("failed to set state(READY) to sinkbin");
1557 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1558 LOGE("failed to add sinkbin to pipeline");
1563 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1564 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1569 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1570 LOGE("failed to set state(PAUSED) to sinkbin");
1579 gst_object_unref(GST_OBJECT(sinkpad));
1587 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1589 mmplayer_t *player = NULL;
1590 GstCaps *caps = NULL;
1591 gchar *caps_str = NULL;
1592 GstStructure *str = NULL;
1593 const gchar *name = NULL;
1594 GstElement *sinkbin = NULL;
1595 gboolean reusing = FALSE;
1596 gboolean caps_ret = TRUE;
1597 gchar *sink_pad_name = "sink";
1600 player = (mmplayer_t *)data;
1603 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1604 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1606 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1610 caps_str = gst_caps_to_string(caps);
1612 LOGD("detected mimetype : %s", name);
1614 if (strstr(name, "audio")) {
1615 if (player->pipeline->audiobin == NULL) {
1616 const gchar *audio_format = gst_structure_get_string(str, "format");
1618 LOGD("original audio format %s", audio_format);
1619 mm_player_set_attribute((MMHandleType)player, NULL,
1620 "content_audio_format", audio_format, strlen(audio_format), NULL);
1623 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1624 LOGE("failed to create audiobin. continuing without audio");
1628 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1629 LOGD("creating audiobin success");
1632 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1633 LOGD("reusing audiobin");
1634 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1636 } else if (strstr(name, "video")) {
1637 /* 1. zero copy is updated at _decode_pad_added()
1638 * 2. NULL surface type is handled in _decode_pad_added() */
1639 LOGD("zero copy %d", player->set_mode.video_zc);
1640 if (player->pipeline->videobin == NULL) {
1641 int surface_type = 0;
1642 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1643 LOGD("display_surface_type (%d)", surface_type);
1645 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1646 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1647 LOGE("failed to acquire video overlay resource");
1651 player->interrupted_by_resource = FALSE;
1653 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1654 LOGE("failed to create videobin. continuing without video");
1658 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1659 LOGD("creating videosink bin success");
1662 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1663 LOGD("re-using videobin");
1664 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1666 } else if (strstr(name, "text")) {
1667 if (player->pipeline->textbin == NULL) {
1668 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1669 LOGE("failed to create text sink bin. continuing without text");
1673 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1674 player->textsink_linked = 1;
1675 LOGD("creating textsink bin success");
1677 if (!player->textsink_linked) {
1678 LOGD("re-using textbin");
1680 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1681 player->textsink_linked = 1;
1683 /* linked textbin exist which means that the external subtitle path exist already */
1684 LOGW("ignoring internal subtutle since external subtitle is available");
1687 sink_pad_name = "text_sink";
1689 LOGW("unknown mime type %s, ignoring it", name);
1693 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1696 LOGD("[handle: %p] success to create and link sink bin", player);
1698 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1699 * streaming task. if the task blocked, then buffer will not flow to the next element
1700 *(autoplugging element). so this is special hack for streaming. please try to remove it
1702 /* dec stream count. we can remove fakesink if it's zero */
1703 if (player->num_dynamic_pad)
1704 player->num_dynamic_pad--;
1706 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1708 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1709 __mmplayer_pipeline_complete(NULL, player);
1713 MMPLAYER_FREEIF(caps_str);
1716 gst_caps_unref(caps);
1722 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1724 int required_angle = 0; /* Angle required for straight view */
1725 int rotation_angle = 0;
1727 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1728 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1730 /* Counter clockwise */
1731 switch (orientation) {
1736 required_angle = 270;
1739 required_angle = 180;
1742 required_angle = 90;
1746 rotation_angle = display_angle + required_angle;
1747 if (rotation_angle >= 360)
1748 rotation_angle -= 360;
1750 /* chech if supported or not */
1751 if (rotation_angle % 90) {
1752 LOGD("not supported rotation angle = %d", rotation_angle);
1756 switch (rotation_angle) {
1758 *value = MM_DISPLAY_ROTATION_NONE;
1761 *value = MM_DISPLAY_ROTATION_90;
1764 *value = MM_DISPLAY_ROTATION_180;
1767 *value = MM_DISPLAY_ROTATION_270;
1771 LOGD("setting rotation property value : %d", *value);
1777 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1779 int display_rotation = 0;
1780 gchar *org_orient = NULL;
1781 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1784 LOGE("cannot get content attribute");
1785 return MM_ERROR_PLAYER_INTERNAL;
1788 if (display_angle) {
1789 /* update user roation */
1790 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1792 /* Counter clockwise */
1793 switch (display_rotation) {
1794 case MM_DISPLAY_ROTATION_NONE:
1797 case MM_DISPLAY_ROTATION_90:
1798 *display_angle = 90;
1800 case MM_DISPLAY_ROTATION_180:
1801 *display_angle = 180;
1803 case MM_DISPLAY_ROTATION_270:
1804 *display_angle = 270;
1807 LOGW("wrong angle type : %d", display_rotation);
1810 LOGD("check user angle: %d", *display_angle);
1814 /* Counter clockwise */
1815 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1818 if (!strcmp(org_orient, "rotate-90"))
1820 else if (!strcmp(org_orient, "rotate-180"))
1822 else if (!strcmp(org_orient, "rotate-270"))
1825 LOGD("original rotation is %s", org_orient);
1827 LOGD("content_video_orientation get fail");
1830 LOGD("check orientation: %d", *orientation);
1833 return MM_ERROR_NONE;
1836 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1838 int rotation_value = 0;
1839 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1840 int display_angle = 0;
1843 /* check video sinkbin is created */
1844 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1847 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1849 /* get rotation value to set */
1850 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1851 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1852 LOGD("set video param : rotate %d", rotation_value);
1855 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1857 MMHandleType attrs = 0;
1861 /* check video sinkbin is created */
1862 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1865 attrs = MMPLAYER_GET_ATTRS(player);
1866 MMPLAYER_RETURN_IF_FAIL(attrs);
1868 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1869 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1870 LOGD("set video param : visible %d", visible);
1873 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1875 MMHandleType attrs = 0;
1876 int display_method = 0;
1879 /* check video sinkbin is created */
1880 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1883 attrs = MMPLAYER_GET_ATTRS(player);
1884 MMPLAYER_RETURN_IF_FAIL(attrs);
1886 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1887 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1888 LOGD("set video param : method %d", display_method);
1891 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1893 MMHandleType attrs = 0;
1897 /* check video sinkbin is created */
1898 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1901 attrs = MMPLAYER_GET_ATTRS(player);
1902 MMPLAYER_RETURN_IF_FAIL(attrs);
1904 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1905 MMPLAYER_RETURN_IF_FAIL(handle);
1907 gst_video_overlay_set_video_roi_area(
1908 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1909 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1910 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1911 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1914 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1916 MMHandleType attrs = 0;
1921 int win_roi_width = 0;
1922 int win_roi_height = 0;
1925 /* check video sinkbin is created */
1926 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1929 attrs = MMPLAYER_GET_ATTRS(player);
1930 MMPLAYER_RETURN_IF_FAIL(attrs);
1932 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1933 MMPLAYER_RETURN_IF_FAIL(handle);
1935 /* It should be set after setting window */
1936 mm_attrs_multiple_get(attrs, NULL,
1937 "display_win_roi_x", &win_roi_x,
1938 "display_win_roi_y", &win_roi_y,
1939 "display_win_roi_width", &win_roi_width,
1940 "display_win_roi_height", &win_roi_height, NULL);
1942 /* After setting window handle, set display roi area */
1943 gst_video_overlay_set_display_roi_area(
1944 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1945 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1946 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1947 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1950 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1952 MMHandleType attrs = 0;
1955 /* check video sinkbin is created */
1956 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1959 attrs = MMPLAYER_GET_ATTRS(player);
1960 MMPLAYER_RETURN_IF_FAIL(attrs);
1962 /* common case if using overlay surface */
1963 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1964 MMPLAYER_RETURN_IF_FAIL(handle);
1966 /* default is using wl_surface_id */
1967 LOGD("set video param : wl_surface_id %d", handle);
1968 gst_video_overlay_set_wl_window_wl_surface_id(
1969 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1974 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1976 gboolean update_all_param = FALSE;
1980 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1981 LOGW("videosink is not ready yet");
1982 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1985 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1986 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1987 return MM_ERROR_PLAYER_INTERNAL;
1990 LOGD("param_name : %s", param_name);
1991 if (!g_strcmp0(param_name, "update_all_param"))
1992 update_all_param = TRUE;
1994 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1995 __mmplayer_video_param_set_display_overlay(player);
1996 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1997 __mmplayer_video_param_set_display_method(player);
1998 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1999 __mmplayer_video_param_set_display_visible(player);
2000 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2001 __mmplayer_video_param_set_display_rotation(player);
2002 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2003 __mmplayer_video_param_set_roi_area(player);
2004 if (update_all_param)
2005 __mmplayer_video_param_set_video_roi_area(player);
2009 return MM_ERROR_NONE;
2013 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2015 gboolean disable_overlay = FALSE;
2016 mmplayer_t *player = (mmplayer_t *)hplayer;
2019 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2020 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2021 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2022 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2024 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2025 LOGW("Display control is not supported");
2026 return MM_ERROR_PLAYER_INTERNAL;
2029 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2031 if (audio_only == (bool)disable_overlay) {
2032 LOGE("It's the same with current setting: (%d)", audio_only);
2033 return MM_ERROR_NONE;
2037 LOGE("disable overlay");
2038 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2040 /* release overlay resource */
2041 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2042 LOGE("failed to release overlay resource");
2046 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2047 LOGE("failed to acquire video overlay resource");
2050 player->interrupted_by_resource = FALSE;
2052 LOGD("enable overlay");
2053 __mmplayer_video_param_set_display_overlay(player);
2054 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2059 return MM_ERROR_NONE;
2063 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2065 mmplayer_t *player = (mmplayer_t *)hplayer;
2066 gboolean disable_overlay = FALSE;
2070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2071 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2072 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2073 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2074 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2076 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2077 LOGW("Display control is not supported");
2078 return MM_ERROR_PLAYER_INTERNAL;
2081 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2083 *paudio_only = (bool)disable_overlay;
2085 LOGD("audio_only : %d", *paudio_only);
2089 return MM_ERROR_NONE;
2093 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2095 GList *bucket = element_bucket;
2096 mmplayer_gst_element_t *element = NULL;
2097 mmplayer_gst_element_t *prv_element = NULL;
2098 GstElement *tee_element = NULL;
2099 gint successful_link_count = 0;
2103 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2105 prv_element = (mmplayer_gst_element_t *)bucket->data;
2106 bucket = bucket->next;
2108 for (; bucket; bucket = bucket->next) {
2109 element = (mmplayer_gst_element_t *)bucket->data;
2111 if (element && element->gst) {
2112 if (prv_element && prv_element->gst) {
2113 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2115 prv_element->gst = tee_element;
2117 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2118 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2119 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2123 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2124 LOGD("linking [%s] to [%s] success",
2125 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2126 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2127 successful_link_count++;
2128 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2129 LOGD("keep audio-tee element for next audio pipeline branch");
2130 tee_element = prv_element->gst;
2133 LOGD("linking [%s] to [%s] failed",
2134 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2135 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2141 prv_element = element;
2146 return successful_link_count;
2150 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2152 GList *bucket = element_bucket;
2153 mmplayer_gst_element_t *element = NULL;
2154 int successful_add_count = 0;
2158 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2159 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2161 for (; bucket; bucket = bucket->next) {
2162 element = (mmplayer_gst_element_t *)bucket->data;
2164 if (element && element->gst) {
2165 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2166 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2167 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2168 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2171 successful_add_count++;
2177 return successful_add_count;
2181 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2183 mmplayer_t *player = (mmplayer_t *)data;
2184 GstCaps *caps = NULL;
2185 GstStructure *str = NULL;
2187 gboolean caps_ret = TRUE;
2191 MMPLAYER_RETURN_IF_FAIL(pad);
2192 MMPLAYER_RETURN_IF_FAIL(unused);
2193 MMPLAYER_RETURN_IF_FAIL(data);
2195 caps = gst_pad_get_current_caps(pad);
2199 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2203 LOGD("name = %s", name);
2205 if (strstr(name, "audio")) {
2206 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2208 if (player->audio_stream_changed_cb) {
2209 LOGE("call the audio stream changed cb");
2210 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2212 } else if (strstr(name, "video")) {
2213 if ((name = gst_structure_get_string(str, "format")))
2214 player->set_mode.video_zc = name[0] == 'S';
2216 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2217 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2219 LOGW("invalid caps info");
2224 gst_caps_unref(caps);
2232 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2237 MMPLAYER_RETURN_IF_FAIL(player);
2239 if (player->audio_stream_buff_list) {
2240 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2241 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2244 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2245 __mmplayer_audio_stream_send_data(player, tmp);
2247 MMPLAYER_FREEIF(tmp->pcm_data);
2248 MMPLAYER_FREEIF(tmp);
2251 g_list_free(player->audio_stream_buff_list);
2252 player->audio_stream_buff_list = NULL;
2259 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2261 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2264 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2266 audio_stream.bitrate = a_buffer->bitrate;
2267 audio_stream.channel = a_buffer->channel;
2268 audio_stream.channel_mask = a_buffer->channel_mask;
2269 audio_stream.data_size = a_buffer->data_size;
2270 audio_stream.data = a_buffer->pcm_data;
2271 audio_stream.pcm_format = a_buffer->pcm_format;
2273 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2275 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2281 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2283 mmplayer_t *player = (mmplayer_t *)data;
2284 const gchar *pcm_format = NULL;
2287 guint64 channel_mask = 0;
2288 void *a_data = NULL;
2290 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2291 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2295 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2297 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2298 a_data = mapinfo.data;
2299 a_size = mapinfo.size;
2301 GstCaps *caps = gst_pad_get_current_caps(pad);
2302 GstStructure *structure = gst_caps_get_structure(caps, 0);
2304 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2306 pcm_format = gst_structure_get_string(structure, "format");
2307 gst_structure_get_int(structure, "rate", &rate);
2308 gst_structure_get_int(structure, "channels", &channel);
2309 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2310 gst_caps_unref(GST_CAPS(caps));
2312 /* In case of the sync is false, use buffer list. *
2313 * The num of buffer list depends on the num of audio channels */
2314 if (player->audio_stream_buff_list) {
2315 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2316 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2318 if (channel_mask == tmp->channel_mask) {
2320 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2322 if (tmp->data_size + a_size < tmp->buff_size) {
2323 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2324 tmp->data_size += a_size;
2326 /* send data to client */
2327 __mmplayer_audio_stream_send_data(player, tmp);
2329 if (a_size > tmp->buff_size) {
2330 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2331 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2332 if (tmp->pcm_data == NULL) {
2333 LOGE("failed to realloc data.");
2336 tmp->buff_size = a_size;
2338 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2339 memcpy(tmp->pcm_data, a_data, a_size);
2340 tmp->data_size = a_size;
2345 LOGE("data is empty in list.");
2351 /* create new audio stream data for newly found audio channel */
2352 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2353 if (a_buffer == NULL) {
2354 LOGE("failed to alloc data.");
2357 a_buffer->bitrate = rate;
2358 a_buffer->channel = channel;
2359 a_buffer->channel_mask = channel_mask;
2360 a_buffer->data_size = a_size;
2361 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2363 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2364 /* If sync is FALSE, use buffer list to reduce the IPC. */
2365 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2366 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2367 if (a_buffer->pcm_data == NULL) {
2368 LOGE("failed to alloc data.");
2369 MMPLAYER_FREEIF(a_buffer);
2372 memcpy(a_buffer->pcm_data, a_data, a_size);
2374 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2376 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2378 /* If sync is TRUE, send data directly. */
2379 a_buffer->pcm_data = a_data;
2380 __mmplayer_audio_stream_send_data(player, a_buffer);
2381 MMPLAYER_FREEIF(a_buffer);
2385 gst_buffer_unmap(buffer, &mapinfo);
2390 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2392 mmplayer_t *player = (mmplayer_t *)data;
2393 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2394 GstPad *sinkpad = NULL;
2395 GstElement *queue = NULL, *sink = NULL;
2398 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2400 queue = gst_element_factory_make("queue", NULL);
2401 if (queue == NULL) {
2402 LOGD("fail make queue");
2406 sink = gst_element_factory_make("fakesink", NULL);
2408 LOGD("fail make fakesink");
2412 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2414 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2415 LOGW("failed to link queue & sink");
2419 sinkpad = gst_element_get_static_pad(queue, "sink");
2421 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2422 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2426 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2428 gst_object_unref(sinkpad);
2429 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2430 g_object_set(sink, "sync", TRUE, NULL);
2431 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2433 /* keep the first sink reference only */
2434 if (!audiobin[MMPLAYER_A_SINK].gst) {
2435 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2436 audiobin[MMPLAYER_A_SINK].gst = sink;
2440 _mmplayer_add_signal_connection(player,
2442 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2444 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2447 __mmplayer_add_sink(player, sink);
2449 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2450 LOGE("failed to sync state");
2454 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2455 LOGE("failed to sync state");
2463 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2465 gst_object_unref(GST_OBJECT(queue));
2469 gst_object_unref(GST_OBJECT(sink));
2473 gst_object_unref(GST_OBJECT(sinkpad));
2481 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2483 mmplayer_t *player = (mmplayer_t *)data;
2486 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2488 player->no_more_pad = TRUE;
2489 __mmplayer_pipeline_complete(NULL, player);
2496 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2498 #define MAX_PROPS_LEN 128
2499 mmplayer_gst_element_t *audiobin = NULL;
2500 gint latency_mode = 0;
2501 gchar *stream_type = NULL;
2502 gchar *latency = NULL;
2504 gchar stream_props[MAX_PROPS_LEN] = {0,};
2505 GstStructure *props = NULL;
2508 * It should be set after player creation through attribute.
2509 * But, it can not be changed during playing.
2512 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2514 audiobin = player->pipeline->audiobin;
2516 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2517 if (player->sound.mute) {
2518 LOGD("mute enabled");
2519 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2522 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2523 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2526 snprintf(stream_props, sizeof(stream_props) - 1,
2527 "props,application.process.id.origin=%d", player->client_pid);
2529 snprintf(stream_props, sizeof(stream_props) - 1,
2530 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2531 stream_type, stream_id, player->client_pid);
2533 props = gst_structure_from_string(stream_props, NULL);
2534 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2535 LOGI("props result[%s].", stream_props);
2536 gst_structure_free(props);
2538 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2540 switch (latency_mode) {
2541 case AUDIO_LATENCY_MODE_LOW:
2542 latency = g_strndup("low", 3);
2544 case AUDIO_LATENCY_MODE_MID:
2545 latency = g_strndup("mid", 3);
2547 case AUDIO_LATENCY_MODE_HIGH:
2548 latency = g_strndup("high", 4);
2552 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2554 LOGD("audiosink property - latency=%s", latency);
2556 MMPLAYER_FREEIF(latency);
2562 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2564 mmplayer_gst_element_t *audiobin = NULL;
2567 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2569 audiobin = player->pipeline->audiobin;
2571 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2572 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2573 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2575 if (player->video360_yaw_radians <= M_PI &&
2576 player->video360_yaw_radians >= -M_PI &&
2577 player->video360_pitch_radians <= M_PI_2 &&
2578 player->video360_pitch_radians >= -M_PI_2) {
2579 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2580 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2581 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2582 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2583 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2584 "source-orientation-y", player->video360_metadata.init_view_heading,
2585 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2592 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2594 mmplayer_gst_element_t *audiobin = NULL;
2595 GstPad *sink_pad = NULL;
2596 GstCaps *acaps = NULL;
2598 int pitch_control = 0;
2599 double pitch_value = 1.0;
2602 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2603 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2605 audiobin = player->pipeline->audiobin;
2607 LOGD("make element for normal audio playback");
2609 /* audio bin structure for playback. {} means optional.
2610 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2612 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2613 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2616 /* for pitch control */
2617 mm_attrs_multiple_get(player->attrs, NULL,
2618 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2619 MM_PLAYER_PITCH_VALUE, &pitch_value,
2622 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2623 if (pitch_control && (player->videodec_linked == 0)) {
2624 GstElementFactory *factory;
2626 factory = gst_element_factory_find("pitch");
2628 gst_object_unref(factory);
2631 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2634 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2635 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2637 LOGW("there is no pitch element");
2642 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2644 /* replaygain volume */
2645 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2646 if (player->sound.rg_enable)
2647 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2649 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2652 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2654 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2655 /* currently, only openalsink uses volume element */
2656 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2659 if (player->sound.mute) {
2660 LOGD("mute enabled");
2661 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2665 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2667 /* audio effect element. if audio effect is enabled */
2668 if ((strcmp(player->ini.audioeffect_element, ""))
2670 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2671 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2673 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2675 if ((!player->bypass_audio_effect)
2676 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2677 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2678 if (!_mmplayer_audio_effect_custom_apply(player))
2679 LOGI("apply audio effect(custom) setting success");
2683 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2684 && (player->set_mode.rich_audio)) {
2685 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2689 /* create audio sink */
2690 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2691 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2692 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2694 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2695 if (player->is_360_feature_enabled &&
2696 player->is_content_spherical &&
2698 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2699 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2700 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2702 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2704 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2706 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2707 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2708 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2709 gst_caps_unref(acaps);
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2713 player->is_openal_plugin_used = TRUE;
2715 if (player->is_360_feature_enabled && player->is_content_spherical)
2716 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2717 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2720 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2721 (player->videodec_linked && player->ini.use_system_clock)) {
2722 LOGD("system clock will be used.");
2723 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2726 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2727 __mmplayer_gst_set_pulsesink_property(player);
2728 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2729 __mmplayer_gst_set_openalsink_property(player);
2732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2735 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2736 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2737 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2738 gst_object_unref(GST_OBJECT(sink_pad));
2740 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2743 return MM_ERROR_NONE;
2745 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2747 return MM_ERROR_PLAYER_INTERNAL;
2751 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2753 mmplayer_gst_element_t *audiobin = NULL;
2754 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2756 gchar *dst_format = NULL;
2758 int dst_samplerate = 0;
2759 int dst_channels = 0;
2760 GstCaps *caps = NULL;
2761 char *caps_str = NULL;
2764 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2765 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2767 audiobin = player->pipeline->audiobin;
2769 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2771 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2773 [case 1] extract interleave audio pcm without playback
2774 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2775 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2777 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2779 [case 2] deinterleave for each channel without playback
2780 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2781 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2783 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2784 - fakesink (sync or not)
2787 [case 3] [case 1(sync only)] + playback
2788 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2790 * src - ... - tee - queue1 - playback path
2791 - queue2 - [case1 pipeline with sync]
2793 [case 4] [case 2(sync only)] + playback
2794 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2796 * src - ... - tee - queue1 - playback path
2797 - queue2 - [case2 pipeline with sync]
2801 /* 1. create tee and playback path
2802 'tee' should be added at first to copy the decoded stream
2804 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2805 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2806 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2808 /* tee - path 1 : for playback path */
2809 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2810 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2812 /* tee - path 2 : for extract path */
2813 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2814 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2817 /* if there is tee, 'tee - path 2' is linked here */
2819 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2822 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2824 /* 2. decide the extract pcm format */
2825 mm_attrs_multiple_get(player->attrs, NULL,
2826 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2827 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2828 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2831 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2832 dst_format, dst_len, dst_samplerate, dst_channels);
2834 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2835 mm_attrs_multiple_get(player->attrs, NULL,
2836 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2837 "content_audio_samplerate", &dst_samplerate,
2838 "content_audio_channels", &dst_channels,
2841 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2842 dst_format, dst_len, dst_samplerate, dst_channels);
2844 /* If there is no enough information, set it to platform default value. */
2845 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2846 LOGD("set platform default format");
2847 dst_format = DEFAULT_PCM_OUT_FORMAT;
2849 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2850 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2853 /* 3. create capsfilter */
2854 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2855 caps = gst_caps_new_simple("audio/x-raw",
2856 "format", G_TYPE_STRING, dst_format,
2857 "rate", G_TYPE_INT, dst_samplerate,
2858 "channels", G_TYPE_INT, dst_channels,
2861 caps_str = gst_caps_to_string(caps);
2862 LOGD("new caps : %s", caps_str);
2864 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2867 gst_caps_unref(caps);
2868 MMPLAYER_FREEIF(caps_str);
2870 /* 4-1. create deinterleave to extract pcm for each channel */
2871 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2872 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2873 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2875 /* audiosink will be added after getting signal for each channel */
2876 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2877 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2878 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2879 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2880 player->no_more_pad = FALSE;
2882 /* 4-2. create fakesink to extract interlevaed pcm */
2883 LOGD("add audio fakesink for interleaved audio");
2884 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2885 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2886 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2887 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2889 _mmplayer_add_signal_connection(player,
2890 G_OBJECT(audiobin[extract_sink_id].gst),
2891 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2893 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2896 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2900 return MM_ERROR_NONE;
2902 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2904 return MM_ERROR_PLAYER_INTERNAL;
2908 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2910 int ret = MM_ERROR_NONE;
2911 mmplayer_gst_element_t *audiobin = NULL;
2912 GList *element_bucket = NULL;
2915 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2916 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2918 audiobin = player->pipeline->audiobin;
2920 if (player->build_audio_offload) { /* skip all the audio filters */
2921 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2923 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2924 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2925 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2927 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2931 /* FIXME: need to mention the supportable condition at API reference */
2932 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2933 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2935 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2937 if (ret != MM_ERROR_NONE)
2940 LOGD("success to make audio bin element");
2941 *bucket = element_bucket;
2944 return MM_ERROR_NONE;
2947 LOGE("failed to make audio bin element");
2948 g_list_free(element_bucket);
2952 return MM_ERROR_PLAYER_INTERNAL;
2956 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2958 mmplayer_gst_element_t *first_element = NULL;
2959 mmplayer_gst_element_t *audiobin = NULL;
2961 GstPad *ghostpad = NULL;
2962 GList *element_bucket = NULL;
2966 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2969 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2971 LOGE("failed to allocate memory for audiobin");
2972 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2976 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2977 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2978 if (!audiobin[MMPLAYER_A_BIN].gst) {
2979 LOGE("failed to create audiobin");
2984 player->pipeline->audiobin = audiobin;
2986 /* create audio filters and audiosink */
2987 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2990 /* adding created elements to bin */
2991 LOGD("adding created elements to bin");
2992 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2995 /* linking elements in the bucket by added order. */
2996 LOGD("Linking elements in the bucket by added order.");
2997 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3000 /* get first element's sinkpad for creating ghostpad */
3001 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3002 if (!first_element) {
3003 LOGE("failed to get first elem");
3007 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3009 LOGE("failed to get pad from first element of audiobin");
3013 ghostpad = gst_ghost_pad_new("sink", pad);
3015 LOGE("failed to create ghostpad");
3019 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3020 LOGE("failed to add ghostpad to audiobin");
3024 gst_object_unref(pad);
3026 g_list_free(element_bucket);
3029 return MM_ERROR_NONE;
3032 LOGD("ERROR : releasing audiobin");
3035 gst_object_unref(GST_OBJECT(pad));
3038 gst_object_unref(GST_OBJECT(ghostpad));
3041 g_list_free(element_bucket);
3043 /* release element which are not added to bin */
3044 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3045 /* NOTE : skip bin */
3046 if (audiobin[i].gst) {
3047 GstObject *parent = NULL;
3048 parent = gst_element_get_parent(audiobin[i].gst);
3051 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3052 audiobin[i].gst = NULL;
3054 gst_object_unref(GST_OBJECT(parent));
3058 /* release audiobin with it's childs */
3059 if (audiobin[MMPLAYER_A_BIN].gst)
3060 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3062 MMPLAYER_FREEIF(audiobin);
3064 player->pipeline->audiobin = NULL;
3066 return MM_ERROR_PLAYER_INTERNAL;
3070 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3072 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3076 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3078 int ret = MM_ERROR_NONE;
3080 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3081 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3083 MMPLAYER_VIDEO_BO_LOCK(player);
3085 if (player->video_bo_list) {
3086 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3087 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3088 if (tmp && tmp->bo == bo) {
3090 LOGD("release bo %p", bo);
3091 tbm_bo_unref(tmp->bo);
3092 MMPLAYER_VIDEO_BO_UNLOCK(player);
3093 MMPLAYER_VIDEO_BO_SIGNAL(player);
3098 /* hw codec is running or the list was reset for DRC. */
3099 LOGW("there is no bo list.");
3101 MMPLAYER_VIDEO_BO_UNLOCK(player);
3103 LOGW("failed to find bo %p", bo);
3108 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3113 MMPLAYER_RETURN_IF_FAIL(player);
3115 MMPLAYER_VIDEO_BO_LOCK(player);
3116 if (player->video_bo_list) {
3117 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3118 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3119 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3122 tbm_bo_unref(tmp->bo);
3126 g_list_free(player->video_bo_list);
3127 player->video_bo_list = NULL;
3129 player->video_bo_size = 0;
3130 MMPLAYER_VIDEO_BO_UNLOCK(player);
3137 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3140 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3141 gboolean ret = TRUE;
3143 /* check DRC, if it is, destroy the prev bo list to create again */
3144 if (player->video_bo_size != size) {
3145 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3146 __mmplayer_video_stream_destroy_bo_list(player);
3147 player->video_bo_size = size;
3150 MMPLAYER_VIDEO_BO_LOCK(player);
3152 if ((!player->video_bo_list) ||
3153 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3155 /* create bo list */
3157 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3159 if (player->video_bo_list) {
3160 /* if bo list did not created all, try it again. */
3161 idx = g_list_length(player->video_bo_list);
3162 LOGD("bo list exist(len: %d)", idx);
3165 for (; idx < player->ini.num_of_video_bo; idx++) {
3166 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3168 LOGE("Fail to alloc bo_info.");
3171 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3173 LOGE("Fail to tbm_bo_alloc.");
3174 MMPLAYER_FREEIF(bo_info);
3177 bo_info->used = FALSE;
3178 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3181 /* update video num buffers */
3182 LOGD("video_num_buffers : %d", idx);
3183 mm_player_set_attribute((MMHandleType)player, NULL,
3184 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3185 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3189 MMPLAYER_VIDEO_BO_UNLOCK(player);
3195 /* get bo from list*/
3196 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3197 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3198 if (tmp && (tmp->used == FALSE)) {
3199 LOGD("found bo %p to use", tmp->bo);
3201 MMPLAYER_VIDEO_BO_UNLOCK(player);
3202 return tbm_bo_ref(tmp->bo);
3206 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3207 MMPLAYER_VIDEO_BO_UNLOCK(player);
3211 if (player->ini.video_bo_timeout <= 0) {
3212 MMPLAYER_VIDEO_BO_WAIT(player);
3214 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3215 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3222 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3224 mmplayer_t *player = (mmplayer_t *)data;
3226 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3228 /* send prerolled pkt */
3229 player->video_stream_prerolled = false;
3231 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3233 /* not to send prerolled pkt again */
3234 player->video_stream_prerolled = true;
3238 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3240 mmplayer_t *player = (mmplayer_t *)data;
3241 mmplayer_video_decoded_data_info_t *stream = NULL;
3242 GstMemory *mem = NULL;
3245 MMPLAYER_RETURN_IF_FAIL(player);
3246 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3248 if (player->video_stream_prerolled) {
3249 player->video_stream_prerolled = false;
3250 LOGD("skip the prerolled pkt not to send it again");
3254 /* clear stream data structure */
3255 stream = __mmplayer_create_stream_from_pad(pad);
3257 LOGE("failed to alloc stream");
3261 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3263 /* set size and timestamp */
3264 mem = gst_buffer_peek_memory(buffer, 0);
3265 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3266 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3268 /* check zero-copy */
3269 if (player->set_mode.video_zc &&
3270 player->set_mode.video_export &&
3271 gst_is_tizen_memory(mem)) {
3272 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3273 stream->internal_buffer = gst_buffer_ref(buffer);
3274 } else { /* sw codec */
3275 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3278 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3282 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3283 LOGE("failed to send video decoded data.");
3290 LOGE("release video stream resource.");
3291 if (gst_is_tizen_memory(mem)) {
3293 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3295 tbm_bo_unref(stream->bo[i]);
3298 /* unref gst buffer */
3299 if (stream->internal_buffer)
3300 gst_buffer_unref(stream->internal_buffer);
3303 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3305 MMPLAYER_FREEIF(stream);
3310 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3312 mmplayer_gst_element_t *videobin = NULL;
3315 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3317 videobin = player->pipeline->videobin;
3319 /* Set spatial media metadata and/or user settings to the element.
3321 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3322 "projection-type", player->video360_metadata.projection_type, NULL);
3324 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3325 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3327 if (player->video360_metadata.full_pano_width_pixels &&
3328 player->video360_metadata.full_pano_height_pixels &&
3329 player->video360_metadata.cropped_area_image_width &&
3330 player->video360_metadata.cropped_area_image_height) {
3331 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3332 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3333 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3334 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3335 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3336 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3337 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3341 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3342 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3343 "horizontal-fov", player->video360_horizontal_fov,
3344 "vertical-fov", player->video360_vertical_fov, NULL);
3347 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3348 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3349 "zoom", 1.0f / player->video360_zoom, NULL);
3352 if (player->video360_yaw_radians <= M_PI &&
3353 player->video360_yaw_radians >= -M_PI &&
3354 player->video360_pitch_radians <= M_PI_2 &&
3355 player->video360_pitch_radians >= -M_PI_2) {
3356 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3357 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3358 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3359 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3360 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3361 "pose-yaw", player->video360_metadata.init_view_heading,
3362 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3365 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3366 "passthrough", !player->is_video360_enabled, NULL);
3373 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3375 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3376 GList *element_bucket = NULL;
3379 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3381 /* create video360 filter */
3382 if (player->is_360_feature_enabled && player->is_content_spherical) {
3383 LOGD("create video360 element");
3384 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3385 __mmplayer_gst_set_video360_property(player);
3389 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3390 LOGD("skip creating the videoconv and rotator");
3391 return MM_ERROR_NONE;
3394 /* in case of sw codec & overlay surface type, except 360 playback.
3395 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3396 LOGD("create video converter: %s", video_csc);
3397 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3400 *bucket = element_bucket;
3402 return MM_ERROR_NONE;
3404 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3405 g_list_free(element_bucket);
3409 return MM_ERROR_PLAYER_INTERNAL;
3413 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3415 gchar *factory_name = NULL;
3417 switch (surface_type) {
3418 case MM_DISPLAY_SURFACE_OVERLAY:
3419 if (strlen(player->ini.videosink_element_overlay) > 0)
3420 factory_name = player->ini.videosink_element_overlay;
3422 case MM_DISPLAY_SURFACE_REMOTE:
3423 case MM_DISPLAY_SURFACE_NULL:
3424 if (strlen(player->ini.videosink_element_fake) > 0)
3425 factory_name = player->ini.videosink_element_fake;
3428 LOGE("unidentified surface type");
3432 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3433 return factory_name;
3437 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3439 gchar *factory_name = NULL;
3440 mmplayer_gst_element_t *videobin = NULL;
3445 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3447 videobin = player->pipeline->videobin;
3448 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3450 attrs = MMPLAYER_GET_ATTRS(player);
3452 LOGE("cannot get content attribute");
3453 return MM_ERROR_PLAYER_INTERNAL;
3456 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3457 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3458 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3460 /* support shard memory with S/W codec on HawkP */
3461 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3462 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3463 "use-tbm", use_tbm, NULL);
3467 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3468 return MM_ERROR_PLAYER_INTERNAL;
3470 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3471 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3474 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3476 LOGD("disable last-sample");
3477 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3480 if (player->set_mode.video_export) {
3482 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3483 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3484 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3486 _mmplayer_add_signal_connection(player,
3487 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3488 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3490 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3493 _mmplayer_add_signal_connection(player,
3494 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3495 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3497 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3501 if (videobin[MMPLAYER_V_SINK].gst) {
3502 GstPad *sink_pad = NULL;
3503 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3505 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3506 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3507 gst_object_unref(GST_OBJECT(sink_pad));
3509 LOGE("failed to get sink pad from videosink");
3513 return MM_ERROR_NONE;
3518 * - video overlay surface(arm/x86) : tizenwlsink
3521 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3524 GList *element_bucket = NULL;
3525 mmplayer_gst_element_t *first_element = NULL;
3526 mmplayer_gst_element_t *videobin = NULL;
3527 gchar *videosink_factory_name = NULL;
3530 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3533 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3535 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3537 player->pipeline->videobin = videobin;
3540 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3541 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3542 if (!videobin[MMPLAYER_V_BIN].gst) {
3543 LOGE("failed to create videobin");
3547 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3550 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3551 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3553 /* additional setting for sink plug-in */
3554 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3555 LOGE("failed to set video property");
3559 /* store it as it's sink element */
3560 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3562 /* adding created elements to bin */
3563 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3564 LOGE("failed to add elements");
3568 /* Linking elements in the bucket by added order */
3569 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3570 LOGE("failed to link elements");
3574 /* get first element's sinkpad for creating ghostpad */
3575 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3576 if (!first_element) {
3577 LOGE("failed to get first element from bucket");
3581 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3583 LOGE("failed to get pad from first element");
3587 /* create ghostpad */
3588 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3589 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3590 LOGE("failed to add ghostpad to videobin");
3593 gst_object_unref(pad);
3595 /* done. free allocated variables */
3596 g_list_free(element_bucket);
3600 return MM_ERROR_NONE;
3603 LOGE("ERROR : releasing videobin");
3604 g_list_free(element_bucket);
3607 gst_object_unref(GST_OBJECT(pad));
3609 /* release videobin with it's childs */
3610 if (videobin[MMPLAYER_V_BIN].gst)
3611 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3613 MMPLAYER_FREEIF(videobin);
3614 player->pipeline->videobin = NULL;
3616 return MM_ERROR_PLAYER_INTERNAL;
3620 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3622 GList *element_bucket = NULL;
3623 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3625 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3626 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3627 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3628 "signal-handoffs", FALSE,
3631 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3632 _mmplayer_add_signal_connection(player,
3633 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3634 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3636 G_CALLBACK(__mmplayer_update_subtitle),
3639 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3640 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3642 if (!player->play_subtitle) {
3643 LOGD("add textbin sink as sink element of whole pipeline.");
3644 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3647 /* adding created elements to bin */
3648 LOGD("adding created elements to bin");
3649 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3650 LOGE("failed to add elements");
3654 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3655 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3656 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3658 /* linking elements in the bucket by added order. */
3659 LOGD("Linking elements in the bucket by added order.");
3660 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3661 LOGE("failed to link elements");
3665 /* done. free allocated variables */
3666 g_list_free(element_bucket);
3668 if (textbin[MMPLAYER_T_QUEUE].gst) {
3670 GstPad *ghostpad = NULL;
3672 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3674 LOGE("failed to get sink pad of text queue");
3678 ghostpad = gst_ghost_pad_new("text_sink", pad);
3679 gst_object_unref(pad);
3682 LOGE("failed to create ghostpad of textbin");
3686 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3687 LOGE("failed to add ghostpad to textbin");
3688 gst_object_unref(ghostpad);
3693 return MM_ERROR_NONE;
3696 g_list_free(element_bucket);
3698 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3699 LOGE("remove textbin sink from sink list");
3700 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3703 /* release element at __mmplayer_gst_create_text_sink_bin */
3704 return MM_ERROR_PLAYER_INTERNAL;
3708 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3710 mmplayer_gst_element_t *textbin = NULL;
3711 GList *element_bucket = NULL;
3712 int surface_type = 0;
3717 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3720 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3722 LOGE("failed to allocate memory for textbin");
3723 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3727 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3728 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3729 if (!textbin[MMPLAYER_T_BIN].gst) {
3730 LOGE("failed to create textbin");
3735 player->pipeline->textbin = textbin;
3738 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3739 LOGD("surface type for subtitle : %d", surface_type);
3740 switch (surface_type) {
3741 case MM_DISPLAY_SURFACE_OVERLAY:
3742 case MM_DISPLAY_SURFACE_NULL:
3743 case MM_DISPLAY_SURFACE_REMOTE:
3744 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3745 LOGE("failed to make plain text elements");
3756 return MM_ERROR_NONE;
3760 LOGD("ERROR : releasing textbin");
3762 g_list_free(element_bucket);
3764 /* release signal */
3765 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3767 /* release element which are not added to bin */
3768 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3769 /* NOTE : skip bin */
3770 if (textbin[i].gst) {
3771 GstObject *parent = NULL;
3772 parent = gst_element_get_parent(textbin[i].gst);
3775 gst_object_unref(GST_OBJECT(textbin[i].gst));
3776 textbin[i].gst = NULL;
3778 gst_object_unref(GST_OBJECT(parent));
3783 /* release textbin with it's childs */
3784 if (textbin[MMPLAYER_T_BIN].gst)
3785 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3787 MMPLAYER_FREEIF(player->pipeline->textbin);
3788 player->pipeline->textbin = NULL;
3791 return MM_ERROR_PLAYER_INTERNAL;
3795 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3797 mmplayer_gst_element_t *mainbin = NULL;
3798 mmplayer_gst_element_t *textbin = NULL;
3799 MMHandleType attrs = 0;
3800 GstElement *subsrc = NULL;
3801 GstElement *subparse = NULL;
3802 gchar *subtitle_uri = NULL;
3803 const gchar *charset = NULL;
3809 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3811 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3813 mainbin = player->pipeline->mainbin;
3815 attrs = MMPLAYER_GET_ATTRS(player);
3817 LOGE("cannot get content attribute");
3818 return MM_ERROR_PLAYER_INTERNAL;
3821 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3822 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3823 LOGE("subtitle uri is not proper filepath.");
3824 return MM_ERROR_PLAYER_INVALID_URI;
3827 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3828 LOGE("failed to get storage info of subtitle path");
3829 return MM_ERROR_PLAYER_INVALID_URI;
3832 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3834 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3835 player->subtitle_language_list = NULL;
3836 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3838 /* create the subtitle source */
3839 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3841 LOGE("failed to create filesrc element");
3844 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3846 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3847 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3849 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3850 LOGW("failed to add queue");
3851 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3852 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3853 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3858 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3860 LOGE("failed to create subparse element");
3864 charset = _mmplayer_get_charset(subtitle_uri);
3866 LOGD("detected charset is %s", charset);
3867 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3870 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3871 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3873 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3874 LOGW("failed to add subparse");
3875 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3876 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3877 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3881 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3882 LOGW("failed to link subsrc and subparse");
3886 player->play_subtitle = TRUE;
3887 player->adjust_subtitle_pos = 0;
3889 LOGD("play subtitle using subtitle file");
3891 if (player->pipeline->textbin == NULL) {
3892 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3893 LOGE("failed to create text sink bin. continuing without text");
3897 textbin = player->pipeline->textbin;
3899 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3900 LOGW("failed to add textbin");
3902 /* release signal */
3903 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3905 /* release textbin with it's childs */
3906 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3907 MMPLAYER_FREEIF(player->pipeline->textbin);
3908 player->pipeline->textbin = textbin = NULL;
3912 LOGD("link text input selector and textbin ghost pad");
3914 player->textsink_linked = 1;
3915 player->external_text_idx = 0;
3916 LOGI("textsink is linked");
3918 textbin = player->pipeline->textbin;
3919 LOGD("text bin has been created. reuse it.");
3920 player->external_text_idx = 1;
3923 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3924 LOGW("failed to link subparse and textbin");
3928 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3930 LOGE("failed to get sink pad from textsink to probe data");
3934 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3935 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3937 gst_object_unref(pad);
3940 /* create dot. for debugging */
3941 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3944 return MM_ERROR_NONE;
3947 /* release text pipeline resource */
3948 player->textsink_linked = 0;
3950 /* release signal */
3951 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3953 if (player->pipeline->textbin) {
3954 LOGE("remove textbin");
3956 /* release textbin with it's childs */
3957 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3958 MMPLAYER_FREEIF(player->pipeline->textbin);
3959 player->pipeline->textbin = NULL;
3963 /* release subtitle elem */
3964 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3965 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3967 return MM_ERROR_PLAYER_INTERNAL;
3971 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3973 mmplayer_t *player = (mmplayer_t *)data;
3974 MMMessageParamType msg = {0, };
3975 GstClockTime duration = 0;
3976 gpointer text = NULL;
3977 guint text_size = 0;
3978 gboolean ret = TRUE;
3979 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3983 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3984 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3986 if (player->is_subtitle_force_drop) {
3987 LOGW("subtitle is dropped forcedly.");
3991 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3992 text = mapinfo.data;
3993 text_size = mapinfo.size;
3995 if (player->set_mode.subtitle_off) {
3996 LOGD("subtitle is OFF.");
4000 if (!text || (text_size == 0)) {
4001 LOGD("There is no subtitle to be displayed.");
4005 msg.data = (void *)text;
4007 duration = GST_BUFFER_DURATION(buffer);
4009 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4010 if (player->duration > GST_BUFFER_PTS(buffer))
4011 duration = player->duration - GST_BUFFER_PTS(buffer);
4014 LOGI("subtitle duration is invalid, subtitle duration change "
4015 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4017 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4019 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4021 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4022 gst_buffer_unmap(buffer, &mapinfo);
4029 static GstPadProbeReturn
4030 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4032 mmplayer_t *player = (mmplayer_t *)u_data;
4033 GstClockTime cur_timestamp = 0;
4034 gint64 adjusted_timestamp = 0;
4035 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4037 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4039 if (player->set_mode.subtitle_off) {
4040 LOGD("subtitle is OFF.");
4044 if (player->adjust_subtitle_pos == 0) {
4045 LOGD("nothing to do");
4049 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4050 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4052 if (adjusted_timestamp < 0) {
4053 LOGD("adjusted_timestamp under zero");
4058 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4059 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4060 GST_TIME_ARGS(cur_timestamp),
4061 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4063 return GST_PAD_PROBE_OK;
4067 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4071 /* check player and subtitlebin are created */
4072 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4073 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4075 if (position == 0) {
4076 LOGD("nothing to do");
4078 return MM_ERROR_NONE;
4081 /* check current postion */
4082 player->adjust_subtitle_pos = position;
4084 LOGD("save adjust_subtitle_pos in player");
4088 return MM_ERROR_NONE;
4092 * This function is to create audio or video pipeline for playing.
4094 * @param player [in] handle of player
4096 * @return This function returns zero on success.
4101 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4103 int ret = MM_ERROR_NONE;
4104 mmplayer_gst_element_t *mainbin = NULL;
4105 MMHandleType attrs = 0;
4108 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4110 /* get profile attribute */
4111 attrs = MMPLAYER_GET_ATTRS(player);
4113 LOGE("failed to get content attribute");
4117 /* create pipeline handles */
4118 if (player->pipeline) {
4119 LOGE("pipeline should be released before create new one");
4123 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4124 if (player->pipeline == NULL)
4127 /* create mainbin */
4128 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4129 if (mainbin == NULL)
4132 /* create pipeline */
4133 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4134 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4135 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4136 LOGE("failed to create pipeline");
4141 player->pipeline->mainbin = mainbin;
4143 /* create the source and decoder elements */
4144 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4145 ret = _mmplayer_gst_build_es_pipeline(player);
4147 ret = _mmplayer_gst_build_pipeline(player);
4149 if (ret != MM_ERROR_NONE) {
4150 LOGE("failed to create some elements");
4154 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4155 if (__mmplayer_check_subtitle(player)
4156 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4157 LOGE("failed to create text pipeline");
4160 ret = _mmplayer_gst_add_bus_watch(player);
4161 if (ret != MM_ERROR_NONE) {
4162 LOGE("failed to add bus watch");
4167 return MM_ERROR_NONE;
4170 __mmplayer_gst_destroy_pipeline(player);
4171 return MM_ERROR_PLAYER_INTERNAL;
4175 __mmplayer_reset_gapless_state(mmplayer_t *player)
4178 MMPLAYER_RETURN_IF_FAIL(player
4180 && player->pipeline->audiobin
4181 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4183 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4190 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4193 int ret = MM_ERROR_NONE;
4197 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4199 /* cleanup stuffs */
4200 MMPLAYER_FREEIF(player->type);
4201 player->no_more_pad = FALSE;
4202 player->num_dynamic_pad = 0;
4203 player->demux_pad_index = 0;
4205 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4206 player->subtitle_language_list = NULL;
4207 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4209 __mmplayer_reset_gapless_state(player);
4211 if (player->streamer) {
4212 _mm_player_streaming_initialize(player->streamer, FALSE);
4213 _mm_player_streaming_destroy(player->streamer);
4214 player->streamer = NULL;
4217 /* cleanup unlinked mime type */
4218 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4219 MMPLAYER_FREEIF(player->unlinked_video_mime);
4220 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4222 /* cleanup running stuffs */
4223 _mmplayer_cancel_eos_timer(player);
4225 /* cleanup gst stuffs */
4226 if (player->pipeline) {
4227 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4228 GstTagList *tag_list = player->pipeline->tag_list;
4230 /* first we need to disconnect all signal hander */
4231 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4234 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4235 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4236 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4237 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4238 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4239 gst_object_unref(bus);
4241 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4242 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4243 if (ret != MM_ERROR_NONE) {
4244 LOGE("fail to change state to NULL");
4245 return MM_ERROR_PLAYER_INTERNAL;
4248 LOGW("succeeded in changing state to NULL");
4250 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4253 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4254 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4256 /* free avsysaudiosink
4257 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4258 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4260 MMPLAYER_FREEIF(audiobin);
4261 MMPLAYER_FREEIF(videobin);
4262 MMPLAYER_FREEIF(textbin);
4263 MMPLAYER_FREEIF(mainbin);
4267 gst_tag_list_unref(tag_list);
4269 MMPLAYER_FREEIF(player->pipeline);
4271 MMPLAYER_FREEIF(player->album_art);
4273 if (player->v_stream_caps) {
4274 gst_caps_unref(player->v_stream_caps);
4275 player->v_stream_caps = NULL;
4278 if (player->a_stream_caps) {
4279 gst_caps_unref(player->a_stream_caps);
4280 player->a_stream_caps = NULL;
4283 if (player->s_stream_caps) {
4284 gst_caps_unref(player->s_stream_caps);
4285 player->s_stream_caps = NULL;
4287 _mmplayer_track_destroy(player);
4289 if (player->sink_elements)
4290 g_list_free(player->sink_elements);
4291 player->sink_elements = NULL;
4293 if (player->bufmgr) {
4294 tbm_bufmgr_deinit(player->bufmgr);
4295 player->bufmgr = NULL;
4298 LOGW("finished destroy pipeline");
4306 __mmplayer_gst_realize(mmplayer_t *player)
4309 int ret = MM_ERROR_NONE;
4313 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4315 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4317 ret = __mmplayer_gst_create_pipeline(player);
4319 LOGE("failed to create pipeline");
4323 /* set pipeline state to READY */
4324 /* NOTE : state change to READY must be performed sync. */
4325 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4326 ret = _mmplayer_gst_set_state(player,
4327 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4329 if (ret != MM_ERROR_NONE) {
4330 /* return error if failed to set state */
4331 LOGE("failed to set READY state");
4335 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4337 /* create dot before error-return. for debugging */
4338 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4346 __mmplayer_gst_unrealize(mmplayer_t *player)
4348 int ret = MM_ERROR_NONE;
4352 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4354 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4355 MMPLAYER_PRINT_STATE(player);
4357 /* release miscellaneous information */
4358 __mmplayer_release_misc(player);
4360 /* destroy pipeline */
4361 ret = __mmplayer_gst_destroy_pipeline(player);
4362 if (ret != MM_ERROR_NONE) {
4363 LOGE("failed to destory pipeline");
4367 /* release miscellaneous information.
4368 these info needs to be released after pipeline is destroyed. */
4369 __mmplayer_release_misc_post(player);
4371 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4379 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4384 LOGW("set_message_callback is called with invalid player handle");
4385 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4388 player->msg_cb = callback;
4389 player->msg_cb_param = user_param;
4391 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4395 return MM_ERROR_NONE;
4399 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4401 int ret = MM_ERROR_NONE;
4406 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4407 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4408 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4410 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4412 if (strstr(uri, "es_buff://")) {
4413 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4414 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4415 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4416 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4418 tmp = g_ascii_strdown(uri, strlen(uri));
4419 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4420 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4422 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4424 } else if (strstr(uri, "mms://")) {
4425 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4426 } else if ((path = strstr(uri, "mem://"))) {
4427 ret = __mmplayer_set_mem_uri(data, path, param);
4429 ret = __mmplayer_set_file_uri(data, uri);
4432 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4433 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4434 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4435 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4437 /* dump parse result */
4438 SECURE_LOGW("incoming uri : %s", uri);
4439 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4440 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4448 __mmplayer_can_do_interrupt(mmplayer_t *player)
4450 if (!player || !player->pipeline || !player->attrs) {
4451 LOGW("not initialized");
4455 if (player->audio_decoded_cb) {
4456 LOGW("not support in pcm extraction mode");
4460 /* check if seeking */
4461 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4462 MMMessageParamType msg_param;
4463 memset(&msg_param, 0, sizeof(MMMessageParamType));
4464 msg_param.code = MM_ERROR_PLAYER_SEEK;
4465 player->seek_state = MMPLAYER_SEEK_NONE;
4466 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4470 /* check other thread */
4471 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4472 LOGW("locked already, cmd state : %d", player->cmd);
4474 /* check application command */
4475 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4476 LOGW("playing.. should wait cmd lock then, will be interrupted");
4478 /* lock will be released at mrp_resource_release_cb() */
4479 MMPLAYER_CMD_LOCK(player);
4482 LOGW("nothing to do");
4485 LOGW("can interrupt immediately");
4489 FAILED: /* with CMD UNLOCKED */
4492 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4497 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4500 mmplayer_t *player = NULL;
4501 MMMessageParamType msg = {0, };
4503 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4508 LOGE("user_data is null");
4511 player = (mmplayer_t *)user_data;
4513 if (!__mmplayer_can_do_interrupt(player)) {
4514 LOGW("no need to interrupt, so leave");
4515 /* FIXME: there is no way to avoid releasing resource. */
4519 player->interrupted_by_resource = TRUE;
4521 /* get last play position */
4522 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4523 msg.union_type = MM_MSG_UNION_TIME;
4524 msg.time.elapsed = pos;
4525 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4527 LOGW("failed to get play position.");
4530 LOGD("video resource conflict so, resource will be freed by unrealizing");
4531 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4532 LOGE("failed to unrealize");
4534 /* lock is called in __mmplayer_can_do_interrupt() */
4535 MMPLAYER_CMD_UNLOCK(player);
4537 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4538 player->hw_resource[res_idx] = NULL;
4542 return TRUE; /* release all the resources */
4546 __mmplayer_initialize_video_roi(mmplayer_t *player)
4548 player->video_roi.scale_x = 0.0;
4549 player->video_roi.scale_y = 0.0;
4550 player->video_roi.scale_width = 1.0;
4551 player->video_roi.scale_height = 1.0;
4555 _mmplayer_create_player(MMHandleType handle)
4557 int ret = MM_ERROR_PLAYER_INTERNAL;
4558 bool enabled = false;
4560 mmplayer_t *player = MM_PLAYER_CAST(handle);
4564 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4566 /* initialize player state */
4567 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4568 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4569 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4570 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4572 /* check current state */
4573 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4575 /* construct attributes */
4576 player->attrs = _mmplayer_construct_attribute(handle);
4578 if (!player->attrs) {
4579 LOGE("Failed to construct attributes");
4583 /* initialize gstreamer with configured parameter */
4584 if (!__mmplayer_init_gstreamer(player)) {
4585 LOGE("Initializing gstreamer failed");
4586 _mmplayer_deconstruct_attribute(handle);
4590 /* create lock. note that g_tread_init() has already called in gst_init() */
4591 g_mutex_init(&player->fsink_lock);
4593 /* create update tag lock */
4594 g_mutex_init(&player->update_tag_lock);
4596 /* create gapless play mutex */
4597 g_mutex_init(&player->gapless_play_thread_mutex);
4599 /* create gapless play cond */
4600 g_cond_init(&player->gapless_play_thread_cond);
4602 /* create gapless play thread */
4603 player->gapless_play_thread =
4604 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4605 if (!player->gapless_play_thread) {
4606 LOGE("failed to create gapless play thread");
4607 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4608 g_mutex_clear(&player->gapless_play_thread_mutex);
4609 g_cond_clear(&player->gapless_play_thread_cond);
4613 player->bus_msg_q = g_queue_new();
4614 if (!player->bus_msg_q) {
4615 LOGE("failed to create queue for bus_msg");
4616 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4620 ret = _mmplayer_initialize_video_capture(player);
4621 if (ret != MM_ERROR_NONE) {
4622 LOGE("failed to initialize video capture");
4626 /* initialize resource manager */
4627 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4628 __resource_release_cb, player, &player->resource_manager)
4629 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4630 LOGE("failed to initialize resource manager");
4631 ret = MM_ERROR_PLAYER_INTERNAL;
4635 /* create video bo lock and cond */
4636 g_mutex_init(&player->video_bo_mutex);
4637 g_cond_init(&player->video_bo_cond);
4639 /* create subtitle info lock and cond */
4640 g_mutex_init(&player->subtitle_info_mutex);
4641 g_cond_init(&player->subtitle_info_cond);
4643 player->streaming_type = STREAMING_SERVICE_NONE;
4645 /* give default value of audio effect setting */
4646 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4647 player->sound.rg_enable = false;
4648 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4650 player->play_subtitle = FALSE;
4651 player->has_closed_caption = FALSE;
4652 player->pending_resume = FALSE;
4653 if (player->ini.dump_element_keyword[0][0] == '\0')
4654 player->ini.set_dump_element_flag = FALSE;
4656 player->ini.set_dump_element_flag = TRUE;
4658 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4659 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4660 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4662 /* Set video360 settings to their defaults for just-created player.
4665 player->is_360_feature_enabled = FALSE;
4666 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4667 LOGI("spherical feature info: %d", enabled);
4669 player->is_360_feature_enabled = TRUE;
4671 LOGE("failed to get spherical feature info");
4674 player->is_content_spherical = FALSE;
4675 player->is_video360_enabled = TRUE;
4676 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4677 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4678 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4679 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4680 player->video360_zoom = 1.0f;
4681 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4682 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4684 __mmplayer_initialize_video_roi(player);
4686 /* set player state to null */
4687 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4688 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4692 return MM_ERROR_NONE;
4696 g_mutex_clear(&player->fsink_lock);
4697 /* free update tag lock */
4698 g_mutex_clear(&player->update_tag_lock);
4699 g_queue_free(player->bus_msg_q);
4700 player->bus_msg_q = NULL;
4701 /* free gapless play thread */
4702 if (player->gapless_play_thread) {
4703 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4704 player->gapless_play_thread_exit = TRUE;
4705 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4706 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4708 g_thread_join(player->gapless_play_thread);
4709 player->gapless_play_thread = NULL;
4711 g_mutex_clear(&player->gapless_play_thread_mutex);
4712 g_cond_clear(&player->gapless_play_thread_cond);
4715 /* release attributes */
4716 _mmplayer_deconstruct_attribute(handle);
4724 __mmplayer_init_gstreamer(mmplayer_t *player)
4726 static gboolean initialized = FALSE;
4727 static const int max_argc = 50;
4729 gchar **argv = NULL;
4730 gchar **argv2 = NULL;
4736 LOGD("gstreamer already initialized.");
4741 argc = malloc(sizeof(int));
4742 argv = malloc(sizeof(gchar *) * max_argc);
4743 argv2 = malloc(sizeof(gchar *) * max_argc);
4745 if (!argc || !argv || !argv2)
4748 memset(argv, 0, sizeof(gchar *) * max_argc);
4749 memset(argv2, 0, sizeof(gchar *) * max_argc);
4753 argv[0] = g_strdup("mmplayer");
4756 for (i = 0; i < 5; i++) {
4757 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4758 if (strlen(player->ini.gst_param[i]) > 0) {
4759 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4764 /* we would not do fork for scanning plugins */
4765 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4768 /* check disable registry scan */
4769 if (player->ini.skip_rescan) {
4770 argv[*argc] = g_strdup("--gst-disable-registry-update");
4774 /* check disable segtrap */
4775 if (player->ini.disable_segtrap) {
4776 argv[*argc] = g_strdup("--gst-disable-segtrap");
4780 LOGD("initializing gstreamer with following parameter");
4781 LOGD("argc : %d", *argc);
4784 for (i = 0; i < arg_count; i++) {
4786 LOGD("argv[%d] : %s", i, argv2[i]);
4789 /* initializing gstreamer */
4790 if (!gst_init_check(argc, &argv, &err)) {
4791 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4798 for (i = 0; i < arg_count; i++) {
4800 LOGD("release - argv[%d] : %s", i, argv2[i]);
4802 MMPLAYER_FREEIF(argv2[i]);
4805 MMPLAYER_FREEIF(argv);
4806 MMPLAYER_FREEIF(argv2);
4807 MMPLAYER_FREEIF(argc);
4817 for (i = 0; i < arg_count; i++) {
4818 LOGD("free[%d] : %s", i, argv2[i]);
4819 MMPLAYER_FREEIF(argv2[i]);
4822 MMPLAYER_FREEIF(argv);
4823 MMPLAYER_FREEIF(argv2);
4824 MMPLAYER_FREEIF(argc);
4830 __mmplayer_check_async_state_transition(mmplayer_t *player)
4832 GstState element_state = GST_STATE_VOID_PENDING;
4833 GstState element_pending_state = GST_STATE_VOID_PENDING;
4834 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4835 GstElement *element = NULL;
4836 gboolean async = FALSE;
4838 /* check player handle */
4839 MMPLAYER_RETURN_IF_FAIL(player &&
4841 player->pipeline->mainbin &&
4842 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4845 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4847 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4848 LOGD("don't need to check the pipeline state");
4852 MMPLAYER_PRINT_STATE(player);
4854 /* wait for state transition */
4855 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4856 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4858 if (ret == GST_STATE_CHANGE_FAILURE) {
4859 LOGE(" [%s] state : %s pending : %s",
4860 GST_ELEMENT_NAME(element),
4861 gst_element_state_get_name(element_state),
4862 gst_element_state_get_name(element_pending_state));
4864 /* dump state of all element */
4865 _mmplayer_dump_pipeline_state(player);
4870 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4875 _mmplayer_destroy(MMHandleType handle)
4877 mmplayer_t *player = MM_PLAYER_CAST(handle);
4881 /* check player handle */
4882 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4884 /* destroy can called at anytime */
4885 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4887 /* check async state transition */
4888 __mmplayer_check_async_state_transition(player);
4890 /* release gapless play thread */
4891 if (player->gapless_play_thread) {
4892 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4893 player->gapless_play_thread_exit = TRUE;
4894 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4895 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4897 LOGD("waitting for gapless play thread exit");
4898 g_thread_join(player->gapless_play_thread);
4899 g_mutex_clear(&player->gapless_play_thread_mutex);
4900 g_cond_clear(&player->gapless_play_thread_cond);
4901 LOGD("gapless play thread released");
4904 _mmplayer_release_video_capture(player);
4906 /* de-initialize resource manager */
4907 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4908 player->resource_manager))
4909 LOGE("failed to deinitialize resource manager");
4911 /* release pipeline */
4912 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4913 LOGE("failed to destory pipeline");
4914 return MM_ERROR_PLAYER_INTERNAL;
4917 g_queue_free(player->bus_msg_q);
4919 /* release subtitle info lock and cond */
4920 g_mutex_clear(&player->subtitle_info_mutex);
4921 g_cond_clear(&player->subtitle_info_cond);
4923 __mmplayer_release_dump_list(player->dump_list);
4925 /* release miscellaneous information */
4926 __mmplayer_release_misc(player);
4928 /* release miscellaneous information.
4929 these info needs to be released after pipeline is destroyed. */
4930 __mmplayer_release_misc_post(player);
4932 /* release attributes */
4933 _mmplayer_deconstruct_attribute(handle);
4936 g_mutex_clear(&player->fsink_lock);
4939 g_mutex_clear(&player->update_tag_lock);
4941 /* release video bo lock and cond */
4942 g_mutex_clear(&player->video_bo_mutex);
4943 g_cond_clear(&player->video_bo_cond);
4947 return MM_ERROR_NONE;
4951 _mmplayer_realize(MMHandleType hplayer)
4953 mmplayer_t *player = (mmplayer_t *)hplayer;
4956 MMHandleType attrs = 0;
4957 int ret = MM_ERROR_NONE;
4961 /* check player handle */
4962 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4964 /* check current state */
4965 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4967 attrs = MMPLAYER_GET_ATTRS(player);
4969 LOGE("fail to get attributes.");
4970 return MM_ERROR_PLAYER_INTERNAL;
4972 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4973 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4975 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4976 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4978 if (ret != MM_ERROR_NONE) {
4979 LOGE("failed to parse profile");
4984 if (uri && (strstr(uri, "es_buff://"))) {
4985 if (strstr(uri, "es_buff://push_mode"))
4986 player->es_player_push_mode = TRUE;
4988 player->es_player_push_mode = FALSE;
4991 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4992 LOGW("mms protocol is not supported format.");
4993 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4996 if (MMPLAYER_IS_STREAMING(player))
4997 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4999 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5001 player->smooth_streaming = FALSE;
5002 player->videodec_linked = 0;
5003 player->audiodec_linked = 0;
5004 player->textsink_linked = 0;
5005 player->is_external_subtitle_present = FALSE;
5006 player->is_external_subtitle_added_now = FALSE;
5007 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5008 player->video360_metadata.is_spherical = -1;
5009 player->is_openal_plugin_used = FALSE;
5010 player->demux_pad_index = 0;
5011 player->subtitle_language_list = NULL;
5012 player->is_subtitle_force_drop = FALSE;
5014 _mmplayer_track_initialize(player);
5015 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5017 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5018 gint prebuffer_ms = 0, rebuffer_ms = 0;
5020 player->streamer = _mm_player_streaming_create();
5021 _mm_player_streaming_initialize(player->streamer, TRUE);
5023 mm_attrs_multiple_get(player->attrs, NULL,
5024 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5025 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5027 if (prebuffer_ms > 0) {
5028 prebuffer_ms = MAX(prebuffer_ms, 1000);
5029 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5032 if (rebuffer_ms > 0) {
5033 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5034 rebuffer_ms = MAX(rebuffer_ms, 1000);
5035 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5038 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5039 player->streamer->buffering_req.rebuffer_time);
5042 /* realize pipeline */
5043 ret = __mmplayer_gst_realize(player);
5044 if (ret != MM_ERROR_NONE)
5045 LOGE("fail to realize the player.");
5047 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5055 _mmplayer_unrealize(MMHandleType hplayer)
5057 mmplayer_t *player = (mmplayer_t *)hplayer;
5058 int ret = MM_ERROR_NONE;
5062 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5064 MMPLAYER_CMD_UNLOCK(player);
5065 /* destroy the gst bus msg thread which is created during realize.
5066 this funct have to be called before getting cmd lock. */
5067 _mmplayer_bus_msg_thread_destroy(player);
5068 MMPLAYER_CMD_LOCK(player);
5070 /* check current state */
5071 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5073 /* check async state transition */
5074 __mmplayer_check_async_state_transition(player);
5076 /* unrealize pipeline */
5077 ret = __mmplayer_gst_unrealize(player);
5079 if (!player->interrupted_by_resource) {
5080 int rm_ret = MM_ERROR_NONE;
5081 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5083 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5084 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5085 if (rm_ret != MM_ERROR_NONE)
5086 LOGE("failed to release [%d] resources", res_idx);
5095 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5097 mmplayer_t *player = (mmplayer_t *)hplayer;
5099 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5101 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5105 _mmplayer_get_state(MMHandleType hplayer, int *state)
5107 mmplayer_t *player = (mmplayer_t *)hplayer;
5109 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5111 *state = MMPLAYER_CURRENT_STATE(player);
5113 return MM_ERROR_NONE;
5117 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5119 GstElement *vol_element = NULL;
5120 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5123 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5124 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5126 /* check pipeline handle */
5127 if (!player->pipeline || !player->pipeline->audiobin) {
5128 LOGD("'%s' will be applied when audiobin is created", prop_name);
5130 /* NOTE : stored value will be used in create_audiobin
5131 * returning MM_ERROR_NONE here makes application to able to
5132 * set audio volume or mute at anytime.
5134 return MM_ERROR_NONE;
5137 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5138 volume_elem_id = MMPLAYER_A_SINK;
5140 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5142 LOGE("failed to get vol element %d", volume_elem_id);
5143 return MM_ERROR_PLAYER_INTERNAL;
5146 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5148 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5149 LOGE("there is no '%s' property", prop_name);
5150 return MM_ERROR_PLAYER_INTERNAL;
5153 if (!strcmp(prop_name, "volume")) {
5154 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5155 } else if (!strcmp(prop_name, "mute")) {
5156 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5158 LOGE("invalid property %s", prop_name);
5159 return MM_ERROR_PLAYER_INTERNAL;
5162 return MM_ERROR_NONE;
5166 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5168 int ret = MM_ERROR_NONE;
5169 mmplayer_t *player = (mmplayer_t *)hplayer;
5172 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5174 LOGD("volume = %f", volume);
5176 /* invalid factor range or not */
5177 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5178 LOGE("Invalid volume value");
5179 return MM_ERROR_INVALID_ARGUMENT;
5182 player->sound.volume = volume;
5184 ret = __mmplayer_gst_set_volume_property(player, "volume");
5191 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5193 mmplayer_t *player = (mmplayer_t *)hplayer;
5197 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5198 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5200 *volume = player->sound.volume;
5202 LOGD("current vol = %f", *volume);
5205 return MM_ERROR_NONE;
5209 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5211 int ret = MM_ERROR_NONE;
5212 mmplayer_t *player = (mmplayer_t *)hplayer;
5215 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5217 LOGD("mute = %d", mute);
5219 player->sound.mute = mute;
5221 ret = __mmplayer_gst_set_volume_property(player, "mute");
5228 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5230 mmplayer_t *player = (mmplayer_t *)hplayer;
5234 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5235 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5237 *mute = player->sound.mute;
5239 LOGD("current mute = %d", *mute);
5243 return MM_ERROR_NONE;
5247 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5249 mmplayer_t *player = (mmplayer_t *)hplayer;
5253 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5255 player->audio_stream_changed_cb = callback;
5256 player->audio_stream_changed_cb_user_param = user_param;
5257 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5261 return MM_ERROR_NONE;
5265 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5267 mmplayer_t *player = (mmplayer_t *)hplayer;
5271 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5273 player->audio_decoded_cb = callback;
5274 player->audio_decoded_cb_user_param = user_param;
5275 player->audio_extract_opt = opt;
5276 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5280 return MM_ERROR_NONE;
5284 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5286 mmplayer_t *player = (mmplayer_t *)hplayer;
5290 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5292 if (callback && !player->bufmgr)
5293 player->bufmgr = tbm_bufmgr_init(-1);
5295 player->set_mode.video_export = (callback) ? true : false;
5296 player->video_decoded_cb = callback;
5297 player->video_decoded_cb_user_param = user_param;
5299 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5303 return MM_ERROR_NONE;
5307 _mmplayer_start(MMHandleType hplayer)
5309 mmplayer_t *player = (mmplayer_t *)hplayer;
5310 gint ret = MM_ERROR_NONE;
5314 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5316 /* check current state */
5317 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5319 /* start pipeline */
5320 ret = _mmplayer_gst_start(player);
5321 if (ret != MM_ERROR_NONE)
5322 LOGE("failed to start player.");
5324 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5325 LOGD("force playing start even during buffering");
5326 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5334 /* NOTE: post "not supported codec message" to application
5335 * when one codec is not found during AUTOPLUGGING in MSL.
5336 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5337 * And, if any codec is not found, don't send message here.
5338 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5341 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5343 MMMessageParamType msg_param;
5344 memset(&msg_param, 0, sizeof(MMMessageParamType));
5345 gboolean post_msg_direct = FALSE;
5349 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5351 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5352 player->not_supported_codec, player->can_support_codec);
5354 if (player->not_found_demuxer) {
5355 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5356 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5358 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5359 MMPLAYER_FREEIF(msg_param.data);
5361 return MM_ERROR_NONE;
5364 if (player->not_supported_codec) {
5365 if (player->can_support_codec) {
5366 // There is one codec to play
5367 post_msg_direct = TRUE;
5369 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5370 post_msg_direct = TRUE;
5373 if (post_msg_direct) {
5374 MMMessageParamType msg_param;
5375 memset(&msg_param, 0, sizeof(MMMessageParamType));
5377 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5378 LOGW("not found AUDIO codec, posting error code to application.");
5380 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5381 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5382 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5383 LOGW("not found VIDEO codec, posting error code to application.");
5385 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5386 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5389 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5391 MMPLAYER_FREEIF(msg_param.data);
5393 return MM_ERROR_NONE;
5395 // no any supported codec case
5396 LOGW("not found any codec, posting error code to application.");
5398 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5399 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5400 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5402 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5403 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5406 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5408 MMPLAYER_FREEIF(msg_param.data);
5414 return MM_ERROR_NONE;
5418 __mmplayer_check_pipeline(mmplayer_t *player)
5420 GstState element_state = GST_STATE_VOID_PENDING;
5421 GstState element_pending_state = GST_STATE_VOID_PENDING;
5423 int ret = MM_ERROR_NONE;
5425 if (!player->gapless.reconfigure)
5428 LOGW("pipeline is under construction.");
5430 MMPLAYER_PLAYBACK_LOCK(player);
5431 MMPLAYER_PLAYBACK_UNLOCK(player);
5433 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5435 /* wait for state transition */
5436 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5437 if (ret == GST_STATE_CHANGE_FAILURE)
5438 LOGE("failed to change pipeline state within %d sec", timeout);
5441 /* NOTE : it should be able to call 'stop' anytime*/
5443 _mmplayer_stop(MMHandleType hplayer)
5445 mmplayer_t *player = (mmplayer_t *)hplayer;
5446 int ret = MM_ERROR_NONE;
5450 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5452 /* check current state */
5453 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5455 /* check pipline building state */
5456 __mmplayer_check_pipeline(player);
5457 __mmplayer_reset_gapless_state(player);
5459 /* NOTE : application should not wait for EOS after calling STOP */
5460 _mmplayer_cancel_eos_timer(player);
5463 player->seek_state = MMPLAYER_SEEK_NONE;
5466 ret = _mmplayer_gst_stop(player);
5468 if (ret != MM_ERROR_NONE)
5469 LOGE("failed to stop player.");
5477 _mmplayer_pause(MMHandleType hplayer)
5479 mmplayer_t *player = (mmplayer_t *)hplayer;
5480 gint64 pos_nsec = 0;
5481 gboolean async = FALSE;
5482 gint ret = MM_ERROR_NONE;
5486 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5488 /* check current state */
5489 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5491 /* check pipline building state */
5492 __mmplayer_check_pipeline(player);
5494 switch (MMPLAYER_CURRENT_STATE(player)) {
5495 case MM_PLAYER_STATE_READY:
5497 /* check prepare async or not.
5498 * In the case of streaming playback, it's recommned to avoid blocking wait.
5500 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5501 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5503 /* Changing back sync of rtspsrc to async */
5504 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5505 LOGD("async prepare working mode for rtsp");
5511 case MM_PLAYER_STATE_PLAYING:
5513 /* NOTE : store current point to overcome some bad operation
5514 *(returning zero when getting current position in paused state) of some
5517 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5518 LOGW("getting current position failed in paused");
5520 player->last_position = pos_nsec;
5522 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5523 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5524 This causes problem is position calculation during normal pause resume scenarios also.
5525 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5526 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5527 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5528 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5534 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5535 LOGD("doing async pause in case of ms buff src");
5539 /* pause pipeline */
5540 ret = _mmplayer_gst_pause(player, async);
5542 if (ret != MM_ERROR_NONE)
5543 LOGE("failed to pause player. ret : 0x%x", ret);
5545 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5546 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5547 LOGE("failed to update display_rotation");
5555 /* in case of streaming, pause could take long time.*/
5557 _mmplayer_abort_pause(MMHandleType hplayer)
5559 mmplayer_t *player = (mmplayer_t *)hplayer;
5560 int ret = MM_ERROR_NONE;
5564 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5566 player->pipeline->mainbin,
5567 MM_ERROR_PLAYER_NOT_INITIALIZED);
5569 LOGD("set the pipeline state to READY");
5571 /* set state to READY */
5572 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5573 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5574 if (ret != MM_ERROR_NONE) {
5575 LOGE("fail to change state to READY");
5576 return MM_ERROR_PLAYER_INTERNAL;
5579 LOGD("succeeded in changing state to READY");
5584 _mmplayer_resume(MMHandleType hplayer)
5586 mmplayer_t *player = (mmplayer_t *)hplayer;
5587 int ret = MM_ERROR_NONE;
5588 gboolean async = FALSE;
5592 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5594 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5595 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5596 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5600 /* Changing back sync mode rtspsrc to async */
5601 LOGD("async resume for rtsp case");
5605 /* check current state */
5606 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5608 ret = _mmplayer_gst_resume(player, async);
5609 if (ret != MM_ERROR_NONE)
5610 LOGE("failed to resume player.");
5612 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5613 LOGD("force resume even during buffering");
5614 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5623 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5625 mmplayer_t *player = (mmplayer_t *)hplayer;
5626 gint64 pos_nsec = 0;
5627 int ret = MM_ERROR_NONE;
5629 signed long long start = 0, stop = 0;
5630 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5633 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5634 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5636 /* The sound of video is not supported under 0.0 and over 2.0. */
5637 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5638 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5641 _mmplayer_set_mute(hplayer, mute);
5643 if (player->playback_rate == rate)
5644 return MM_ERROR_NONE;
5646 /* If the position is reached at start potion during fast backward, EOS is posted.
5647 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5649 player->playback_rate = rate;
5651 current_state = MMPLAYER_CURRENT_STATE(player);
5653 if (current_state != MM_PLAYER_STATE_PAUSED)
5654 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5656 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5658 if ((current_state == MM_PLAYER_STATE_PAUSED)
5659 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5660 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5661 pos_nsec = player->last_position;
5666 stop = GST_CLOCK_TIME_NONE;
5668 start = GST_CLOCK_TIME_NONE;
5672 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5673 player->playback_rate,
5675 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5676 GST_SEEK_TYPE_SET, start,
5677 GST_SEEK_TYPE_SET, stop)) {
5678 LOGE("failed to set speed playback");
5679 return MM_ERROR_PLAYER_SEEK;
5682 LOGD("succeeded to set speed playback as %0.1f", rate);
5686 return MM_ERROR_NONE;;
5690 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5692 mmplayer_t *player = (mmplayer_t *)hplayer;
5693 int ret = MM_ERROR_NONE;
5697 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5699 /* check pipline building state */
5700 __mmplayer_check_pipeline(player);
5702 ret = _mmplayer_gst_set_position(player, position, FALSE);
5710 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5712 mmplayer_t *player = (mmplayer_t *)hplayer;
5713 int ret = MM_ERROR_NONE;
5715 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5716 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5718 if (g_strrstr(player->type, "video/mpegts"))
5719 __mmplayer_update_duration_value(player);
5721 *duration = player->duration;
5726 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5728 mmplayer_t *player = (mmplayer_t *)hplayer;
5729 int ret = MM_ERROR_NONE;
5731 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5733 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5739 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5741 mmplayer_t *player = (mmplayer_t *)hplayer;
5742 int ret = MM_ERROR_NONE;
5746 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5748 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5756 __mmplayer_is_midi_type(gchar *str_caps)
5758 if ((g_strrstr(str_caps, "audio/midi")) ||
5759 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5760 (g_strrstr(str_caps, "application/x-smaf")) ||
5761 (g_strrstr(str_caps, "audio/x-imelody")) ||
5762 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5763 (g_strrstr(str_caps, "audio/xmf")) ||
5764 (g_strrstr(str_caps, "audio/mxmf"))) {
5773 __mmplayer_is_only_mp3_type(gchar *str_caps)
5775 if (g_strrstr(str_caps, "application/x-id3") ||
5776 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5782 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5784 GstStructure *caps_structure = NULL;
5785 gint samplerate = 0;
5789 MMPLAYER_RETURN_IF_FAIL(player && caps);
5791 caps_structure = gst_caps_get_structure(caps, 0);
5793 /* set stream information */
5794 gst_structure_get_int(caps_structure, "rate", &samplerate);
5795 gst_structure_get_int(caps_structure, "channels", &channels);
5797 mm_player_set_attribute((MMHandleType)player, NULL,
5798 "content_audio_samplerate", samplerate,
5799 "content_audio_channels", channels, NULL);
5801 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5805 __mmplayer_update_content_type_info(mmplayer_t *player)
5808 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5810 if (__mmplayer_is_midi_type(player->type)) {
5811 player->bypass_audio_effect = TRUE;
5815 if (!player->streamer) {
5816 LOGD("no need to check streaming type");
5820 if (g_strrstr(player->type, "application/x-hls")) {
5821 /* If it can't know exact type when it parses uri because of redirection case,
5822 * it will be fixed by typefinder or when doing autoplugging.
5824 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5825 player->streamer->is_adaptive_streaming = TRUE;
5826 } else if (g_strrstr(player->type, "application/dash+xml")) {
5827 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5828 player->streamer->is_adaptive_streaming = TRUE;
5831 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5832 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5833 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5835 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5836 if (player->streamer->is_adaptive_streaming)
5837 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5839 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5843 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5848 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5849 GstCaps *caps, gpointer data)
5851 mmplayer_t *player = (mmplayer_t *)data;
5856 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5858 /* store type string */
5859 MMPLAYER_FREEIF(player->type);
5860 player->type = gst_caps_to_string(caps);
5862 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5863 player, player->type, probability, gst_caps_get_size(caps));
5865 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5866 (g_strrstr(player->type, "audio/x-raw-int"))) {
5867 LOGE("not support media format");
5869 if (player->msg_posted == FALSE) {
5870 MMMessageParamType msg_param;
5871 memset(&msg_param, 0, sizeof(MMMessageParamType));
5873 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5874 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5876 /* don't post more if one was sent already */
5877 player->msg_posted = TRUE;
5882 __mmplayer_update_content_type_info(player);
5884 pad = gst_element_get_static_pad(tf, "src");
5886 LOGE("fail to get typefind src pad.");
5890 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5891 gboolean async = FALSE;
5892 LOGE("failed to autoplug %s", player->type);
5894 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5896 if (async && player->msg_posted == FALSE)
5897 __mmplayer_handle_missed_plugin(player);
5901 gst_object_unref(GST_OBJECT(pad));
5909 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5911 GstElement *decodebin = NULL;
5915 /* create decodebin */
5916 decodebin = gst_element_factory_make("decodebin", NULL);
5919 LOGE("fail to create decodebin");
5923 /* raw pad handling signal */
5924 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5925 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5927 /* no-more-pad pad handling signal */
5928 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5929 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5931 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5932 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5934 /* This signal is emitted when a pad for which there is no further possible
5935 decoding is added to the decodebin.*/
5936 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5937 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5939 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5940 before looking for any elements that can handle that stream.*/
5941 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5942 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5944 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5945 before looking for any elements that can handle that stream.*/
5946 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5947 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5949 /* This signal is emitted once decodebin has finished decoding all the data.*/
5950 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5951 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5953 /* This signal is emitted when a element is added to the bin.*/
5954 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5955 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5962 __mmplayer_gst_make_queue2(mmplayer_t *player)
5964 GstElement *queue2 = NULL;
5965 gint64 dur_bytes = 0L;
5966 mmplayer_gst_element_t *mainbin = NULL;
5967 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5970 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5972 mainbin = player->pipeline->mainbin;
5974 queue2 = gst_element_factory_make("queue2", "queue2");
5976 LOGE("failed to create buffering queue element");
5980 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5981 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5983 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5985 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5986 * skip the pull mode(file or ring buffering) setting. */
5987 if (dur_bytes > 0) {
5988 if (!g_strrstr(player->type, "video/mpegts")) {
5989 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5990 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5996 _mm_player_streaming_set_queue2(player->streamer,
6000 (guint64)dur_bytes); /* no meaning at the moment */
6006 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6008 mmplayer_gst_element_t *mainbin = NULL;
6009 GstElement *decodebin = NULL;
6010 GstElement *queue2 = NULL;
6011 GstPad *sinkpad = NULL;
6012 GstPad *qsrcpad = NULL;
6015 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6017 mainbin = player->pipeline->mainbin;
6019 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6021 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6022 LOGW("need to check: muxed buffer is not null");
6025 queue2 = __mmplayer_gst_make_queue2(player);
6027 LOGE("failed to make queue2");
6031 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6032 LOGE("failed to add buffering queue");
6036 sinkpad = gst_element_get_static_pad(queue2, "sink");
6037 qsrcpad = gst_element_get_static_pad(queue2, "src");
6039 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6040 LOGE("failed to link [%s:%s]-[%s:%s]",
6041 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6045 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6046 LOGE("failed to sync queue2 state with parent");
6050 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6051 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6055 gst_object_unref(GST_OBJECT(sinkpad));
6059 /* create decodebin */
6060 decodebin = _mmplayer_gst_make_decodebin(player);
6062 LOGE("failed to make decodebin");
6066 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6067 LOGE("failed to add decodebin");
6071 /* to force caps on the decodebin element and avoid reparsing stuff by
6072 * typefind. It also avoids a deadlock in the way typefind activates pads in
6073 * the state change */
6074 g_object_set(decodebin, "sink-caps", caps, NULL);
6076 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6078 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6079 LOGE("failed to link [%s:%s]-[%s:%s]",
6080 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6084 gst_object_unref(GST_OBJECT(sinkpad));
6086 gst_object_unref(GST_OBJECT(qsrcpad));
6089 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6090 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6092 /* set decodebin property about buffer in streaming playback. *
6093 * in case of HLS/DASH, it does not need to have big buffer *
6094 * because it is kind of adaptive streaming. */
6095 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6096 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6097 gint high_percent = 0;
6099 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6100 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6102 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6104 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6106 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6107 "high-percent", high_percent,
6108 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6109 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6110 "max-size-buffers", 0, NULL); // disable or automatic
6113 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6114 LOGE("failed to sync decodebin state with parent");
6125 gst_object_unref(GST_OBJECT(sinkpad));
6128 gst_object_unref(GST_OBJECT(qsrcpad));
6131 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6132 * You need to explicitly set elements to the NULL state before
6133 * dropping the final reference, to allow them to clean up.
6135 gst_element_set_state(queue2, GST_STATE_NULL);
6137 /* And, it still has a parent "player".
6138 * You need to let the parent manage the object instead of unreffing the object directly.
6140 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6141 gst_object_unref(queue2);
6146 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6147 * You need to explicitly set elements to the NULL state before
6148 * dropping the final reference, to allow them to clean up.
6150 gst_element_set_state(decodebin, GST_STATE_NULL);
6152 /* And, it still has a parent "player".
6153 * You need to let the parent manage the object instead of unreffing the object directly.
6156 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6157 gst_object_unref(decodebin);
6165 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6169 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6170 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6172 LOGD("class : %s, mime : %s", factory_class, mime);
6174 /* add missing plugin */
6175 /* NOTE : msl should check missing plugin for image mime type.
6176 * Some motion jpeg clips can have playable audio track.
6177 * So, msl have to play audio after displaying popup written video format not supported.
6179 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6180 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6181 LOGD("not found demuxer");
6182 player->not_found_demuxer = TRUE;
6183 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6189 if (!g_strrstr(factory_class, "Demuxer")) {
6190 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6191 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6192 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6194 /* check that clip have multi tracks or not */
6195 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6196 LOGD("video plugin is already linked");
6198 LOGW("add VIDEO to missing plugin");
6199 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6200 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6202 } else if (g_str_has_prefix(mime, "audio")) {
6203 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6204 LOGD("audio plugin is already linked");
6206 LOGW("add AUDIO to missing plugin");
6207 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6208 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6216 return MM_ERROR_NONE;
6220 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6222 mmplayer_t *player = (mmplayer_t *)data;
6226 MMPLAYER_RETURN_IF_FAIL(player);
6228 /* remove fakesink. */
6229 if (!_mmplayer_gst_remove_fakesink(player,
6230 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6231 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6232 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6233 * source element are not same. To overcome this situation, this function will called
6234 * several places and several times. Therefore, this is not an error case.
6239 LOGD("[handle: %p] pipeline has completely constructed", player);
6241 if ((player->ini.async_start) &&
6242 (player->msg_posted == FALSE) &&
6243 (player->cmd >= MMPLAYER_COMMAND_START))
6244 __mmplayer_handle_missed_plugin(player);
6246 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6250 __mmplayer_check_profile(void)
6253 static int profile_tv = -1;
6255 if (__builtin_expect(profile_tv != -1, 1))
6258 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6259 switch (*profileName) {
6274 __mmplayer_get_next_uri(mmplayer_t *player)
6276 mmplayer_parse_profile_t profile;
6278 guint num_of_list = 0;
6281 num_of_list = g_list_length(player->uri_info.uri_list);
6282 uri_idx = player->uri_info.uri_idx;
6284 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6285 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6286 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6288 LOGW("next uri does not exist");
6292 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6293 LOGE("failed to parse profile");
6297 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6298 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6299 LOGW("uri type is not supported(%d)", profile.uri_type);
6303 LOGD("success to find next uri %d", uri_idx);
6307 if (!uri || uri_idx == num_of_list) {
6308 LOGE("failed to find next uri");
6312 player->uri_info.uri_idx = uri_idx;
6313 if (mm_player_set_attribute((MMHandleType)player, NULL,
6314 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6315 LOGE("failed to set attribute");
6319 SECURE_LOGD("next playback uri: %s", uri);
6324 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6326 #define REPEAT_COUNT_INFINITE -1
6327 #define REPEAT_COUNT_MIN 2
6328 #define ORIGINAL_URI_ONLY 1
6330 MMHandleType attrs = 0;
6334 guint num_of_uri = 0;
6335 int profile_tv = -1;
6339 LOGD("checking for gapless play option");
6341 if (player->build_audio_offload) {
6342 LOGE("offload path is not supportable.");
6346 if (player->pipeline->textbin) {
6347 LOGE("subtitle path is enabled. gapless play is not supported.");
6351 attrs = MMPLAYER_GET_ATTRS(player);
6353 LOGE("fail to get attributes.");
6357 mm_attrs_multiple_get(player->attrs, NULL,
6358 "content_video_found", &video,
6359 "profile_play_count", &count,
6360 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6362 /* gapless playback is not supported in case of video at TV profile. */
6363 profile_tv = __mmplayer_check_profile();
6364 if (profile_tv && video) {
6365 LOGW("not support video gapless playback");
6369 /* check repeat count in case of audio */
6371 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6372 LOGW("gapless is disabled");
6376 num_of_uri = g_list_length(player->uri_info.uri_list);
6378 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6380 if (num_of_uri == ORIGINAL_URI_ONLY) {
6381 /* audio looping path */
6382 if (count >= REPEAT_COUNT_MIN) {
6383 /* decrease play count */
6384 /* we succeeded to rewind. update play count and then wait for next EOS */
6386 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6387 } else if (count != REPEAT_COUNT_INFINITE) {
6388 LOGD("there is no next uri and no repeat");
6391 LOGD("looping cnt %d", count);
6393 /* gapless playback path */
6394 if (!__mmplayer_get_next_uri(player)) {
6395 LOGE("failed to get next uri");
6402 LOGE("unable to play gapless path. EOS will be posted soon");
6407 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6409 mmplayer_selector_t *selector = &player->selector[type];
6410 mmplayer_gst_element_t *sinkbin = NULL;
6411 main_element_id_e selectorId = MMPLAYER_M_NUM;
6412 main_element_id_e sinkId = MMPLAYER_M_NUM;
6413 GstPad *srcpad = NULL;
6414 GstPad *sinkpad = NULL;
6415 gboolean send_notice = FALSE;
6418 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6420 LOGD("type %d", type);
6423 case MM_PLAYER_TRACK_TYPE_AUDIO:
6424 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6425 sinkId = MMPLAYER_A_BIN;
6426 sinkbin = player->pipeline->audiobin;
6428 case MM_PLAYER_TRACK_TYPE_VIDEO:
6429 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6430 sinkId = MMPLAYER_V_BIN;
6431 sinkbin = player->pipeline->videobin;
6434 case MM_PLAYER_TRACK_TYPE_TEXT:
6435 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6436 sinkId = MMPLAYER_T_BIN;
6437 sinkbin = player->pipeline->textbin;
6440 LOGE("requested type is not supportable");
6445 if (player->pipeline->mainbin[selectorId].gst) {
6448 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6450 if (selector->event_probe_id != 0)
6451 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6452 selector->event_probe_id = 0;
6454 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6455 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6457 if (srcpad && sinkpad) {
6458 /* after getting drained signal there is no data flows, so no need to do pad_block */
6459 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6460 gst_pad_unlink(srcpad, sinkpad);
6462 /* send custom event to sink pad to handle it at video sink */
6464 LOGD("send custom event to sinkpad");
6465 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6466 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6467 gst_pad_send_event(sinkpad, event);
6471 gst_object_unref(sinkpad);
6474 gst_object_unref(srcpad);
6477 LOGD("selector release");
6479 /* release and unref requests pad from the selector */
6480 for (n = 0; n < selector->channels->len; n++) {
6481 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6482 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6484 g_ptr_array_set_size(selector->channels, 0);
6486 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6487 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6489 player->pipeline->mainbin[selectorId].gst = NULL;
6497 __mmplayer_deactivate_old_path(mmplayer_t *player)
6500 MMPLAYER_RETURN_IF_FAIL(player);
6502 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6503 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6504 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6505 LOGE("deactivate selector error");
6509 _mmplayer_track_destroy(player);
6510 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6512 if (player->streamer) {
6513 _mm_player_streaming_initialize(player->streamer, FALSE);
6514 _mm_player_streaming_destroy(player->streamer);
6515 player->streamer = NULL;
6518 MMPLAYER_PLAYBACK_LOCK(player);
6519 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6526 if (!player->msg_posted) {
6527 MMMessageParamType msg = {0,};
6530 msg.code = MM_ERROR_PLAYER_INTERNAL;
6531 LOGE("gapless_uri_play> deactivate error");
6533 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6534 player->msg_posted = TRUE;
6540 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6542 int result = MM_ERROR_NONE;
6543 mmplayer_t *player = (mmplayer_t *)hplayer;
6546 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6547 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6549 if (mm_player_set_attribute(hplayer, NULL,
6550 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6551 LOGE("failed to set attribute");
6552 result = MM_ERROR_PLAYER_INTERNAL;
6554 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6555 LOGE("failed to add the original uri in the uri list.");
6563 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6565 mmplayer_t *player = (mmplayer_t *)hplayer;
6566 guint num_of_list = 0;
6570 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6571 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6573 if (player->pipeline && player->pipeline->textbin) {
6574 LOGE("subtitle path is enabled.");
6575 return MM_ERROR_PLAYER_INVALID_STATE;
6578 num_of_list = g_list_length(player->uri_info.uri_list);
6580 if (is_first_path) {
6581 if (num_of_list == 0) {
6582 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6583 SECURE_LOGD("add original path : %s", uri);
6585 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6586 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6588 SECURE_LOGD("change original path : %s", uri);
6591 MMHandleType attrs = 0;
6592 attrs = MMPLAYER_GET_ATTRS(player);
6594 if (num_of_list == 0) {
6595 char *original_uri = NULL;
6598 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6600 if (!original_uri) {
6601 LOGE("there is no original uri.");
6602 return MM_ERROR_PLAYER_INVALID_STATE;
6605 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6606 player->uri_info.uri_idx = 0;
6608 SECURE_LOGD("add original path at first : %s", original_uri);
6612 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6613 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6617 return MM_ERROR_NONE;
6621 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6623 mmplayer_t *player = (mmplayer_t *)hplayer;
6624 char *next_uri = NULL;
6625 guint num_of_list = 0;
6628 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6630 num_of_list = g_list_length(player->uri_info.uri_list);
6632 if (num_of_list > 0) {
6633 gint uri_idx = player->uri_info.uri_idx;
6635 if (uri_idx < num_of_list-1)
6640 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6641 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6643 *uri = g_strdup(next_uri);
6647 return MM_ERROR_NONE;
6651 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6652 GstCaps *caps, gpointer data)
6654 mmplayer_t *player = (mmplayer_t *)data;
6655 const gchar *klass = NULL;
6656 const gchar *mime = NULL;
6657 gchar *caps_str = NULL;
6659 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6660 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6661 caps_str = gst_caps_to_string(caps);
6663 LOGW("unknown type of caps : %s from %s",
6664 caps_str, GST_ELEMENT_NAME(elem));
6666 MMPLAYER_FREEIF(caps_str);
6668 /* There is no available codec. */
6669 __mmplayer_check_not_supported_codec(player, klass, mime);
6673 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6674 GstCaps *caps, gpointer data)
6676 mmplayer_t *player = (mmplayer_t *)data;
6677 const char *mime = NULL;
6678 gboolean ret = TRUE;
6680 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6681 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6683 if (g_str_has_prefix(mime, "audio")) {
6684 GstStructure *caps_structure = NULL;
6685 gint samplerate = 0;
6687 gchar *caps_str = NULL;
6689 caps_structure = gst_caps_get_structure(caps, 0);
6690 gst_structure_get_int(caps_structure, "rate", &samplerate);
6691 gst_structure_get_int(caps_structure, "channels", &channels);
6693 if ((channels > 0 && samplerate == 0)) {
6694 LOGD("exclude audio...");
6698 caps_str = gst_caps_to_string(caps);
6699 /* set it directly because not sent by TAG */
6700 if (g_strrstr(caps_str, "mobile-xmf"))
6701 mm_player_set_attribute((MMHandleType)player, NULL,
6702 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6704 MMPLAYER_FREEIF(caps_str);
6705 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6706 MMMessageParamType msg_param;
6707 memset(&msg_param, 0, sizeof(MMMessageParamType));
6708 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6709 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6710 LOGD("video file is not supported on this device");
6712 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6713 LOGD("already video linked");
6716 LOGD("found new stream");
6723 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6725 gboolean ret = TRUE;
6726 GDBusConnection *conn = NULL;
6728 GVariant *result = NULL;
6729 const gchar *dbus_device_type = NULL;
6730 const gchar *dbus_ret = NULL;
6733 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6735 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6741 result = g_dbus_connection_call_sync(conn,
6742 "org.pulseaudio.Server",
6743 "/org/pulseaudio/StreamManager",
6744 "org.pulseaudio.StreamManager",
6745 "GetCurrentMediaRoutingPath",
6746 g_variant_new("(s)", "out"),
6747 G_VARIANT_TYPE("(ss)"),
6748 G_DBUS_CALL_FLAGS_NONE,
6752 if (!result || err) {
6753 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6759 /* device type is listed in stream-map.json at mmfw-sysconf */
6760 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6762 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6763 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6768 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6769 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6770 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6771 LOGD("audio offload is supportable");
6777 LOGD("audio offload is not supportable");
6781 g_variant_unref(result);
6782 g_object_unref(conn);
6787 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6789 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6790 gint64 position = 0;
6792 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6793 player->pipeline && player->pipeline->mainbin);
6795 MMPLAYER_CMD_LOCK(player);
6796 current_state = MMPLAYER_CURRENT_STATE(player);
6798 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6799 LOGW("getting current position failed in paused");
6801 _mmplayer_unrealize((MMHandleType)player);
6802 _mmplayer_realize((MMHandleType)player);
6804 _mmplayer_set_position((MMHandleType)player, position);
6806 /* async not to be blocked in streaming case */
6807 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6809 _mmplayer_pause((MMHandleType)player);
6811 if (current_state == MM_PLAYER_STATE_PLAYING)
6812 _mmplayer_start((MMHandleType)player);
6813 MMPLAYER_CMD_UNLOCK(player);
6815 LOGD("rebuilding audio pipeline is completed.");
6818 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6820 mmplayer_t *player = (mmplayer_t *)user_data;
6821 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6822 gboolean is_supportable = FALSE;
6824 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6825 LOGW("failed to get device type");
6827 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6829 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6830 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6831 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6832 LOGD("ignore this dev connected info");
6836 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6837 if (player->build_audio_offload == is_supportable) {
6838 LOGD("keep current pipeline without re-building");
6842 /* rebuild pipeline */
6843 LOGD("re-build pipeline - offload: %d", is_supportable);
6844 player->build_audio_offload = FALSE;
6845 __mmplayer_rebuild_audio_pipeline(player);
6851 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6853 unsigned int id = 0;
6855 if (player->audio_device_cb_id != 0) {
6856 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6860 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6861 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6862 LOGD("added device connected cb (%u)", id);
6863 player->audio_device_cb_id = id;
6865 LOGW("failed to add device connected cb");
6872 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6874 mmplayer_t *player = (mmplayer_t *)hplayer;
6877 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6878 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6880 *activated = player->build_audio_offload;
6882 LOGD("offload activated : %d", (int)*activated);
6885 return MM_ERROR_NONE;
6889 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6892 this function need to be updated according to the supported media format
6893 @see player->ini.audio_offload_media_format */
6895 if (__mmplayer_is_only_mp3_type(player->type)) {
6896 LOGD("offload supportable media format type");
6904 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6906 gboolean ret = FALSE;
6907 GstElementFactory *factory = NULL;
6910 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6912 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6913 if (!__mmplayer_is_offload_supported_type(player))
6916 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6917 LOGD("there is no audio offload sink");
6921 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6922 LOGW("there is no audio device type to support offload");
6926 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6928 LOGW("there is no installed audio offload sink element");
6931 gst_object_unref(factory);
6933 if (__mmplayer_acquire_hw_resource(player,
6934 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6935 LOGE("failed to acquire audio offload decoder resource");
6939 if (!__mmplayer_add_audio_device_connected_cb(player))
6942 if (!__mmplayer_is_audio_offload_device_type(player))
6945 LOGD("audio offload can be built");
6950 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6956 static GstAutoplugSelectResult
6957 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6959 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6961 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6962 int audio_offload = 0;
6964 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6965 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6967 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6968 LOGD("expose audio path to build offload output path");
6969 player->build_audio_offload = TRUE;
6970 /* update codec info */
6971 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6972 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6973 player->audiodec_linked = 1;
6975 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6979 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6981 LOGD("audio codec type: %d", codec_type);
6982 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6983 /* sw codec will be skipped */
6984 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6985 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6986 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6987 ret = GST_AUTOPLUG_SELECT_SKIP;
6991 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6992 /* hw codec will be skipped */
6993 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6994 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6995 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6996 ret = GST_AUTOPLUG_SELECT_SKIP;
7001 /* set stream information */
7002 if (!player->audiodec_linked)
7003 __mmplayer_set_audio_attrs(player, caps);
7005 /* update codec info */
7006 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7007 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7008 player->audiodec_linked = 1;
7010 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7012 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7014 LOGD("video codec type: %d", codec_type);
7015 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7016 /* sw codec is skipped */
7017 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7018 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7019 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7020 ret = GST_AUTOPLUG_SELECT_SKIP;
7024 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7025 /* hw codec is skipped */
7026 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7027 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7028 ret = GST_AUTOPLUG_SELECT_SKIP;
7033 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7034 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7036 /* mark video decoder for acquire */
7037 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7038 LOGW("video decoder resource is already acquired, skip it.");
7039 ret = GST_AUTOPLUG_SELECT_SKIP;
7043 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7044 LOGE("failed to acquire video decoder resource");
7045 ret = GST_AUTOPLUG_SELECT_SKIP;
7048 player->interrupted_by_resource = FALSE;
7051 /* update codec info */
7052 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7053 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7054 player->videodec_linked = 1;
7062 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7063 GstCaps *caps, GstElementFactory *factory, gpointer data)
7065 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7066 mmplayer_t *player = (mmplayer_t *)data;
7068 gchar *factory_name = NULL;
7069 gchar *caps_str = NULL;
7070 const gchar *klass = NULL;
7073 factory_name = GST_OBJECT_NAME(factory);
7074 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7075 caps_str = gst_caps_to_string(caps);
7077 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7079 /* store type string */
7080 if (player->type == NULL) {
7081 player->type = gst_caps_to_string(caps);
7082 __mmplayer_update_content_type_info(player);
7085 /* filtering exclude keyword */
7086 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7087 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7088 LOGW("skipping [%s] by exculde keyword [%s]",
7089 factory_name, player->ini.exclude_element_keyword[idx]);
7091 result = GST_AUTOPLUG_SELECT_SKIP;
7096 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7097 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7098 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7099 factory_name, player->ini.unsupported_codec_keyword[idx]);
7100 result = GST_AUTOPLUG_SELECT_SKIP;
7105 /* exclude webm format */
7106 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7107 * because webm format is not supportable.
7108 * If webm is disabled in "autoplug-continue", there is no state change
7109 * failure or error because the decodebin will expose the pad directly.
7110 * It make MSL invoke _prepare_async_callback.
7111 * So, we need to disable webm format in "autoplug-select" */
7112 if (caps_str && strstr(caps_str, "webm")) {
7113 LOGW("webm is not supported");
7114 result = GST_AUTOPLUG_SELECT_SKIP;
7118 /* check factory class for filtering */
7119 /* NOTE : msl don't need to use image plugins.
7120 * So, those plugins should be skipped for error handling.
7122 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7123 LOGD("skipping [%s] by not required", factory_name);
7124 result = GST_AUTOPLUG_SELECT_SKIP;
7128 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7129 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7130 // TO CHECK : subtitle if needed, add subparse exception.
7131 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7132 result = GST_AUTOPLUG_SELECT_SKIP;
7136 if (g_strrstr(factory_name, "mpegpsdemux")) {
7137 LOGD("skipping PS container - not support");
7138 result = GST_AUTOPLUG_SELECT_SKIP;
7142 if (g_strrstr(factory_name, "mssdemux"))
7143 player->smooth_streaming = TRUE;
7145 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7146 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7149 GstStructure *str = NULL;
7150 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7152 /* don't make video because of not required */
7153 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7154 (!player->set_mode.video_export)) {
7155 LOGD("no need video decoding, expose pad");
7156 result = GST_AUTOPLUG_SELECT_EXPOSE;
7160 /* get w/h for omx state-tune */
7161 /* FIXME: deprecated? */
7162 str = gst_caps_get_structure(caps, 0);
7163 gst_structure_get_int(str, "width", &width);
7166 if (player->v_stream_caps) {
7167 gst_caps_unref(player->v_stream_caps);
7168 player->v_stream_caps = NULL;
7171 player->v_stream_caps = gst_caps_copy(caps);
7172 LOGD("take caps for video state tune");
7173 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7177 if (g_strrstr(klass, "Codec/Decoder")) {
7178 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7179 if (result != GST_AUTOPLUG_SELECT_TRY) {
7180 LOGW("skip add decoder");
7186 MMPLAYER_FREEIF(caps_str);
7192 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7195 //mmplayer_t *player = (mmplayer_t *)data;
7196 GstCaps *caps = NULL;
7198 LOGD("[Decodebin2] pad-removed signal");
7200 caps = gst_pad_query_caps(new_pad, NULL);
7202 LOGW("query caps is NULL");
7206 gchar *caps_str = NULL;
7207 caps_str = gst_caps_to_string(caps);
7209 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7211 MMPLAYER_FREEIF(caps_str);
7212 gst_caps_unref(caps);
7216 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7218 mmplayer_t *player = (mmplayer_t *)data;
7219 GstIterator *iter = NULL;
7220 GValue item = { 0, };
7222 gboolean done = FALSE;
7223 gboolean is_all_drained = TRUE;
7226 MMPLAYER_RETURN_IF_FAIL(player);
7228 LOGD("__mmplayer_gst_decode_drained");
7230 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7231 LOGW("Fail to get cmd lock");
7235 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7236 !__mmplayer_verify_gapless_play_path(player)) {
7237 LOGD("decoding is finished.");
7238 __mmplayer_reset_gapless_state(player);
7239 MMPLAYER_CMD_UNLOCK(player);
7243 player->gapless.reconfigure = TRUE;
7245 /* check decodebin src pads whether they received EOS or not */
7246 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7249 switch (gst_iterator_next(iter, &item)) {
7250 case GST_ITERATOR_OK:
7251 pad = g_value_get_object(&item);
7252 if (pad && !GST_PAD_IS_EOS(pad)) {
7253 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7254 is_all_drained = FALSE;
7257 g_value_reset(&item);
7259 case GST_ITERATOR_RESYNC:
7260 gst_iterator_resync(iter);
7262 case GST_ITERATOR_ERROR:
7263 case GST_ITERATOR_DONE:
7268 g_value_unset(&item);
7269 gst_iterator_free(iter);
7271 if (!is_all_drained) {
7272 LOGD("Wait util the all pads get EOS.");
7273 MMPLAYER_CMD_UNLOCK(player);
7278 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7279 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7281 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7282 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7283 __mmplayer_deactivate_old_path(player);
7284 MMPLAYER_CMD_UNLOCK(player);
7290 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7292 mmplayer_t *player = (mmplayer_t *)data;
7293 const gchar *klass = NULL;
7294 gchar *factory_name = NULL;
7296 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7297 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7299 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7301 if (__mmplayer_add_dump_buffer_probe(player, element))
7302 LOGD("add buffer probe");
7304 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7305 gchar *selected = NULL;
7306 selected = g_strdup(GST_ELEMENT_NAME(element));
7307 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7310 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7311 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7312 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7314 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7315 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7317 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7318 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7319 "max-video-width", player->adaptive_info.limit.width,
7320 "max-video-height", player->adaptive_info.limit.height, NULL);
7322 } else if (g_strrstr(klass, "Demuxer")) {
7324 LOGD("plugged element is demuxer. take it");
7326 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7327 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7330 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7331 int surface_type = 0;
7333 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7336 // to support trust-zone only
7337 if (g_strrstr(factory_name, "asfdemux")) {
7338 LOGD("set file-location %s", player->profile.uri);
7339 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7340 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7341 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7342 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7343 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7344 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7345 (__mmplayer_is_only_mp3_type(player->type))) {
7346 LOGD("[mpegaudioparse] set streaming pull mode.");
7347 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7349 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7350 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7353 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7354 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7355 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7357 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7358 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7360 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7361 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7362 (MMPLAYER_IS_DASH_STREAMING(player))) {
7363 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7364 _mm_player_streaming_set_multiqueue(player->streamer, element);
7365 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7374 __mmplayer_release_misc(mmplayer_t *player)
7377 bool cur_mode = player->set_mode.rich_audio;
7380 MMPLAYER_RETURN_IF_FAIL(player);
7382 player->video_decoded_cb = NULL;
7383 player->video_decoded_cb_user_param = NULL;
7384 player->video_stream_prerolled = false;
7386 player->audio_decoded_cb = NULL;
7387 player->audio_decoded_cb_user_param = NULL;
7388 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7390 player->audio_stream_changed_cb = NULL;
7391 player->audio_stream_changed_cb_user_param = NULL;
7393 player->sent_bos = FALSE;
7394 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7396 player->seek_state = MMPLAYER_SEEK_NONE;
7398 player->total_bitrate = 0;
7399 player->total_maximum_bitrate = 0;
7401 player->not_found_demuxer = 0;
7403 player->last_position = 0;
7404 player->duration = 0;
7405 player->http_content_size = 0;
7406 player->not_supported_codec = MISSING_PLUGIN_NONE;
7407 player->can_support_codec = FOUND_PLUGIN_NONE;
7408 player->pending_seek.is_pending = false;
7409 player->pending_seek.pos = 0;
7410 player->msg_posted = FALSE;
7411 player->has_many_types = FALSE;
7412 player->is_subtitle_force_drop = FALSE;
7413 player->play_subtitle = FALSE;
7414 player->adjust_subtitle_pos = 0;
7415 player->has_closed_caption = FALSE;
7416 player->set_mode.video_export = false;
7417 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7418 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7420 player->set_mode.rich_audio = cur_mode;
7422 if (player->audio_device_cb_id > 0 &&
7423 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7424 LOGW("failed to remove audio device_connected_callback");
7425 player->audio_device_cb_id = 0;
7427 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7428 player->bitrate[i] = 0;
7429 player->maximum_bitrate[i] = 0;
7432 /* free memory related to audio effect */
7433 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7435 if (player->adaptive_info.var_list) {
7436 g_list_free_full(player->adaptive_info.var_list, g_free);
7437 player->adaptive_info.var_list = NULL;
7440 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7441 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7442 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7444 /* Reset video360 settings to their defaults in case if the pipeline is to be
7447 player->video360_metadata.is_spherical = -1;
7448 player->is_openal_plugin_used = FALSE;
7450 player->is_content_spherical = FALSE;
7451 player->is_video360_enabled = TRUE;
7452 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7453 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7454 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7455 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7456 player->video360_zoom = 1.0f;
7457 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7458 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7460 player->sound.rg_enable = false;
7462 __mmplayer_initialize_video_roi(player);
7467 __mmplayer_release_misc_post(mmplayer_t *player)
7469 char *original_uri = NULL;
7472 /* player->pipeline is already released before. */
7474 MMPLAYER_RETURN_IF_FAIL(player);
7476 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7478 /* clean found audio decoders */
7479 if (player->audio_decoders) {
7480 GList *a_dec = player->audio_decoders;
7481 for (; a_dec; a_dec = g_list_next(a_dec)) {
7482 gchar *name = a_dec->data;
7483 MMPLAYER_FREEIF(name);
7485 g_list_free(player->audio_decoders);
7486 player->audio_decoders = NULL;
7489 /* clean the uri list except original uri */
7490 if (player->uri_info.uri_list) {
7491 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7494 LOGW("failed to get original uri info");
7496 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7497 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7499 GList *uri_list = player->uri_info.uri_list;
7500 for (; uri_list; uri_list = g_list_next(uri_list)) {
7501 gchar *uri = uri_list->data;
7502 MMPLAYER_FREEIF(uri);
7504 g_list_free(player->uri_info.uri_list);
7505 player->uri_info.uri_list = NULL;
7508 /* clear the audio stream buffer list */
7509 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7511 /* clear the video stream bo list */
7512 __mmplayer_video_stream_destroy_bo_list(player);
7513 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7515 if (player->profile.input_mem.buf) {
7516 free(player->profile.input_mem.buf);
7517 player->profile.input_mem.buf = NULL;
7519 player->profile.input_mem.len = 0;
7520 player->profile.input_mem.offset = 0;
7522 player->uri_info.uri_idx = 0;
7527 __mmplayer_check_subtitle(mmplayer_t *player)
7529 MMHandleType attrs = 0;
7530 char *subtitle_uri = NULL;
7534 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7536 /* get subtitle attribute */
7537 attrs = MMPLAYER_GET_ATTRS(player);
7541 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7542 if (!subtitle_uri || !strlen(subtitle_uri))
7545 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7546 player->is_external_subtitle_present = TRUE;
7554 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7556 MMPLAYER_RETURN_IF_FAIL(player);
7558 if (player->eos_timer) {
7559 LOGD("cancel eos timer");
7560 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7561 player->eos_timer = 0;
7568 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7572 MMPLAYER_RETURN_IF_FAIL(player);
7573 MMPLAYER_RETURN_IF_FAIL(sink);
7575 player->sink_elements = g_list_append(player->sink_elements, sink);
7581 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7585 MMPLAYER_RETURN_IF_FAIL(player);
7586 MMPLAYER_RETURN_IF_FAIL(sink);
7588 player->sink_elements = g_list_remove(player->sink_elements, sink);
7594 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7595 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7597 mmplayer_signal_item_t *item = NULL;
7600 MMPLAYER_RETURN_IF_FAIL(player);
7602 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7603 LOGE("invalid signal type [%d]", type);
7607 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7609 LOGE("cannot connect signal [%s]", signal);
7614 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7615 player->signals[type] = g_list_append(player->signals[type], item);
7621 /* NOTE : be careful with calling this api. please refer to below glib comment
7622 * glib comment : Note that there is a bug in GObject that makes this function much
7623 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7624 * will no longer be called, but, the signal handler is not currently disconnected.
7625 * If the instance is itself being freed at the same time than this doesn't matter,
7626 * since the signal will automatically be removed, but if instance persists,
7627 * then the signal handler will leak. You should not remove the signal yourself
7628 * because in a future versions of GObject, the handler will automatically be
7631 * It's possible to work around this problem in a way that will continue to work
7632 * with future versions of GObject by checking that the signal handler is still
7633 * connected before disconnected it:
7635 * if (g_signal_handler_is_connected(instance, id))
7636 * g_signal_handler_disconnect(instance, id);
7639 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7641 GList *sig_list = NULL;
7642 mmplayer_signal_item_t *item = NULL;
7646 MMPLAYER_RETURN_IF_FAIL(player);
7648 LOGD("release signals type : %d", type);
7650 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7651 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7652 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7653 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7654 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7655 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7659 sig_list = player->signals[type];
7661 for (; sig_list; sig_list = sig_list->next) {
7662 item = sig_list->data;
7664 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7665 if (g_signal_handler_is_connected(item->obj, item->sig))
7666 g_signal_handler_disconnect(item->obj, item->sig);
7669 MMPLAYER_FREEIF(item);
7672 g_list_free(player->signals[type]);
7673 player->signals[type] = NULL;
7681 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, unsigned int wl_surface_id)
7683 mmplayer_t *player = 0;
7684 int prev_display_surface_type = 0;
7688 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7690 player = MM_PLAYER_CAST(handle);
7692 /* check video sinkbin is created */
7693 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7694 LOGW("Videosink is already created");
7695 return MM_ERROR_NONE;
7698 LOGD("videosink element is not yet ready");
7700 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7701 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7703 return MM_ERROR_INVALID_ARGUMENT;
7706 /* load previous attributes */
7707 if (player->attrs) {
7708 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7709 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7710 if (prev_display_surface_type == surface_type) {
7711 LOGD("incoming display surface type is same as previous one, do nothing..");
7713 return MM_ERROR_NONE;
7716 LOGE("failed to load attributes");
7718 return MM_ERROR_PLAYER_INTERNAL;
7721 /* videobin is not created yet, so we just set attributes related to display surface */
7722 LOGD("store display attribute for given surface type(%d)", surface_type);
7723 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7724 "display_overlay", (int)wl_surface_id, NULL);
7727 return MM_ERROR_NONE;
7730 /* Note : if silent is true, then subtitle would not be displayed. :*/
7732 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7734 mmplayer_t *player = (mmplayer_t *)hplayer;
7738 /* check player handle */
7739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7741 player->set_mode.subtitle_off = silent;
7743 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7747 return MM_ERROR_NONE;
7751 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7753 mmplayer_gst_element_t *mainbin = NULL;
7754 mmplayer_gst_element_t *textbin = NULL;
7755 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7756 GstState current_state = GST_STATE_VOID_PENDING;
7757 GstState element_state = GST_STATE_VOID_PENDING;
7758 GstState element_pending_state = GST_STATE_VOID_PENDING;
7760 GstEvent *event = NULL;
7761 int result = MM_ERROR_NONE;
7763 GstClock *curr_clock = NULL;
7764 GstClockTime base_time, start_time, curr_time;
7769 /* check player handle */
7770 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7772 player->pipeline->mainbin &&
7773 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7775 mainbin = player->pipeline->mainbin;
7776 textbin = player->pipeline->textbin;
7778 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7780 // sync clock with current pipeline
7781 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7782 curr_time = gst_clock_get_time(curr_clock);
7784 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7785 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7787 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7788 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7790 if (current_state > GST_STATE_READY) {
7791 // sync state with current pipeline
7792 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7793 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7794 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7796 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7797 if (GST_STATE_CHANGE_FAILURE == ret) {
7798 LOGE("fail to state change.");
7799 result = MM_ERROR_PLAYER_INTERNAL;
7803 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7804 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7807 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7808 gst_object_unref(curr_clock);
7811 // seek to current position
7812 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7813 result = MM_ERROR_PLAYER_INVALID_STATE;
7814 LOGE("gst_element_query_position failed, invalid state");
7818 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7819 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);
7821 _mmplayer_gst_send_event_to_sink(player, event);
7823 result = MM_ERROR_PLAYER_INTERNAL;
7824 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7828 /* sync state with current pipeline */
7829 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7830 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7831 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7833 return MM_ERROR_NONE;
7836 /* release text pipeline resource */
7837 player->textsink_linked = 0;
7839 /* release signal */
7840 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7842 /* release textbin with it's childs */
7843 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7844 MMPLAYER_FREEIF(player->pipeline->textbin);
7845 player->pipeline->textbin = NULL;
7847 /* release subtitle elem */
7848 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7849 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7855 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7857 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7858 GstState current_state = GST_STATE_VOID_PENDING;
7860 MMHandleType attrs = 0;
7861 mmplayer_gst_element_t *mainbin = NULL;
7862 mmplayer_gst_element_t *textbin = NULL;
7864 gchar *subtitle_uri = NULL;
7865 int result = MM_ERROR_NONE;
7866 const gchar *charset = NULL;
7870 /* check player handle */
7871 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7873 player->pipeline->mainbin &&
7874 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7875 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7877 mainbin = player->pipeline->mainbin;
7878 textbin = player->pipeline->textbin;
7880 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7881 if (current_state < GST_STATE_READY) {
7882 result = MM_ERROR_PLAYER_INVALID_STATE;
7883 LOGE("Pipeline is not in proper state");
7887 attrs = MMPLAYER_GET_ATTRS(player);
7889 LOGE("cannot get content attribute");
7890 result = MM_ERROR_PLAYER_INTERNAL;
7894 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7895 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7896 LOGE("subtitle uri is not proper filepath");
7897 result = MM_ERROR_PLAYER_INVALID_URI;
7901 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7902 LOGE("failed to get storage info of subtitle path");
7903 result = MM_ERROR_PLAYER_INVALID_URI;
7907 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7908 SECURE_LOGD("new subtitle file path is [%s]", filepath);
7910 if (!strcmp(filepath, subtitle_uri)) {
7911 LOGD("subtitle path is not changed");
7914 if (mm_player_set_attribute((MMHandleType)player, NULL,
7915 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7916 LOGE("failed to set attribute");
7921 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7922 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7923 player->subtitle_language_list = NULL;
7924 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7926 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7927 if (ret != GST_STATE_CHANGE_SUCCESS) {
7928 LOGE("failed to change state of textbin to READY");
7929 result = MM_ERROR_PLAYER_INTERNAL;
7933 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7934 if (ret != GST_STATE_CHANGE_SUCCESS) {
7935 LOGE("failed to change state of subparse to READY");
7936 result = MM_ERROR_PLAYER_INTERNAL;
7940 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7941 if (ret != GST_STATE_CHANGE_SUCCESS) {
7942 LOGE("failed to change state of filesrc to READY");
7943 result = MM_ERROR_PLAYER_INTERNAL;
7947 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7949 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7951 charset = _mmplayer_get_charset(filepath);
7953 LOGD("detected charset is %s", charset);
7954 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7957 result = _mmplayer_sync_subtitle_pipeline(player);
7964 /* API to switch between external subtitles */
7966 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7968 int result = MM_ERROR_NONE;
7969 mmplayer_t *player = (mmplayer_t *)hplayer;
7974 /* check player handle */
7975 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7977 /* filepath can be null in idle state */
7979 /* check file path */
7980 if ((path = strstr(filepath, "file://")))
7981 result = _mmplayer_exist_file_path(path + 7);
7983 result = _mmplayer_exist_file_path(filepath);
7985 if (result != MM_ERROR_NONE) {
7986 LOGE("invalid subtitle path 0x%X", result);
7987 return result; /* file not found or permission denied */
7991 if (!player->pipeline) {
7993 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
7994 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
7995 LOGE("failed to set attribute");
7996 return MM_ERROR_PLAYER_INTERNAL;
7999 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8000 /* check filepath */
8001 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8003 if (!__mmplayer_check_subtitle(player)) {
8004 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8005 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8006 LOGE("failed to set attribute");
8007 return MM_ERROR_PLAYER_INTERNAL;
8010 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8011 LOGE("fail to create text pipeline");
8012 return MM_ERROR_PLAYER_INTERNAL;
8015 result = _mmplayer_sync_subtitle_pipeline(player);
8017 result = __mmplayer_change_external_subtitle_language(player, filepath);
8020 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8021 player->is_external_subtitle_added_now = TRUE;
8023 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8024 if (!player->subtitle_language_list) {
8025 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8026 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8027 LOGW("subtitle language list is not updated yet");
8029 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8037 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8039 int result = MM_ERROR_NONE;
8040 gchar *change_pad_name = NULL;
8041 GstPad *sinkpad = NULL;
8042 mmplayer_gst_element_t *mainbin = NULL;
8043 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8044 GstCaps *caps = NULL;
8045 gint total_track_num = 0;
8049 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8050 MM_ERROR_PLAYER_NOT_INITIALIZED);
8052 LOGD("Change Track(%d) to %d", type, index);
8054 mainbin = player->pipeline->mainbin;
8056 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8057 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8058 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8059 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8061 /* Changing Video Track is not supported. */
8062 LOGE("Track Type Error");
8066 if (mainbin[elem_idx].gst == NULL) {
8067 result = MM_ERROR_PLAYER_NO_OP;
8068 LOGD("Req track doesn't exist");
8072 total_track_num = player->selector[type].total_track_num;
8073 if (total_track_num <= 0) {
8074 result = MM_ERROR_PLAYER_NO_OP;
8075 LOGD("Language list is not available");
8079 if ((index < 0) || (index >= total_track_num)) {
8080 result = MM_ERROR_INVALID_ARGUMENT;
8081 LOGD("Not a proper index : %d", index);
8085 /*To get the new pad from the selector*/
8086 change_pad_name = g_strdup_printf("sink_%u", index);
8087 if (change_pad_name == NULL) {
8088 result = MM_ERROR_PLAYER_INTERNAL;
8089 LOGD("Pad does not exists");
8093 LOGD("new active pad name: %s", change_pad_name);
8095 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8096 if (sinkpad == NULL) {
8097 LOGD("sinkpad is NULL");
8098 result = MM_ERROR_PLAYER_INTERNAL;
8102 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8103 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8105 caps = gst_pad_get_current_caps(sinkpad);
8106 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8109 gst_object_unref(sinkpad);
8111 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8112 __mmplayer_set_audio_attrs(player, caps);
8115 MMPLAYER_FREEIF(change_pad_name);
8120 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8122 int result = MM_ERROR_NONE;
8123 mmplayer_t *player = NULL;
8124 mmplayer_gst_element_t *mainbin = NULL;
8126 gint current_active_index = 0;
8128 GstState current_state = GST_STATE_VOID_PENDING;
8129 GstEvent *event = NULL;
8134 player = (mmplayer_t *)hplayer;
8135 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8137 if (!player->pipeline) {
8138 LOGE("Track %d pre setting -> %d", type, index);
8140 player->selector[type].active_pad_index = index;
8144 mainbin = player->pipeline->mainbin;
8146 current_active_index = player->selector[type].active_pad_index;
8148 /*If index is same as running index no need to change the pad*/
8149 if (current_active_index == index)
8152 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8153 result = MM_ERROR_PLAYER_INVALID_STATE;
8157 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8158 if (current_state < GST_STATE_PAUSED) {
8159 result = MM_ERROR_PLAYER_INVALID_STATE;
8160 LOGW("Pipeline not in porper state");
8164 result = __mmplayer_change_selector_pad(player, type, index);
8165 if (result != MM_ERROR_NONE) {
8166 LOGE("change selector pad error");
8170 player->selector[type].active_pad_index = index;
8172 if (current_state == GST_STATE_PLAYING) {
8173 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8174 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8175 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8177 _mmplayer_gst_send_event_to_sink(player, event);
8179 result = MM_ERROR_PLAYER_INTERNAL;
8189 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8191 mmplayer_t *player = (mmplayer_t *)hplayer;
8195 /* check player handle */
8196 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8198 *silent = player->set_mode.subtitle_off;
8200 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8204 return MM_ERROR_NONE;
8208 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8210 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8211 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8213 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8214 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8218 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8219 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8220 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8221 mmplayer_dump_t *dump_s;
8222 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8223 if (dump_s == NULL) {
8224 LOGE("malloc fail");
8228 dump_s->dump_element_file = NULL;
8229 dump_s->dump_pad = NULL;
8230 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8232 if (dump_s->dump_pad) {
8233 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8234 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]);
8235 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8236 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);
8237 /* add list for removed buffer probe and close FILE */
8238 player->dump_list = g_list_append(player->dump_list, dump_s);
8239 LOGD("%s sink pad added buffer probe for dump", factory_name);
8242 MMPLAYER_FREEIF(dump_s);
8243 LOGE("failed to get %s sink pad added", factory_name);
8250 static GstPadProbeReturn
8251 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8253 FILE *dump_data = (FILE *)u_data;
8255 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8256 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8258 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8260 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8262 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8264 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8266 gst_buffer_unmap(buffer, &probe_info);
8268 return GST_PAD_PROBE_OK;
8272 __mmplayer_release_dump_list(GList *dump_list)
8274 GList *d_list = dump_list;
8279 for (; d_list; d_list = g_list_next(d_list)) {
8280 mmplayer_dump_t *dump_s = d_list->data;
8281 if (dump_s->dump_pad) {
8282 if (dump_s->probe_handle_id)
8283 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8284 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8286 if (dump_s->dump_element_file) {
8287 fclose(dump_s->dump_element_file);
8288 dump_s->dump_element_file = NULL;
8290 MMPLAYER_FREEIF(dump_s);
8292 g_list_free(dump_list);
8297 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8299 mmplayer_t *player = (mmplayer_t *)hplayer;
8303 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8304 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8306 *exist = (bool)player->has_closed_caption;
8310 return MM_ERROR_NONE;
8314 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8319 LOGD("unref internal gst buffer %p", buffer);
8321 gst_buffer_unref((GstBuffer *)buffer);
8328 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8330 mmplayer_t *player = (mmplayer_t *)hplayer;
8334 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8335 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8337 if (MMPLAYER_IS_STREAMING(player))
8338 *timeout = (int)player->ini.live_state_change_timeout;
8340 *timeout = (int)player->ini.localplayback_state_change_timeout;
8342 LOGD("timeout = %d", *timeout);
8345 return MM_ERROR_NONE;
8349 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8353 MMPLAYER_RETURN_IF_FAIL(player);
8355 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8357 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8358 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8359 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8360 player->storage_info[i].id = -1;
8361 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8363 if (path_type != MMPLAYER_PATH_MAX)
8372 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8374 int ret = MM_ERROR_NONE;
8375 mmplayer_t *player = (mmplayer_t *)hplayer;
8376 MMMessageParamType msg_param = {0, };
8379 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8381 LOGW("state changed storage %d:%d", id, state);
8383 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8384 return MM_ERROR_NONE;
8386 /* FIXME: text path should be handled seperately. */
8387 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8388 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8389 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8390 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8391 LOGW("external storage is removed");
8393 if (player->msg_posted == FALSE) {
8394 memset(&msg_param, 0, sizeof(MMMessageParamType));
8395 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8396 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8397 player->msg_posted = TRUE;
8400 /* unrealize the player */
8401 ret = _mmplayer_unrealize(hplayer);
8402 if (ret != MM_ERROR_NONE)
8403 LOGE("failed to unrealize");
8411 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8413 int ret = MM_ERROR_NONE;
8414 mmplayer_t *player = (mmplayer_t *)hplayer;
8415 int idx = 0, total = 0;
8416 gchar *result = NULL, *tmp = NULL;
8419 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8420 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8422 total = *num = g_list_length(player->adaptive_info.var_list);
8424 LOGW("There is no stream variant info.");
8428 result = g_strdup("");
8429 for (idx = 0 ; idx < total ; idx++) {
8430 stream_variant_t *v_data = NULL;
8431 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8434 gchar data[64] = {0};
8435 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8437 tmp = g_strconcat(result, data, NULL);
8441 LOGW("There is no variant data in %d", idx);
8446 *var_info = (char *)result;
8448 LOGD("variant info %d:%s", *num, *var_info);
8454 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8456 int ret = MM_ERROR_NONE;
8457 mmplayer_t *player = (mmplayer_t *)hplayer;
8460 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8462 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8464 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8465 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8466 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8468 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8469 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8470 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8471 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8473 /* FIXME: seek to current position for applying new variant limitation */
8482 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8484 int ret = MM_ERROR_NONE;
8485 mmplayer_t *player = (mmplayer_t *)hplayer;
8488 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8489 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8491 *bandwidth = player->adaptive_info.limit.bandwidth;
8492 *width = player->adaptive_info.limit.width;
8493 *height = player->adaptive_info.limit.height;
8495 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8502 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8504 int ret = MM_ERROR_NONE;
8505 mmplayer_t *player = (mmplayer_t *)hplayer;
8508 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8509 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8510 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8512 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8514 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8515 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8516 else /* live case */
8517 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8519 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8526 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8528 #define IDX_FIRST_SW_CODEC 0
8529 mmplayer_t *player = (mmplayer_t *)hplayer;
8530 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8533 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8535 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8536 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8537 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8539 switch (stream_type) {
8540 case MM_PLAYER_STREAM_TYPE_AUDIO:
8541 /* to support audio codec selection, codec info have to be added in ini file as below.
8542 audio codec element hw = xxxx
8543 audio codec element sw = avdec */
8544 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8545 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8546 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8547 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8548 LOGE("There is no audio codec info for codec_type %d", codec_type);
8549 return MM_ERROR_PLAYER_NO_OP;
8552 case MM_PLAYER_STREAM_TYPE_VIDEO:
8553 /* to support video codec selection, codec info have to be added in ini file as below.
8554 video codec element hw = omx
8555 video codec element sw = avdec */
8556 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8557 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8558 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8559 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8560 LOGE("There is no video codec info for codec_type %d", codec_type);
8561 return MM_ERROR_PLAYER_NO_OP;
8565 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8566 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8570 LOGD("update %s codec_type to %d", attr_name, codec_type);
8571 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8574 return MM_ERROR_NONE;
8578 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8580 mmplayer_t *player = (mmplayer_t *)hplayer;
8581 GstElement *rg_vol_element = NULL;
8585 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8587 player->sound.rg_enable = enabled;
8589 /* just hold rgvolume enable value if pipeline is not ready */
8590 if (!player->pipeline || !player->pipeline->audiobin) {
8591 LOGD("pipeline is not ready. holding rgvolume enable value");
8592 return MM_ERROR_NONE;
8595 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8597 if (!rg_vol_element) {
8598 LOGD("rgvolume element is not created");
8599 return MM_ERROR_PLAYER_INTERNAL;
8603 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8605 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8609 return MM_ERROR_NONE;
8613 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8615 mmplayer_t *player = (mmplayer_t *)hplayer;
8616 GstElement *rg_vol_element = NULL;
8617 gboolean enable = FALSE;
8621 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8622 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8624 /* just hold enable_rg value if pipeline is not ready */
8625 if (!player->pipeline || !player->pipeline->audiobin) {
8626 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8627 *enabled = player->sound.rg_enable;
8628 return MM_ERROR_NONE;
8631 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8633 if (!rg_vol_element) {
8634 LOGD("rgvolume element is not created");
8635 return MM_ERROR_PLAYER_INTERNAL;
8638 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8639 *enabled = (bool)enable;
8643 return MM_ERROR_NONE;
8647 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8649 mmplayer_t *player = (mmplayer_t *)hplayer;
8650 MMHandleType attrs = 0;
8652 int ret = MM_ERROR_NONE;
8656 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8658 attrs = MMPLAYER_GET_ATTRS(player);
8659 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8661 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8663 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8664 return MM_ERROR_PLAYER_INTERNAL;
8667 player->video_roi.scale_x = scale_x;
8668 player->video_roi.scale_y = scale_y;
8669 player->video_roi.scale_width = scale_width;
8670 player->video_roi.scale_height = scale_height;
8672 /* check video sinkbin is created */
8673 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8674 return MM_ERROR_NONE;
8676 if (!gst_video_overlay_set_video_roi_area(
8677 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8678 scale_x, scale_y, scale_width, scale_height))
8679 ret = MM_ERROR_PLAYER_INTERNAL;
8681 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8682 scale_x, scale_y, scale_width, scale_height);
8690 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8692 mmplayer_t *player = (mmplayer_t *)hplayer;
8693 int ret = MM_ERROR_NONE;
8697 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8698 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8700 *scale_x = player->video_roi.scale_x;
8701 *scale_y = player->video_roi.scale_y;
8702 *scale_width = player->video_roi.scale_width;
8703 *scale_height = player->video_roi.scale_height;
8705 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8706 *scale_x, *scale_y, *scale_width, *scale_height);
8712 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8714 mmplayer_t* player = (mmplayer_t*)hplayer;
8718 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8720 player->client_pid = pid;
8722 LOGD("client pid[%d] %p", pid, player);
8726 return MM_ERROR_NONE;
8730 __mmplayer_update_duration_value(mmplayer_t *player)
8732 gboolean ret = FALSE;
8733 gint64 dur_nsec = 0;
8734 LOGD("try to update duration");
8736 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8737 player->duration = dur_nsec;
8738 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8742 if (player->duration < 0) {
8743 LOGW("duration is Non-Initialized !!!");
8744 player->duration = 0;
8747 /* update streaming service type */
8748 player->streaming_type = _mmplayer_get_stream_service_type(player);
8750 /* check duration is OK */
8751 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8752 /* FIXIT : find another way to get duration here. */
8753 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8759 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8761 /* update audio params
8762 NOTE : We need original audio params and it can be only obtained from src pad of audio
8763 decoder. Below code only valid when we are not using 'resampler' just before
8764 'audioconverter'. */
8765 GstCaps *caps_a = NULL;
8767 gint samplerate = 0, channels = 0;
8768 GstStructure *p = NULL;
8769 GstElement *aconv = NULL;
8771 LOGD("try to update audio attrs");
8773 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8775 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8776 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8777 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8778 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8780 LOGE("there is no audio converter");
8784 pad = gst_element_get_static_pad(aconv, "sink");
8787 LOGW("failed to get pad from audio converter");
8791 caps_a = gst_pad_get_current_caps(pad);
8793 LOGW("not ready to get audio caps");
8794 gst_object_unref(pad);
8798 p = gst_caps_get_structure(caps_a, 0);
8800 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8802 gst_structure_get_int(p, "rate", &samplerate);
8803 gst_structure_get_int(p, "channels", &channels);
8805 mm_player_set_attribute((MMHandleType)player, NULL,
8806 "content_audio_samplerate", samplerate,
8807 "content_audio_channels", channels, NULL);
8809 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8811 gst_caps_unref(caps_a);
8812 gst_object_unref(pad);
8818 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8820 LOGD("try to update video attrs");
8822 GstCaps *caps_v = NULL;
8826 GstStructure *p = NULL;
8828 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8829 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8831 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8833 LOGD("no videosink sink pad");
8837 caps_v = gst_pad_get_current_caps(pad);
8838 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8839 if (!caps_v && player->v_stream_caps) {
8840 caps_v = player->v_stream_caps;
8841 gst_caps_ref(caps_v);
8845 LOGD("no negitiated caps from videosink");
8846 gst_object_unref(pad);
8850 p = gst_caps_get_structure(caps_v, 0);
8851 gst_structure_get_int(p, "width", &width);
8852 gst_structure_get_int(p, "height", &height);
8854 mm_player_set_attribute((MMHandleType)player, NULL,
8855 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
8857 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8859 SECURE_LOGD("width : %d height : %d", width, height);
8861 gst_caps_unref(caps_v);
8862 gst_object_unref(pad);
8865 mm_player_set_attribute((MMHandleType)player, NULL,
8866 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
8867 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8874 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8876 gboolean ret = FALSE;
8877 guint64 data_size = 0;
8881 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8882 if (!player->duration)
8885 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8886 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8887 if (stat(path, &sb) == 0)
8888 data_size = (guint64)sb.st_size;
8890 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8891 data_size = player->http_content_size;
8894 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8897 guint64 bitrate = 0;
8898 guint64 msec_dur = 0;
8900 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8902 bitrate = data_size * 8 * 1000 / msec_dur;
8903 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
8904 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8905 mm_player_set_attribute((MMHandleType)player, NULL,
8906 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
8909 LOGD("player duration is less than 0");
8913 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8914 if (player->total_bitrate) {
8915 mm_player_set_attribute((MMHandleType)player, NULL,
8916 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
8925 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8927 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8928 data->uri_type = uri_type;
8932 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8934 int ret = MM_ERROR_PLAYER_INVALID_URI;
8936 char *buffer = NULL;
8937 char *seperator = strchr(path, ',');
8938 char ext[100] = {0,}, size[100] = {0,};
8941 if ((buffer = strstr(path, "ext="))) {
8942 buffer += strlen("ext=");
8944 if (strlen(buffer)) {
8945 strncpy(ext, buffer, 99);
8947 if ((seperator = strchr(ext, ','))
8948 || (seperator = strchr(ext, ' '))
8949 || (seperator = strchr(ext, '\0'))) {
8950 seperator[0] = '\0';
8955 if ((buffer = strstr(path, "size="))) {
8956 buffer += strlen("size=");
8958 if (strlen(buffer) > 0) {
8959 strncpy(size, buffer, 99);
8961 if ((seperator = strchr(size, ','))
8962 || (seperator = strchr(size, ' '))
8963 || (seperator = strchr(size, '\0'))) {
8964 seperator[0] = '\0';
8967 mem_size = atoi(size);
8972 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8974 if (mem_size && param) {
8975 if (data->input_mem.buf)
8976 free(data->input_mem.buf);
8977 data->input_mem.buf = malloc(mem_size);
8979 if (data->input_mem.buf) {
8980 memcpy(data->input_mem.buf, param, mem_size);
8981 data->input_mem.len = mem_size;
8982 ret = MM_ERROR_NONE;
8984 LOGE("failed to alloc mem %d", mem_size);
8985 ret = MM_ERROR_PLAYER_INTERNAL;
8988 data->input_mem.offset = 0;
8989 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8996 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
8998 gchar *location = NULL;
9001 int ret = MM_ERROR_NONE;
9003 if ((path = strstr(uri, "file://"))) {
9004 location = g_filename_from_uri(uri, NULL, &err);
9005 if (!location || (err != NULL)) {
9006 LOGE("Invalid URI '%s' for filesrc: %s", path,
9007 (err != NULL) ? err->message : "unknown error");
9011 MMPLAYER_FREEIF(location);
9013 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9014 return MM_ERROR_PLAYER_INVALID_URI;
9016 LOGD("path from uri: %s", location);
9019 path = (location != NULL) ? (location) : ((char *)uri);
9022 ret = _mmplayer_exist_file_path(path);
9024 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9025 if (ret == MM_ERROR_NONE) {
9026 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9027 if (_mmplayer_is_sdp_file(path)) {
9028 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9029 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9031 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9033 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9034 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9036 LOGE("invalid uri, could not play..");
9037 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9040 MMPLAYER_FREEIF(location);
9045 static mmplayer_video_decoded_data_info_t *
9046 __mmplayer_create_stream_from_pad(GstPad *pad)
9048 GstCaps *caps = NULL;
9049 GstStructure *structure = NULL;
9050 unsigned int fourcc = 0;
9051 const gchar *string_format = NULL;
9052 mmplayer_video_decoded_data_info_t *stream = NULL;
9054 MMPixelFormatType format;
9057 caps = gst_pad_get_current_caps(pad);
9059 LOGE("Caps is NULL.");
9064 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9066 structure = gst_caps_get_structure(caps, 0);
9067 gst_structure_get_int(structure, "width", &width);
9068 gst_structure_get_int(structure, "height", &height);
9069 string_format = gst_structure_get_string(structure, "format");
9072 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9073 format = _mmplayer_get_pixtype(fourcc);
9074 gst_video_info_from_caps(&info, caps);
9075 gst_caps_unref(caps);
9078 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9079 LOGE("Wrong condition!!");
9083 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9085 LOGE("failed to alloc mem for video data");
9089 stream->width = width;
9090 stream->height = height;
9091 stream->format = format;
9092 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9098 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9100 unsigned int pitch = 0;
9101 unsigned int size = 0;
9103 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9106 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9107 bo = gst_tizen_memory_get_bos(mem, index);
9109 stream->bo[index] = tbm_bo_ref(bo);
9111 LOGE("failed to get bo for index %d", index);
9114 for (index = 0; index < stream->plane_num; index++) {
9115 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9116 stream->stride[index] = pitch;
9118 stream->elevation[index] = size / pitch;
9120 stream->elevation[index] = stream->height;
9125 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9127 if (stream->format == MM_PIXEL_FORMAT_I420) {
9128 int ret = TBM_SURFACE_ERROR_NONE;
9129 tbm_surface_h surface;
9130 tbm_surface_info_s info;
9132 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9134 ret = tbm_surface_get_info(surface, &info);
9135 if (ret != TBM_SURFACE_ERROR_NONE) {
9136 tbm_surface_destroy(surface);
9140 tbm_surface_destroy(surface);
9141 stream->stride[0] = info.planes[0].stride;
9142 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9143 stream->stride[1] = info.planes[1].stride;
9144 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9145 stream->stride[2] = info.planes[2].stride;
9146 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9147 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9148 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9149 stream->stride[0] = stream->width * 4;
9150 stream->elevation[0] = stream->height;
9151 stream->bo_size = stream->stride[0] * stream->height;
9153 LOGE("Not support format %d", stream->format);
9161 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9163 tbm_bo_handle thandle;
9165 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9166 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9167 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9171 unsigned char *src = NULL;
9172 unsigned char *dest = NULL;
9173 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9175 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9177 LOGE("fail to gst_memory_map");
9181 if (!mapinfo.data) {
9182 LOGE("data pointer is wrong");
9186 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9187 if (!stream->bo[0]) {
9188 LOGE("Fail to tbm_bo_alloc!!");
9192 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9194 LOGE("thandle pointer is wrong");
9198 if (stream->format == MM_PIXEL_FORMAT_I420) {
9199 src_stride[0] = GST_ROUND_UP_4(stream->width);
9200 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9201 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9202 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9205 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9206 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9208 for (i = 0; i < 3; i++) {
9209 src = mapinfo.data + src_offset[i];
9210 dest = thandle.ptr + dest_offset[i];
9215 for (j = 0; j < stream->height >> k; j++) {
9216 memcpy(dest, src, stream->width>>k);
9217 src += src_stride[i];
9218 dest += stream->stride[i];
9221 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9222 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9224 LOGE("Not support format %d", stream->format);
9228 tbm_bo_unmap(stream->bo[0]);
9229 gst_memory_unmap(mem, &mapinfo);
9235 tbm_bo_unmap(stream->bo[0]);
9238 gst_memory_unmap(mem, &mapinfo);
9244 __mmplayer_set_pause_state(mmplayer_t *player)
9246 if (player->sent_bos)
9249 /* rtsp case, get content attrs by GstMessage */
9250 if (MMPLAYER_IS_RTSP_STREAMING(player))
9253 /* it's first time to update all content attrs. */
9254 _mmplayer_update_content_attrs(player, ATTR_ALL);
9258 __mmplayer_set_playing_state(mmplayer_t *player)
9260 gchar *audio_codec = NULL;
9262 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9263 /* initialize because auto resume is done well. */
9264 player->resumed_by_rewind = FALSE;
9265 player->playback_rate = 1.0;
9268 if (player->sent_bos)
9271 /* try to get content metadata */
9273 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9274 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9275 * legacy mmfw-player api
9277 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9279 if ((player->cmd == MMPLAYER_COMMAND_START)
9280 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9281 __mmplayer_handle_missed_plugin(player);
9284 /* check audio codec field is set or not
9285 * we can get it from typefinder or codec's caps.
9287 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9289 /* The codec format can't be sent for audio only case like amr, mid etc.
9290 * Because, parser don't make related TAG.
9291 * So, if it's not set yet, fill it with found data.
9294 if (g_strrstr(player->type, "audio/midi"))
9295 audio_codec = "MIDI";
9296 else if (g_strrstr(player->type, "audio/x-amr"))
9297 audio_codec = "AMR";
9298 else if (g_strrstr(player->type, "audio/mpeg")
9299 && !g_strrstr(player->type, "mpegversion=(int)1"))
9300 audio_codec = "AAC";
9302 audio_codec = "unknown";
9304 if (mm_player_set_attribute((MMHandleType)player, NULL,
9305 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9306 LOGE("failed to set attribute");
9308 LOGD("set audio codec type with caps");