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;
1894 void *handle = NULL;
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);
1903 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1905 gst_video_overlay_set_video_roi_area(
1906 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1907 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1908 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1909 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1913 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1915 MMHandleType attrs = 0;
1916 void *handle = NULL;
1920 int win_roi_width = 0;
1921 int win_roi_height = 0;
1924 /* check video sinkbin is created */
1925 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1928 attrs = MMPLAYER_GET_ATTRS(player);
1929 MMPLAYER_RETURN_IF_FAIL(attrs);
1931 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
1934 /* It should be set after setting window */
1935 mm_attrs_multiple_get(attrs, NULL,
1936 "display_win_roi_x", &win_roi_x,
1937 "display_win_roi_y", &win_roi_y,
1938 "display_win_roi_width", &win_roi_width,
1939 "display_win_roi_height", &win_roi_height, NULL);
1941 /* After setting window handle, set display roi area */
1942 gst_video_overlay_set_display_roi_area(
1943 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1944 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1945 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1946 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;
1953 void *handle = NULL;
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_data_by_name(attrs, "display_overlay", &handle);
1966 /* default is using wl_surface_id */
1967 unsigned int wl_surface_id = 0;
1968 wl_surface_id = *(int *)handle;
1969 LOGD("set video param : wl_surface_id %d", wl_surface_id);
1970 gst_video_overlay_set_wl_window_wl_surface_id(
1971 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1974 /* FIXIT : is it error case? */
1975 LOGW("still we don't have a window handle on player attribute. create it's own surface.");
1980 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1982 gboolean update_all_param = FALSE;
1986 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1987 LOGW("videosink is not ready yet");
1988 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1991 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1992 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1993 return MM_ERROR_PLAYER_INTERNAL;
1996 LOGD("param_name : %s", param_name);
1997 if (!g_strcmp0(param_name, "update_all_param"))
1998 update_all_param = TRUE;
2000 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2001 __mmplayer_video_param_set_display_overlay(player);
2002 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2003 __mmplayer_video_param_set_display_method(player);
2004 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2005 __mmplayer_video_param_set_display_visible(player);
2006 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2007 __mmplayer_video_param_set_display_rotation(player);
2008 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2009 __mmplayer_video_param_set_roi_area(player);
2010 if (update_all_param)
2011 __mmplayer_video_param_set_video_roi_area(player);
2015 return MM_ERROR_NONE;
2019 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2021 gboolean disable_overlay = FALSE;
2022 mmplayer_t *player = (mmplayer_t *)hplayer;
2025 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2026 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2027 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2028 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2030 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2031 LOGW("Display control is not supported");
2032 return MM_ERROR_PLAYER_INTERNAL;
2035 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2037 if (audio_only == (bool)disable_overlay) {
2038 LOGE("It's the same with current setting: (%d)", audio_only);
2039 return MM_ERROR_NONE;
2043 LOGE("disable overlay");
2044 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2046 /* release overlay resource */
2047 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2048 LOGE("failed to release overlay resource");
2052 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2053 LOGE("failed to acquire video overlay resource");
2056 player->interrupted_by_resource = FALSE;
2058 LOGD("enable overlay");
2059 __mmplayer_video_param_set_display_overlay(player);
2060 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2065 return MM_ERROR_NONE;
2069 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2071 mmplayer_t *player = (mmplayer_t *)hplayer;
2072 gboolean disable_overlay = FALSE;
2076 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2077 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2078 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2079 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2080 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2082 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2083 LOGW("Display control is not supported");
2084 return MM_ERROR_PLAYER_INTERNAL;
2087 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2089 *paudio_only = (bool)disable_overlay;
2091 LOGD("audio_only : %d", *paudio_only);
2095 return MM_ERROR_NONE;
2099 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2101 GList *bucket = element_bucket;
2102 mmplayer_gst_element_t *element = NULL;
2103 mmplayer_gst_element_t *prv_element = NULL;
2104 GstElement *tee_element = NULL;
2105 gint successful_link_count = 0;
2109 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2111 prv_element = (mmplayer_gst_element_t *)bucket->data;
2112 bucket = bucket->next;
2114 for (; bucket; bucket = bucket->next) {
2115 element = (mmplayer_gst_element_t *)bucket->data;
2117 if (element && element->gst) {
2118 if (prv_element && prv_element->gst) {
2119 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2121 prv_element->gst = tee_element;
2123 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2124 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2125 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2129 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2130 LOGD("linking [%s] to [%s] success",
2131 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2132 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2133 successful_link_count++;
2134 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2135 LOGD("keep audio-tee element for next audio pipeline branch");
2136 tee_element = prv_element->gst;
2139 LOGD("linking [%s] to [%s] failed",
2140 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2141 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2147 prv_element = element;
2152 return successful_link_count;
2156 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2158 GList *bucket = element_bucket;
2159 mmplayer_gst_element_t *element = NULL;
2160 int successful_add_count = 0;
2164 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2165 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2167 for (; bucket; bucket = bucket->next) {
2168 element = (mmplayer_gst_element_t *)bucket->data;
2170 if (element && element->gst) {
2171 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2172 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2173 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2174 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2177 successful_add_count++;
2183 return successful_add_count;
2187 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2189 mmplayer_t *player = (mmplayer_t *)data;
2190 GstCaps *caps = NULL;
2191 GstStructure *str = NULL;
2193 gboolean caps_ret = TRUE;
2197 MMPLAYER_RETURN_IF_FAIL(pad);
2198 MMPLAYER_RETURN_IF_FAIL(unused);
2199 MMPLAYER_RETURN_IF_FAIL(data);
2201 caps = gst_pad_get_current_caps(pad);
2205 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2209 LOGD("name = %s", name);
2211 if (strstr(name, "audio")) {
2212 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2214 if (player->audio_stream_changed_cb) {
2215 LOGE("call the audio stream changed cb");
2216 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2218 } else if (strstr(name, "video")) {
2219 if ((name = gst_structure_get_string(str, "format")))
2220 player->set_mode.video_zc = name[0] == 'S';
2222 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2223 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2225 LOGW("invalid caps info");
2230 gst_caps_unref(caps);
2238 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2243 MMPLAYER_RETURN_IF_FAIL(player);
2245 if (player->audio_stream_buff_list) {
2246 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2247 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2250 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2251 __mmplayer_audio_stream_send_data(player, tmp);
2253 MMPLAYER_FREEIF(tmp->pcm_data);
2254 MMPLAYER_FREEIF(tmp);
2257 g_list_free(player->audio_stream_buff_list);
2258 player->audio_stream_buff_list = NULL;
2265 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2267 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2270 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2272 audio_stream.bitrate = a_buffer->bitrate;
2273 audio_stream.channel = a_buffer->channel;
2274 audio_stream.depth = a_buffer->depth;
2275 audio_stream.is_little_endian = a_buffer->is_little_endian;
2276 audio_stream.channel_mask = a_buffer->channel_mask;
2277 audio_stream.data_size = a_buffer->data_size;
2278 audio_stream.data = a_buffer->pcm_data;
2279 audio_stream.pcm_format = a_buffer->pcm_format;
2281 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2283 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2289 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2291 mmplayer_t *player = (mmplayer_t *)data;
2292 const gchar *pcm_format = NULL;
2296 gint endianness = 0;
2297 guint64 channel_mask = 0;
2298 void *a_data = NULL;
2300 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2301 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2305 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2307 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2308 a_data = mapinfo.data;
2309 a_size = mapinfo.size;
2311 GstCaps *caps = gst_pad_get_current_caps(pad);
2312 GstStructure *structure = gst_caps_get_structure(caps, 0);
2314 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2316 pcm_format = gst_structure_get_string(structure, "format");
2317 gst_structure_get_int(structure, "rate", &rate);
2318 gst_structure_get_int(structure, "channels", &channel);
2319 gst_structure_get_int(structure, "depth", &depth);
2320 gst_structure_get_int(structure, "endianness", &endianness);
2321 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2322 gst_caps_unref(GST_CAPS(caps));
2324 /* In case of the sync is false, use buffer list. *
2325 * The num of buffer list depends on the num of audio channels */
2326 if (player->audio_stream_buff_list) {
2327 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2328 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2330 if (channel_mask == tmp->channel_mask) {
2332 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2334 if (tmp->data_size + a_size < tmp->buff_size) {
2335 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2336 tmp->data_size += a_size;
2338 /* send data to client */
2339 __mmplayer_audio_stream_send_data(player, tmp);
2341 if (a_size > tmp->buff_size) {
2342 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2343 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2344 if (tmp->pcm_data == NULL) {
2345 LOGE("failed to realloc data.");
2348 tmp->buff_size = a_size;
2350 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2351 memcpy(tmp->pcm_data, a_data, a_size);
2352 tmp->data_size = a_size;
2357 LOGE("data is empty in list.");
2363 /* create new audio stream data for newly found audio channel */
2364 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2365 if (a_buffer == NULL) {
2366 LOGE("failed to alloc data.");
2369 a_buffer->bitrate = rate;
2370 a_buffer->channel = channel;
2371 a_buffer->depth = depth;
2372 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2373 a_buffer->channel_mask = channel_mask;
2374 a_buffer->data_size = a_size;
2375 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2377 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2378 /* If sync is FALSE, use buffer list to reduce the IPC. */
2379 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2380 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2381 if (a_buffer->pcm_data == NULL) {
2382 LOGE("failed to alloc data.");
2383 MMPLAYER_FREEIF(a_buffer);
2386 memcpy(a_buffer->pcm_data, a_data, a_size);
2388 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2390 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2392 /* If sync is TRUE, send data directly. */
2393 a_buffer->pcm_data = a_data;
2394 __mmplayer_audio_stream_send_data(player, a_buffer);
2395 MMPLAYER_FREEIF(a_buffer);
2399 gst_buffer_unmap(buffer, &mapinfo);
2404 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2406 mmplayer_t *player = (mmplayer_t *)data;
2407 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2408 GstPad *sinkpad = NULL;
2409 GstElement *queue = NULL, *sink = NULL;
2412 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2414 queue = gst_element_factory_make("queue", NULL);
2415 if (queue == NULL) {
2416 LOGD("fail make queue");
2420 sink = gst_element_factory_make("fakesink", NULL);
2422 LOGD("fail make fakesink");
2426 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2428 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2429 LOGW("failed to link queue & sink");
2433 sinkpad = gst_element_get_static_pad(queue, "sink");
2435 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2436 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2440 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2442 gst_object_unref(sinkpad);
2443 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2444 g_object_set(sink, "sync", TRUE, NULL);
2445 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2447 /* keep the first sink reference only */
2448 if (!audiobin[MMPLAYER_A_SINK].gst) {
2449 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2450 audiobin[MMPLAYER_A_SINK].gst = sink;
2454 _mmplayer_add_signal_connection(player,
2456 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2458 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2461 __mmplayer_add_sink(player, sink);
2463 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2464 LOGE("failed to sync state");
2468 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2469 LOGE("failed to sync state");
2477 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2479 gst_object_unref(GST_OBJECT(queue));
2483 gst_object_unref(GST_OBJECT(sink));
2487 gst_object_unref(GST_OBJECT(sinkpad));
2495 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2497 mmplayer_t *player = (mmplayer_t *)data;
2500 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2502 player->no_more_pad = TRUE;
2503 __mmplayer_pipeline_complete(NULL, player);
2510 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2512 #define MAX_PROPS_LEN 128
2513 mmplayer_gst_element_t *audiobin = NULL;
2514 gint latency_mode = 0;
2515 gchar *stream_type = NULL;
2516 gchar *latency = NULL;
2518 gchar stream_props[MAX_PROPS_LEN] = {0,};
2519 GstStructure *props = NULL;
2522 * It should be set after player creation through attribute.
2523 * But, it can not be changed during playing.
2526 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2528 audiobin = player->pipeline->audiobin;
2530 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2531 if (player->sound.mute) {
2532 LOGD("mute enabled");
2533 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2536 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2537 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2540 snprintf(stream_props, sizeof(stream_props) - 1,
2541 "props,application.process.id.origin=%d", player->client_pid);
2543 snprintf(stream_props, sizeof(stream_props) - 1,
2544 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2545 stream_type, stream_id, player->client_pid);
2547 props = gst_structure_from_string(stream_props, NULL);
2548 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2549 LOGI("props result[%s].", stream_props);
2550 gst_structure_free(props);
2552 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2554 switch (latency_mode) {
2555 case AUDIO_LATENCY_MODE_LOW:
2556 latency = g_strndup("low", 3);
2558 case AUDIO_LATENCY_MODE_MID:
2559 latency = g_strndup("mid", 3);
2561 case AUDIO_LATENCY_MODE_HIGH:
2562 latency = g_strndup("high", 4);
2566 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2568 LOGD("audiosink property - latency=%s", latency);
2570 MMPLAYER_FREEIF(latency);
2576 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2578 mmplayer_gst_element_t *audiobin = NULL;
2581 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2583 audiobin = player->pipeline->audiobin;
2585 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2586 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2587 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2589 if (player->video360_yaw_radians <= M_PI &&
2590 player->video360_yaw_radians >= -M_PI &&
2591 player->video360_pitch_radians <= M_PI_2 &&
2592 player->video360_pitch_radians >= -M_PI_2) {
2593 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2594 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2595 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2596 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2597 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2598 "source-orientation-y", player->video360_metadata.init_view_heading,
2599 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2606 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2608 mmplayer_gst_element_t *audiobin = NULL;
2609 GstPad *sink_pad = NULL;
2610 GstCaps *acaps = NULL;
2612 int pitch_control = 0;
2613 double pitch_value = 1.0;
2616 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2617 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2619 audiobin = player->pipeline->audiobin;
2621 LOGD("make element for normal audio playback");
2623 /* audio bin structure for playback. {} means optional.
2624 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2626 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2627 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2630 /* for pitch control */
2631 mm_attrs_multiple_get(player->attrs, NULL,
2632 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2633 MM_PLAYER_PITCH_VALUE, &pitch_value,
2636 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2637 if (pitch_control && (player->videodec_linked == 0)) {
2638 GstElementFactory *factory;
2640 factory = gst_element_factory_find("pitch");
2642 gst_object_unref(factory);
2645 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2648 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2649 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2651 LOGW("there is no pitch element");
2656 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2658 /* replaygain volume */
2659 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2660 if (player->sound.rg_enable)
2661 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2663 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2666 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2668 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2669 /* currently, only openalsink uses volume element */
2670 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2671 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2673 if (player->sound.mute) {
2674 LOGD("mute enabled");
2675 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2679 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2681 /* audio effect element. if audio effect is enabled */
2682 if ((strcmp(player->ini.audioeffect_element, ""))
2684 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2685 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2687 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2689 if ((!player->bypass_audio_effect)
2690 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2691 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2692 if (!_mmplayer_audio_effect_custom_apply(player))
2693 LOGI("apply audio effect(custom) setting success");
2697 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2698 && (player->set_mode.rich_audio)) {
2699 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2703 /* create audio sink */
2704 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2705 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2706 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2708 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2709 if (player->is_360_feature_enabled &&
2710 player->is_content_spherical &&
2712 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2713 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2714 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2716 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2718 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2720 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2721 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2722 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2723 gst_caps_unref(acaps);
2725 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2727 player->is_openal_plugin_used = TRUE;
2729 if (player->is_360_feature_enabled && player->is_content_spherical)
2730 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2731 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2734 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2735 (player->videodec_linked && player->ini.use_system_clock)) {
2736 LOGD("system clock will be used.");
2737 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2740 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2741 __mmplayer_gst_set_pulsesink_property(player);
2742 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2743 __mmplayer_gst_set_openalsink_property(player);
2746 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2747 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2749 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2750 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2751 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2752 gst_object_unref(GST_OBJECT(sink_pad));
2754 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2757 return MM_ERROR_NONE;
2759 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2761 return MM_ERROR_PLAYER_INTERNAL;
2765 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2767 mmplayer_gst_element_t *audiobin = NULL;
2768 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2770 gchar *dst_format = NULL;
2772 int dst_samplerate = 0;
2773 int dst_channels = 0;
2774 GstCaps *caps = NULL;
2775 char *caps_str = NULL;
2778 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2779 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2781 audiobin = player->pipeline->audiobin;
2783 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2785 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2787 [case 1] extract interleave audio pcm without playback
2788 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2789 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2791 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2793 [case 2] deinterleave for each channel without playback
2794 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2795 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2797 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2798 - fakesink (sync or not)
2801 [case 3] [case 1(sync only)] + playback
2802 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2804 * src - ... - tee - queue1 - playback path
2805 - queue2 - [case1 pipeline with sync]
2807 [case 4] [case 2(sync only)] + playback
2808 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2810 * src - ... - tee - queue1 - playback path
2811 - queue2 - [case2 pipeline with sync]
2815 /* 1. create tee and playback path
2816 'tee' should be added at first to copy the decoded stream
2818 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2819 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2820 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2822 /* tee - path 1 : for playback path */
2823 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2824 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2826 /* tee - path 2 : for extract path */
2827 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2828 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2831 /* if there is tee, 'tee - path 2' is linked here */
2833 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2836 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2838 /* 2. decide the extract pcm format */
2839 mm_attrs_multiple_get(player->attrs, NULL,
2840 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2841 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2842 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2845 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2846 dst_format, dst_len, dst_samplerate, dst_channels);
2848 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2849 mm_attrs_multiple_get(player->attrs, NULL,
2850 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2851 "content_audio_samplerate", &dst_samplerate,
2852 "content_audio_channels", &dst_channels,
2855 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2856 dst_format, dst_len, dst_samplerate, dst_channels);
2858 /* If there is no enough information, set it to platform default value. */
2859 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2860 LOGD("set platform default format");
2861 dst_format = DEFAULT_PCM_OUT_FORMAT;
2863 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2864 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2867 /* 3. create capsfilter */
2868 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2869 caps = gst_caps_new_simple("audio/x-raw",
2870 "format", G_TYPE_STRING, dst_format,
2871 "rate", G_TYPE_INT, dst_samplerate,
2872 "channels", G_TYPE_INT, dst_channels,
2875 caps_str = gst_caps_to_string(caps);
2876 LOGD("new caps : %s", caps_str);
2878 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2881 gst_caps_unref(caps);
2882 MMPLAYER_FREEIF(caps_str);
2884 /* 4-1. create deinterleave to extract pcm for each channel */
2885 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2886 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2887 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2889 /* audiosink will be added after getting signal for each channel */
2890 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2891 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2892 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2893 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2894 player->no_more_pad = FALSE;
2896 /* 4-2. create fakesink to extract interlevaed pcm */
2897 LOGD("add audio fakesink for interleaved audio");
2898 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2899 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2900 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2901 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2903 _mmplayer_add_signal_connection(player,
2904 G_OBJECT(audiobin[extract_sink_id].gst),
2905 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2907 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2910 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2914 return MM_ERROR_NONE;
2916 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2918 return MM_ERROR_PLAYER_INTERNAL;
2922 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2924 int ret = MM_ERROR_NONE;
2925 mmplayer_gst_element_t *audiobin = NULL;
2926 GList *element_bucket = NULL;
2929 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2930 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2932 audiobin = player->pipeline->audiobin;
2934 if (player->build_audio_offload) { /* skip all the audio filters */
2935 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2937 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2938 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2939 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2941 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2945 /* FIXME: need to mention the supportable condition at API reference */
2946 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2947 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2949 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2951 if (ret != MM_ERROR_NONE)
2954 LOGD("success to make audio bin element");
2955 *bucket = element_bucket;
2958 return MM_ERROR_NONE;
2961 LOGE("failed to make audio bin element");
2962 g_list_free(element_bucket);
2966 return MM_ERROR_PLAYER_INTERNAL;
2970 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2972 mmplayer_gst_element_t *first_element = NULL;
2973 mmplayer_gst_element_t *audiobin = NULL;
2975 GstPad *ghostpad = NULL;
2976 GList *element_bucket = NULL;
2980 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2983 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2985 LOGE("failed to allocate memory for audiobin");
2986 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2990 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2991 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2992 if (!audiobin[MMPLAYER_A_BIN].gst) {
2993 LOGE("failed to create audiobin");
2998 player->pipeline->audiobin = audiobin;
3000 /* create audio filters and audiosink */
3001 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3004 /* adding created elements to bin */
3005 LOGD("adding created elements to bin");
3006 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3009 /* linking elements in the bucket by added order. */
3010 LOGD("Linking elements in the bucket by added order.");
3011 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3014 /* get first element's sinkpad for creating ghostpad */
3015 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3016 if (!first_element) {
3017 LOGE("failed to get first elem");
3021 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3023 LOGE("failed to get pad from first element of audiobin");
3027 ghostpad = gst_ghost_pad_new("sink", pad);
3029 LOGE("failed to create ghostpad");
3033 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3034 LOGE("failed to add ghostpad to audiobin");
3038 gst_object_unref(pad);
3040 g_list_free(element_bucket);
3043 return MM_ERROR_NONE;
3046 LOGD("ERROR : releasing audiobin");
3049 gst_object_unref(GST_OBJECT(pad));
3052 gst_object_unref(GST_OBJECT(ghostpad));
3055 g_list_free(element_bucket);
3057 /* release element which are not added to bin */
3058 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3059 /* NOTE : skip bin */
3060 if (audiobin[i].gst) {
3061 GstObject *parent = NULL;
3062 parent = gst_element_get_parent(audiobin[i].gst);
3065 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3066 audiobin[i].gst = NULL;
3068 gst_object_unref(GST_OBJECT(parent));
3072 /* release audiobin with it's childs */
3073 if (audiobin[MMPLAYER_A_BIN].gst)
3074 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3076 MMPLAYER_FREEIF(audiobin);
3078 player->pipeline->audiobin = NULL;
3080 return MM_ERROR_PLAYER_INTERNAL;
3084 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3086 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3090 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3092 int ret = MM_ERROR_NONE;
3094 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3095 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3097 MMPLAYER_VIDEO_BO_LOCK(player);
3099 if (player->video_bo_list) {
3100 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3101 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3102 if (tmp && tmp->bo == bo) {
3104 LOGD("release bo %p", bo);
3105 tbm_bo_unref(tmp->bo);
3106 MMPLAYER_VIDEO_BO_UNLOCK(player);
3107 MMPLAYER_VIDEO_BO_SIGNAL(player);
3112 /* hw codec is running or the list was reset for DRC. */
3113 LOGW("there is no bo list.");
3115 MMPLAYER_VIDEO_BO_UNLOCK(player);
3117 LOGW("failed to find bo %p", bo);
3122 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3127 MMPLAYER_RETURN_IF_FAIL(player);
3129 MMPLAYER_VIDEO_BO_LOCK(player);
3130 if (player->video_bo_list) {
3131 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3132 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3133 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3136 tbm_bo_unref(tmp->bo);
3140 g_list_free(player->video_bo_list);
3141 player->video_bo_list = NULL;
3143 player->video_bo_size = 0;
3144 MMPLAYER_VIDEO_BO_UNLOCK(player);
3151 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3154 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3155 gboolean ret = TRUE;
3157 /* check DRC, if it is, destroy the prev bo list to create again */
3158 if (player->video_bo_size != size) {
3159 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3160 __mmplayer_video_stream_destroy_bo_list(player);
3161 player->video_bo_size = size;
3164 MMPLAYER_VIDEO_BO_LOCK(player);
3166 if ((!player->video_bo_list) ||
3167 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3169 /* create bo list */
3171 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3173 if (player->video_bo_list) {
3174 /* if bo list did not created all, try it again. */
3175 idx = g_list_length(player->video_bo_list);
3176 LOGD("bo list exist(len: %d)", idx);
3179 for (; idx < player->ini.num_of_video_bo; idx++) {
3180 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3182 LOGE("Fail to alloc bo_info.");
3185 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3187 LOGE("Fail to tbm_bo_alloc.");
3188 MMPLAYER_FREEIF(bo_info);
3191 bo_info->used = FALSE;
3192 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3195 /* update video num buffers */
3196 LOGD("video_num_buffers : %d", idx);
3197 mm_player_set_attribute((MMHandleType)player, NULL,
3198 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3199 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3203 MMPLAYER_VIDEO_BO_UNLOCK(player);
3209 /* get bo from list*/
3210 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3211 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3212 if (tmp && (tmp->used == FALSE)) {
3213 LOGD("found bo %p to use", tmp->bo);
3215 MMPLAYER_VIDEO_BO_UNLOCK(player);
3216 return tbm_bo_ref(tmp->bo);
3220 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3221 MMPLAYER_VIDEO_BO_UNLOCK(player);
3225 if (player->ini.video_bo_timeout <= 0) {
3226 MMPLAYER_VIDEO_BO_WAIT(player);
3228 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3229 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3236 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3238 mmplayer_t *player = (mmplayer_t *)data;
3240 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3242 /* send prerolled pkt */
3243 player->video_stream_prerolled = false;
3245 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3247 /* not to send prerolled pkt again */
3248 player->video_stream_prerolled = true;
3252 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3254 mmplayer_t *player = (mmplayer_t *)data;
3255 mmplayer_video_decoded_data_info_t *stream = NULL;
3256 GstMemory *mem = NULL;
3259 MMPLAYER_RETURN_IF_FAIL(player);
3260 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3262 if (player->video_stream_prerolled) {
3263 player->video_stream_prerolled = false;
3264 LOGD("skip the prerolled pkt not to send it again");
3268 /* clear stream data structure */
3269 stream = __mmplayer_create_stream_from_pad(pad);
3271 LOGE("failed to alloc stream");
3275 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3277 /* set size and timestamp */
3278 mem = gst_buffer_peek_memory(buffer, 0);
3279 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3280 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3282 /* check zero-copy */
3283 if (player->set_mode.video_zc &&
3284 player->set_mode.video_export &&
3285 gst_is_tizen_memory(mem)) {
3286 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3287 stream->internal_buffer = gst_buffer_ref(buffer);
3288 } else { /* sw codec */
3289 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3292 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3296 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3297 LOGE("failed to send video decoded data.");
3304 LOGE("release video stream resource.");
3305 if (gst_is_tizen_memory(mem)) {
3307 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3309 tbm_bo_unref(stream->bo[i]);
3312 /* unref gst buffer */
3313 if (stream->internal_buffer)
3314 gst_buffer_unref(stream->internal_buffer);
3317 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3319 MMPLAYER_FREEIF(stream);
3324 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3326 mmplayer_gst_element_t *videobin = NULL;
3329 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3331 videobin = player->pipeline->videobin;
3333 /* Set spatial media metadata and/or user settings to the element.
3335 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3336 "projection-type", player->video360_metadata.projection_type, NULL);
3338 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3339 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3341 if (player->video360_metadata.full_pano_width_pixels &&
3342 player->video360_metadata.full_pano_height_pixels &&
3343 player->video360_metadata.cropped_area_image_width &&
3344 player->video360_metadata.cropped_area_image_height) {
3345 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3346 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3347 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3348 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3349 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3350 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3351 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3355 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3356 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3357 "horizontal-fov", player->video360_horizontal_fov,
3358 "vertical-fov", player->video360_vertical_fov, NULL);
3361 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3362 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3363 "zoom", 1.0f / player->video360_zoom, NULL);
3366 if (player->video360_yaw_radians <= M_PI &&
3367 player->video360_yaw_radians >= -M_PI &&
3368 player->video360_pitch_radians <= M_PI_2 &&
3369 player->video360_pitch_radians >= -M_PI_2) {
3370 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3371 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3372 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3373 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3374 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3375 "pose-yaw", player->video360_metadata.init_view_heading,
3376 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3379 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3380 "passthrough", !player->is_video360_enabled, NULL);
3387 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3389 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3390 GList *element_bucket = NULL;
3393 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3395 /* create video360 filter */
3396 if (player->is_360_feature_enabled && player->is_content_spherical) {
3397 LOGD("create video360 element");
3398 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3399 __mmplayer_gst_set_video360_property(player);
3403 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3404 LOGD("skip creating the videoconv and rotator");
3405 return MM_ERROR_NONE;
3408 /* in case of sw codec & overlay surface type, except 360 playback.
3409 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3410 LOGD("create video converter: %s", video_csc);
3411 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3414 *bucket = element_bucket;
3416 return MM_ERROR_NONE;
3418 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3419 g_list_free(element_bucket);
3423 return MM_ERROR_PLAYER_INTERNAL;
3427 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3429 gchar *factory_name = NULL;
3431 switch (surface_type) {
3432 case MM_DISPLAY_SURFACE_OVERLAY:
3433 if (strlen(player->ini.videosink_element_overlay) > 0)
3434 factory_name = player->ini.videosink_element_overlay;
3436 case MM_DISPLAY_SURFACE_REMOTE:
3437 case MM_DISPLAY_SURFACE_NULL:
3438 if (strlen(player->ini.videosink_element_fake) > 0)
3439 factory_name = player->ini.videosink_element_fake;
3442 LOGE("unidentified surface type");
3446 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3447 return factory_name;
3451 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3453 gchar *factory_name = NULL;
3454 mmplayer_gst_element_t *videobin = NULL;
3459 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3461 videobin = player->pipeline->videobin;
3462 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3464 attrs = MMPLAYER_GET_ATTRS(player);
3466 LOGE("cannot get content attribute");
3467 return MM_ERROR_PLAYER_INTERNAL;
3470 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3471 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3472 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3474 /* support shard memory with S/W codec on HawkP */
3475 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3476 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3477 "use-tbm", use_tbm, NULL);
3481 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3482 return MM_ERROR_PLAYER_INTERNAL;
3484 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3485 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3488 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3490 LOGD("disable last-sample");
3491 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3494 if (player->set_mode.video_export) {
3496 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3497 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3498 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3500 _mmplayer_add_signal_connection(player,
3501 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3502 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3504 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3507 _mmplayer_add_signal_connection(player,
3508 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3509 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3511 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3515 if (videobin[MMPLAYER_V_SINK].gst) {
3516 GstPad *sink_pad = NULL;
3517 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3519 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3520 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3521 gst_object_unref(GST_OBJECT(sink_pad));
3523 LOGE("failed to get sink pad from videosink");
3527 return MM_ERROR_NONE;
3532 * - video overlay surface(arm/x86) : tizenwlsink
3535 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3538 GList *element_bucket = NULL;
3539 mmplayer_gst_element_t *first_element = NULL;
3540 mmplayer_gst_element_t *videobin = NULL;
3541 gchar *videosink_factory_name = NULL;
3544 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3547 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3549 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3551 player->pipeline->videobin = videobin;
3554 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3555 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3556 if (!videobin[MMPLAYER_V_BIN].gst) {
3557 LOGE("failed to create videobin");
3561 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3564 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3565 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3567 /* additional setting for sink plug-in */
3568 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3569 LOGE("failed to set video property");
3573 /* store it as it's sink element */
3574 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3576 /* adding created elements to bin */
3577 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3578 LOGE("failed to add elements");
3582 /* Linking elements in the bucket by added order */
3583 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3584 LOGE("failed to link elements");
3588 /* get first element's sinkpad for creating ghostpad */
3589 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3590 if (!first_element) {
3591 LOGE("failed to get first element from bucket");
3595 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3597 LOGE("failed to get pad from first element");
3601 /* create ghostpad */
3602 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3603 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3604 LOGE("failed to add ghostpad to videobin");
3607 gst_object_unref(pad);
3609 /* done. free allocated variables */
3610 g_list_free(element_bucket);
3614 return MM_ERROR_NONE;
3617 LOGE("ERROR : releasing videobin");
3618 g_list_free(element_bucket);
3621 gst_object_unref(GST_OBJECT(pad));
3623 /* release videobin with it's childs */
3624 if (videobin[MMPLAYER_V_BIN].gst)
3625 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3627 MMPLAYER_FREEIF(videobin);
3628 player->pipeline->videobin = NULL;
3630 return MM_ERROR_PLAYER_INTERNAL;
3634 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3636 GList *element_bucket = NULL;
3637 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3639 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3640 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3641 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3642 "signal-handoffs", FALSE,
3645 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3646 _mmplayer_add_signal_connection(player,
3647 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3648 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3650 G_CALLBACK(__mmplayer_update_subtitle),
3653 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3654 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3656 if (!player->play_subtitle) {
3657 LOGD("add textbin sink as sink element of whole pipeline.");
3658 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3661 /* adding created elements to bin */
3662 LOGD("adding created elements to bin");
3663 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3664 LOGE("failed to add elements");
3668 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3669 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3670 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3672 /* linking elements in the bucket by added order. */
3673 LOGD("Linking elements in the bucket by added order.");
3674 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3675 LOGE("failed to link elements");
3679 /* done. free allocated variables */
3680 g_list_free(element_bucket);
3682 if (textbin[MMPLAYER_T_QUEUE].gst) {
3684 GstPad *ghostpad = NULL;
3686 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3688 LOGE("failed to get sink pad of text queue");
3692 ghostpad = gst_ghost_pad_new("text_sink", pad);
3693 gst_object_unref(pad);
3696 LOGE("failed to create ghostpad of textbin");
3700 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3701 LOGE("failed to add ghostpad to textbin");
3702 gst_object_unref(ghostpad);
3707 return MM_ERROR_NONE;
3710 g_list_free(element_bucket);
3712 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3713 LOGE("remove textbin sink from sink list");
3714 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3717 /* release element at __mmplayer_gst_create_text_sink_bin */
3718 return MM_ERROR_PLAYER_INTERNAL;
3722 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3724 mmplayer_gst_element_t *textbin = NULL;
3725 GList *element_bucket = NULL;
3726 int surface_type = 0;
3731 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3734 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3736 LOGE("failed to allocate memory for textbin");
3737 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3741 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3742 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3743 if (!textbin[MMPLAYER_T_BIN].gst) {
3744 LOGE("failed to create textbin");
3749 player->pipeline->textbin = textbin;
3752 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3753 LOGD("surface type for subtitle : %d", surface_type);
3754 switch (surface_type) {
3755 case MM_DISPLAY_SURFACE_OVERLAY:
3756 case MM_DISPLAY_SURFACE_NULL:
3757 case MM_DISPLAY_SURFACE_REMOTE:
3758 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3759 LOGE("failed to make plain text elements");
3770 return MM_ERROR_NONE;
3774 LOGD("ERROR : releasing textbin");
3776 g_list_free(element_bucket);
3778 /* release signal */
3779 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3781 /* release element which are not added to bin */
3782 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3783 /* NOTE : skip bin */
3784 if (textbin[i].gst) {
3785 GstObject *parent = NULL;
3786 parent = gst_element_get_parent(textbin[i].gst);
3789 gst_object_unref(GST_OBJECT(textbin[i].gst));
3790 textbin[i].gst = NULL;
3792 gst_object_unref(GST_OBJECT(parent));
3797 /* release textbin with it's childs */
3798 if (textbin[MMPLAYER_T_BIN].gst)
3799 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3801 MMPLAYER_FREEIF(player->pipeline->textbin);
3802 player->pipeline->textbin = NULL;
3805 return MM_ERROR_PLAYER_INTERNAL;
3809 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3811 mmplayer_gst_element_t *mainbin = NULL;
3812 mmplayer_gst_element_t *textbin = NULL;
3813 MMHandleType attrs = 0;
3814 GstElement *subsrc = NULL;
3815 GstElement *subparse = NULL;
3816 gchar *subtitle_uri = NULL;
3817 const gchar *charset = NULL;
3823 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3825 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3827 mainbin = player->pipeline->mainbin;
3829 attrs = MMPLAYER_GET_ATTRS(player);
3831 LOGE("cannot get content attribute");
3832 return MM_ERROR_PLAYER_INTERNAL;
3835 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3836 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3837 LOGE("subtitle uri is not proper filepath.");
3838 return MM_ERROR_PLAYER_INVALID_URI;
3841 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3842 LOGE("failed to get storage info of subtitle path");
3843 return MM_ERROR_PLAYER_INVALID_URI;
3846 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3848 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3849 player->subtitle_language_list = NULL;
3850 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3852 /* create the subtitle source */
3853 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3855 LOGE("failed to create filesrc element");
3858 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3860 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3861 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3863 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3864 LOGW("failed to add queue");
3865 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3866 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3867 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3872 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3874 LOGE("failed to create subparse element");
3878 charset = _mmplayer_get_charset(subtitle_uri);
3880 LOGD("detected charset is %s", charset);
3881 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3884 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3885 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3887 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3888 LOGW("failed to add subparse");
3889 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3890 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3891 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3895 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3896 LOGW("failed to link subsrc and subparse");
3900 player->play_subtitle = TRUE;
3901 player->adjust_subtitle_pos = 0;
3903 LOGD("play subtitle using subtitle file");
3905 if (player->pipeline->textbin == NULL) {
3906 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3907 LOGE("failed to create text sink bin. continuing without text");
3911 textbin = player->pipeline->textbin;
3913 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3914 LOGW("failed to add textbin");
3916 /* release signal */
3917 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3919 /* release textbin with it's childs */
3920 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3921 MMPLAYER_FREEIF(player->pipeline->textbin);
3922 player->pipeline->textbin = textbin = NULL;
3926 LOGD("link text input selector and textbin ghost pad");
3928 player->textsink_linked = 1;
3929 player->external_text_idx = 0;
3930 LOGI("textsink is linked");
3932 textbin = player->pipeline->textbin;
3933 LOGD("text bin has been created. reuse it.");
3934 player->external_text_idx = 1;
3937 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3938 LOGW("failed to link subparse and textbin");
3942 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3944 LOGE("failed to get sink pad from textsink to probe data");
3948 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3949 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3951 gst_object_unref(pad);
3954 /* create dot. for debugging */
3955 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3958 return MM_ERROR_NONE;
3961 /* release text pipeline resource */
3962 player->textsink_linked = 0;
3964 /* release signal */
3965 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3967 if (player->pipeline->textbin) {
3968 LOGE("remove textbin");
3970 /* release textbin with it's childs */
3971 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3972 MMPLAYER_FREEIF(player->pipeline->textbin);
3973 player->pipeline->textbin = NULL;
3977 /* release subtitle elem */
3978 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3979 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3981 return MM_ERROR_PLAYER_INTERNAL;
3985 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3987 mmplayer_t *player = (mmplayer_t *)data;
3988 MMMessageParamType msg = {0, };
3989 GstClockTime duration = 0;
3990 gpointer text = NULL;
3991 guint text_size = 0;
3992 gboolean ret = TRUE;
3993 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3997 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3998 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4000 if (player->is_subtitle_force_drop) {
4001 LOGW("subtitle is dropped forcedly.");
4005 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4006 text = mapinfo.data;
4007 text_size = mapinfo.size;
4009 if (player->set_mode.subtitle_off) {
4010 LOGD("subtitle is OFF.");
4014 if (!text || (text_size == 0)) {
4015 LOGD("There is no subtitle to be displayed.");
4019 msg.data = (void *)text;
4021 duration = GST_BUFFER_DURATION(buffer);
4023 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4024 if (player->duration > GST_BUFFER_PTS(buffer))
4025 duration = player->duration - GST_BUFFER_PTS(buffer);
4028 LOGI("subtitle duration is invalid, subtitle duration change "
4029 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4031 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4033 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4035 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4036 gst_buffer_unmap(buffer, &mapinfo);
4043 static GstPadProbeReturn
4044 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4046 mmplayer_t *player = (mmplayer_t *)u_data;
4047 GstClockTime cur_timestamp = 0;
4048 gint64 adjusted_timestamp = 0;
4049 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4051 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4053 if (player->set_mode.subtitle_off) {
4054 LOGD("subtitle is OFF.");
4058 if (player->adjust_subtitle_pos == 0) {
4059 LOGD("nothing to do");
4063 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4064 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4066 if (adjusted_timestamp < 0) {
4067 LOGD("adjusted_timestamp under zero");
4072 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4073 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4074 GST_TIME_ARGS(cur_timestamp),
4075 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4077 return GST_PAD_PROBE_OK;
4081 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4085 /* check player and subtitlebin are created */
4086 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4087 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4089 if (position == 0) {
4090 LOGD("nothing to do");
4092 return MM_ERROR_NONE;
4095 /* check current postion */
4096 player->adjust_subtitle_pos = position;
4098 LOGD("save adjust_subtitle_pos in player");
4102 return MM_ERROR_NONE;
4106 * This function is to create audio or video pipeline for playing.
4108 * @param player [in] handle of player
4110 * @return This function returns zero on success.
4115 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4117 int ret = MM_ERROR_NONE;
4118 mmplayer_gst_element_t *mainbin = NULL;
4119 MMHandleType attrs = 0;
4122 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4124 /* get profile attribute */
4125 attrs = MMPLAYER_GET_ATTRS(player);
4127 LOGE("failed to get content attribute");
4131 /* create pipeline handles */
4132 if (player->pipeline) {
4133 LOGE("pipeline should be released before create new one");
4137 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4138 if (player->pipeline == NULL)
4141 /* create mainbin */
4142 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4143 if (mainbin == NULL)
4146 /* create pipeline */
4147 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4148 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4149 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4150 LOGE("failed to create pipeline");
4155 player->pipeline->mainbin = mainbin;
4157 /* create the source and decoder elements */
4158 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4159 ret = _mmplayer_gst_build_es_pipeline(player);
4161 ret = _mmplayer_gst_build_pipeline(player);
4163 if (ret != MM_ERROR_NONE) {
4164 LOGE("failed to create some elements");
4168 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4169 if (__mmplayer_check_subtitle(player)
4170 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4171 LOGE("failed to create text pipeline");
4174 ret = _mmplayer_gst_add_bus_watch(player);
4175 if (ret != MM_ERROR_NONE) {
4176 LOGE("failed to add bus watch");
4181 return MM_ERROR_NONE;
4184 __mmplayer_gst_destroy_pipeline(player);
4185 return MM_ERROR_PLAYER_INTERNAL;
4189 __mmplayer_reset_gapless_state(mmplayer_t *player)
4192 MMPLAYER_RETURN_IF_FAIL(player
4194 && player->pipeline->audiobin
4195 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4197 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4204 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4207 int ret = MM_ERROR_NONE;
4211 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4213 /* cleanup stuffs */
4214 MMPLAYER_FREEIF(player->type);
4215 player->no_more_pad = FALSE;
4216 player->num_dynamic_pad = 0;
4217 player->demux_pad_index = 0;
4219 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4220 player->subtitle_language_list = NULL;
4221 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4223 __mmplayer_reset_gapless_state(player);
4225 if (player->streamer) {
4226 _mm_player_streaming_initialize(player->streamer, FALSE);
4227 _mm_player_streaming_destroy(player->streamer);
4228 player->streamer = NULL;
4231 /* cleanup unlinked mime type */
4232 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4233 MMPLAYER_FREEIF(player->unlinked_video_mime);
4234 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4236 /* cleanup running stuffs */
4237 _mmplayer_cancel_eos_timer(player);
4239 /* cleanup gst stuffs */
4240 if (player->pipeline) {
4241 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4242 GstTagList *tag_list = player->pipeline->tag_list;
4244 /* first we need to disconnect all signal hander */
4245 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4248 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4249 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4250 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4251 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4252 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4253 gst_object_unref(bus);
4255 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4256 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4257 if (ret != MM_ERROR_NONE) {
4258 LOGE("fail to change state to NULL");
4259 return MM_ERROR_PLAYER_INTERNAL;
4262 LOGW("succeeded in changing state to NULL");
4264 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4267 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4268 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4270 /* free avsysaudiosink
4271 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4272 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4274 MMPLAYER_FREEIF(audiobin);
4275 MMPLAYER_FREEIF(videobin);
4276 MMPLAYER_FREEIF(textbin);
4277 MMPLAYER_FREEIF(mainbin);
4281 gst_tag_list_unref(tag_list);
4283 MMPLAYER_FREEIF(player->pipeline);
4285 MMPLAYER_FREEIF(player->album_art);
4287 if (player->v_stream_caps) {
4288 gst_caps_unref(player->v_stream_caps);
4289 player->v_stream_caps = NULL;
4292 if (player->a_stream_caps) {
4293 gst_caps_unref(player->a_stream_caps);
4294 player->a_stream_caps = NULL;
4297 if (player->s_stream_caps) {
4298 gst_caps_unref(player->s_stream_caps);
4299 player->s_stream_caps = NULL;
4301 _mmplayer_track_destroy(player);
4303 if (player->sink_elements)
4304 g_list_free(player->sink_elements);
4305 player->sink_elements = NULL;
4307 if (player->bufmgr) {
4308 tbm_bufmgr_deinit(player->bufmgr);
4309 player->bufmgr = NULL;
4312 LOGW("finished destroy pipeline");
4320 __mmplayer_gst_realize(mmplayer_t *player)
4323 int ret = MM_ERROR_NONE;
4327 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4329 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4331 ret = __mmplayer_gst_create_pipeline(player);
4333 LOGE("failed to create pipeline");
4337 /* set pipeline state to READY */
4338 /* NOTE : state change to READY must be performed sync. */
4339 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4340 ret = _mmplayer_gst_set_state(player,
4341 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4343 if (ret != MM_ERROR_NONE) {
4344 /* return error if failed to set state */
4345 LOGE("failed to set READY state");
4349 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4351 /* create dot before error-return. for debugging */
4352 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4360 __mmplayer_gst_unrealize(mmplayer_t *player)
4362 int ret = MM_ERROR_NONE;
4366 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4368 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4369 MMPLAYER_PRINT_STATE(player);
4371 /* release miscellaneous information */
4372 __mmplayer_release_misc(player);
4374 /* destroy pipeline */
4375 ret = __mmplayer_gst_destroy_pipeline(player);
4376 if (ret != MM_ERROR_NONE) {
4377 LOGE("failed to destory pipeline");
4381 /* release miscellaneous information.
4382 these info needs to be released after pipeline is destroyed. */
4383 __mmplayer_release_misc_post(player);
4385 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4393 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4398 LOGW("set_message_callback is called with invalid player handle");
4399 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4402 player->msg_cb = callback;
4403 player->msg_cb_param = user_param;
4405 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4409 return MM_ERROR_NONE;
4413 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4415 int ret = MM_ERROR_NONE;
4420 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4421 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4422 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4424 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4426 if (strstr(uri, "es_buff://")) {
4427 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4428 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4429 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4430 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4432 tmp = g_ascii_strdown(uri, strlen(uri));
4433 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4434 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4436 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4438 } else if (strstr(uri, "mms://")) {
4439 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4440 } else if ((path = strstr(uri, "mem://"))) {
4441 ret = __mmplayer_set_mem_uri(data, path, param);
4443 ret = __mmplayer_set_file_uri(data, uri);
4446 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4447 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4448 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4449 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4451 /* dump parse result */
4452 SECURE_LOGW("incoming uri : %s", uri);
4453 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4454 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4462 __mmplayer_can_do_interrupt(mmplayer_t *player)
4464 if (!player || !player->pipeline || !player->attrs) {
4465 LOGW("not initialized");
4469 if (player->audio_decoded_cb) {
4470 LOGW("not support in pcm extraction mode");
4474 /* check if seeking */
4475 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4476 MMMessageParamType msg_param;
4477 memset(&msg_param, 0, sizeof(MMMessageParamType));
4478 msg_param.code = MM_ERROR_PLAYER_SEEK;
4479 player->seek_state = MMPLAYER_SEEK_NONE;
4480 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4484 /* check other thread */
4485 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4486 LOGW("locked already, cmd state : %d", player->cmd);
4488 /* check application command */
4489 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4490 LOGW("playing.. should wait cmd lock then, will be interrupted");
4492 /* lock will be released at mrp_resource_release_cb() */
4493 MMPLAYER_CMD_LOCK(player);
4496 LOGW("nothing to do");
4499 LOGW("can interrupt immediately");
4503 FAILED: /* with CMD UNLOCKED */
4506 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4511 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4514 mmplayer_t *player = NULL;
4515 MMMessageParamType msg = {0, };
4517 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4522 LOGE("user_data is null");
4525 player = (mmplayer_t *)user_data;
4527 if (!__mmplayer_can_do_interrupt(player)) {
4528 LOGW("no need to interrupt, so leave");
4529 /* FIXME: there is no way to avoid releasing resource. */
4533 player->interrupted_by_resource = TRUE;
4535 /* get last play position */
4536 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4537 msg.union_type = MM_MSG_UNION_TIME;
4538 msg.time.elapsed = pos;
4539 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4541 LOGW("failed to get play position.");
4544 LOGD("video resource conflict so, resource will be freed by unrealizing");
4545 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4546 LOGE("failed to unrealize");
4548 /* lock is called in __mmplayer_can_do_interrupt() */
4549 MMPLAYER_CMD_UNLOCK(player);
4551 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4552 player->hw_resource[res_idx] = NULL;
4556 return TRUE; /* release all the resources */
4560 __mmplayer_initialize_video_roi(mmplayer_t *player)
4562 player->video_roi.scale_x = 0.0;
4563 player->video_roi.scale_y = 0.0;
4564 player->video_roi.scale_width = 1.0;
4565 player->video_roi.scale_height = 1.0;
4569 _mmplayer_create_player(MMHandleType handle)
4571 int ret = MM_ERROR_PLAYER_INTERNAL;
4572 bool enabled = false;
4574 mmplayer_t *player = MM_PLAYER_CAST(handle);
4578 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4580 /* initialize player state */
4581 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4582 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4583 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4584 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4586 /* check current state */
4587 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4589 /* construct attributes */
4590 player->attrs = _mmplayer_construct_attribute(handle);
4592 if (!player->attrs) {
4593 LOGE("Failed to construct attributes");
4597 /* initialize gstreamer with configured parameter */
4598 if (!__mmplayer_init_gstreamer(player)) {
4599 LOGE("Initializing gstreamer failed");
4600 _mmplayer_deconstruct_attribute(handle);
4604 /* create lock. note that g_tread_init() has already called in gst_init() */
4605 g_mutex_init(&player->fsink_lock);
4607 /* create update tag lock */
4608 g_mutex_init(&player->update_tag_lock);
4610 /* create gapless play mutex */
4611 g_mutex_init(&player->gapless_play_thread_mutex);
4613 /* create gapless play cond */
4614 g_cond_init(&player->gapless_play_thread_cond);
4616 /* create gapless play thread */
4617 player->gapless_play_thread =
4618 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4619 if (!player->gapless_play_thread) {
4620 LOGE("failed to create gapless play thread");
4621 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4622 g_mutex_clear(&player->gapless_play_thread_mutex);
4623 g_cond_clear(&player->gapless_play_thread_cond);
4627 player->bus_msg_q = g_queue_new();
4628 if (!player->bus_msg_q) {
4629 LOGE("failed to create queue for bus_msg");
4630 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4634 ret = _mmplayer_initialize_video_capture(player);
4635 if (ret != MM_ERROR_NONE) {
4636 LOGE("failed to initialize video capture");
4640 /* initialize resource manager */
4641 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4642 __resource_release_cb, player, &player->resource_manager)
4643 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4644 LOGE("failed to initialize resource manager");
4645 ret = MM_ERROR_PLAYER_INTERNAL;
4649 /* create video bo lock and cond */
4650 g_mutex_init(&player->video_bo_mutex);
4651 g_cond_init(&player->video_bo_cond);
4653 /* create subtitle info lock and cond */
4654 g_mutex_init(&player->subtitle_info_mutex);
4655 g_cond_init(&player->subtitle_info_cond);
4657 player->streaming_type = STREAMING_SERVICE_NONE;
4659 /* give default value of audio effect setting */
4660 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4661 player->sound.rg_enable = false;
4662 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4664 player->play_subtitle = FALSE;
4665 player->has_closed_caption = FALSE;
4666 player->pending_resume = FALSE;
4667 if (player->ini.dump_element_keyword[0][0] == '\0')
4668 player->ini.set_dump_element_flag = FALSE;
4670 player->ini.set_dump_element_flag = TRUE;
4672 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4673 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4674 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4676 /* Set video360 settings to their defaults for just-created player.
4679 player->is_360_feature_enabled = FALSE;
4680 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4681 LOGI("spherical feature info: %d", enabled);
4683 player->is_360_feature_enabled = TRUE;
4685 LOGE("failed to get spherical feature info");
4688 player->is_content_spherical = FALSE;
4689 player->is_video360_enabled = TRUE;
4690 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4691 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4692 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4693 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4694 player->video360_zoom = 1.0f;
4695 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4696 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4698 __mmplayer_initialize_video_roi(player);
4700 /* set player state to null */
4701 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4702 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4706 return MM_ERROR_NONE;
4710 g_mutex_clear(&player->fsink_lock);
4711 /* free update tag lock */
4712 g_mutex_clear(&player->update_tag_lock);
4713 g_queue_free(player->bus_msg_q);
4714 player->bus_msg_q = NULL;
4715 /* free gapless play thread */
4716 if (player->gapless_play_thread) {
4717 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4718 player->gapless_play_thread_exit = TRUE;
4719 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4720 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4722 g_thread_join(player->gapless_play_thread);
4723 player->gapless_play_thread = NULL;
4725 g_mutex_clear(&player->gapless_play_thread_mutex);
4726 g_cond_clear(&player->gapless_play_thread_cond);
4729 /* release attributes */
4730 _mmplayer_deconstruct_attribute(handle);
4738 __mmplayer_init_gstreamer(mmplayer_t *player)
4740 static gboolean initialized = FALSE;
4741 static const int max_argc = 50;
4743 gchar **argv = NULL;
4744 gchar **argv2 = NULL;
4750 LOGD("gstreamer already initialized.");
4755 argc = malloc(sizeof(int));
4756 argv = malloc(sizeof(gchar *) * max_argc);
4757 argv2 = malloc(sizeof(gchar *) * max_argc);
4759 if (!argc || !argv || !argv2)
4762 memset(argv, 0, sizeof(gchar *) * max_argc);
4763 memset(argv2, 0, sizeof(gchar *) * max_argc);
4767 argv[0] = g_strdup("mmplayer");
4770 for (i = 0; i < 5; i++) {
4771 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4772 if (strlen(player->ini.gst_param[i]) > 0) {
4773 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4778 /* we would not do fork for scanning plugins */
4779 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4782 /* check disable registry scan */
4783 if (player->ini.skip_rescan) {
4784 argv[*argc] = g_strdup("--gst-disable-registry-update");
4788 /* check disable segtrap */
4789 if (player->ini.disable_segtrap) {
4790 argv[*argc] = g_strdup("--gst-disable-segtrap");
4794 LOGD("initializing gstreamer with following parameter");
4795 LOGD("argc : %d", *argc);
4798 for (i = 0; i < arg_count; i++) {
4800 LOGD("argv[%d] : %s", i, argv2[i]);
4803 /* initializing gstreamer */
4804 if (!gst_init_check(argc, &argv, &err)) {
4805 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4812 for (i = 0; i < arg_count; i++) {
4814 LOGD("release - argv[%d] : %s", i, argv2[i]);
4816 MMPLAYER_FREEIF(argv2[i]);
4819 MMPLAYER_FREEIF(argv);
4820 MMPLAYER_FREEIF(argv2);
4821 MMPLAYER_FREEIF(argc);
4831 for (i = 0; i < arg_count; i++) {
4832 LOGD("free[%d] : %s", i, argv2[i]);
4833 MMPLAYER_FREEIF(argv2[i]);
4836 MMPLAYER_FREEIF(argv);
4837 MMPLAYER_FREEIF(argv2);
4838 MMPLAYER_FREEIF(argc);
4844 __mmplayer_check_async_state_transition(mmplayer_t *player)
4846 GstState element_state = GST_STATE_VOID_PENDING;
4847 GstState element_pending_state = GST_STATE_VOID_PENDING;
4848 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4849 GstElement *element = NULL;
4850 gboolean async = FALSE;
4852 /* check player handle */
4853 MMPLAYER_RETURN_IF_FAIL(player &&
4855 player->pipeline->mainbin &&
4856 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4859 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4861 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4862 LOGD("don't need to check the pipeline state");
4866 MMPLAYER_PRINT_STATE(player);
4868 /* wait for state transition */
4869 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4870 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4872 if (ret == GST_STATE_CHANGE_FAILURE) {
4873 LOGE(" [%s] state : %s pending : %s",
4874 GST_ELEMENT_NAME(element),
4875 gst_element_state_get_name(element_state),
4876 gst_element_state_get_name(element_pending_state));
4878 /* dump state of all element */
4879 _mmplayer_dump_pipeline_state(player);
4884 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4889 _mmplayer_destroy(MMHandleType handle)
4891 mmplayer_t *player = MM_PLAYER_CAST(handle);
4895 /* check player handle */
4896 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4898 /* destroy can called at anytime */
4899 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4901 /* check async state transition */
4902 __mmplayer_check_async_state_transition(player);
4904 /* release gapless play thread */
4905 if (player->gapless_play_thread) {
4906 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4907 player->gapless_play_thread_exit = TRUE;
4908 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4909 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4911 LOGD("waitting for gapless play thread exit");
4912 g_thread_join(player->gapless_play_thread);
4913 g_mutex_clear(&player->gapless_play_thread_mutex);
4914 g_cond_clear(&player->gapless_play_thread_cond);
4915 LOGD("gapless play thread released");
4918 _mmplayer_release_video_capture(player);
4920 /* de-initialize resource manager */
4921 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4922 player->resource_manager))
4923 LOGE("failed to deinitialize resource manager");
4925 /* release pipeline */
4926 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4927 LOGE("failed to destory pipeline");
4928 return MM_ERROR_PLAYER_INTERNAL;
4931 g_queue_free(player->bus_msg_q);
4933 /* release subtitle info lock and cond */
4934 g_mutex_clear(&player->subtitle_info_mutex);
4935 g_cond_clear(&player->subtitle_info_cond);
4937 __mmplayer_release_dump_list(player->dump_list);
4939 /* release miscellaneous information */
4940 __mmplayer_release_misc(player);
4942 /* release miscellaneous information.
4943 these info needs to be released after pipeline is destroyed. */
4944 __mmplayer_release_misc_post(player);
4946 /* release attributes */
4947 _mmplayer_deconstruct_attribute(handle);
4950 g_mutex_clear(&player->fsink_lock);
4953 g_mutex_clear(&player->update_tag_lock);
4955 /* release video bo lock and cond */
4956 g_mutex_clear(&player->video_bo_mutex);
4957 g_cond_clear(&player->video_bo_cond);
4961 return MM_ERROR_NONE;
4965 _mmplayer_realize(MMHandleType hplayer)
4967 mmplayer_t *player = (mmplayer_t *)hplayer;
4970 MMHandleType attrs = 0;
4971 int ret = MM_ERROR_NONE;
4975 /* check player handle */
4976 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4978 /* check current state */
4979 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4981 attrs = MMPLAYER_GET_ATTRS(player);
4983 LOGE("fail to get attributes.");
4984 return MM_ERROR_PLAYER_INTERNAL;
4986 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4987 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4989 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4990 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4992 if (ret != MM_ERROR_NONE) {
4993 LOGE("failed to parse profile");
4998 if (uri && (strstr(uri, "es_buff://"))) {
4999 if (strstr(uri, "es_buff://push_mode"))
5000 player->es_player_push_mode = TRUE;
5002 player->es_player_push_mode = FALSE;
5005 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5006 LOGW("mms protocol is not supported format.");
5007 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5010 if (MMPLAYER_IS_STREAMING(player))
5011 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5013 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5015 player->smooth_streaming = FALSE;
5016 player->videodec_linked = 0;
5017 player->audiodec_linked = 0;
5018 player->textsink_linked = 0;
5019 player->is_external_subtitle_present = FALSE;
5020 player->is_external_subtitle_added_now = FALSE;
5021 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5022 player->video360_metadata.is_spherical = -1;
5023 player->is_openal_plugin_used = FALSE;
5024 player->demux_pad_index = 0;
5025 player->subtitle_language_list = NULL;
5026 player->is_subtitle_force_drop = FALSE;
5028 _mmplayer_track_initialize(player);
5029 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5031 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5032 gint prebuffer_ms = 0, rebuffer_ms = 0;
5034 player->streamer = _mm_player_streaming_create();
5035 _mm_player_streaming_initialize(player->streamer, TRUE);
5037 mm_attrs_multiple_get(player->attrs, NULL,
5038 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5039 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5041 if (prebuffer_ms > 0) {
5042 prebuffer_ms = MAX(prebuffer_ms, 1000);
5043 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5046 if (rebuffer_ms > 0) {
5047 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5048 rebuffer_ms = MAX(rebuffer_ms, 1000);
5049 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5052 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5053 player->streamer->buffering_req.rebuffer_time);
5056 /* realize pipeline */
5057 ret = __mmplayer_gst_realize(player);
5058 if (ret != MM_ERROR_NONE)
5059 LOGE("fail to realize the player.");
5061 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5069 _mmplayer_unrealize(MMHandleType hplayer)
5071 mmplayer_t *player = (mmplayer_t *)hplayer;
5072 int ret = MM_ERROR_NONE;
5076 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5078 MMPLAYER_CMD_UNLOCK(player);
5079 /* destroy the gst bus msg thread which is created during realize.
5080 this funct have to be called before getting cmd lock. */
5081 _mmplayer_bus_msg_thread_destroy(player);
5082 MMPLAYER_CMD_LOCK(player);
5084 /* check current state */
5085 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5087 /* check async state transition */
5088 __mmplayer_check_async_state_transition(player);
5090 /* unrealize pipeline */
5091 ret = __mmplayer_gst_unrealize(player);
5093 if (!player->interrupted_by_resource) {
5094 int rm_ret = MM_ERROR_NONE;
5095 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5097 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5098 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5099 if (rm_ret != MM_ERROR_NONE)
5100 LOGE("failed to release [%d] resources", res_idx);
5109 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5111 mmplayer_t *player = (mmplayer_t *)hplayer;
5113 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5115 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5119 _mmplayer_get_state(MMHandleType hplayer, int *state)
5121 mmplayer_t *player = (mmplayer_t *)hplayer;
5123 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5125 *state = MMPLAYER_CURRENT_STATE(player);
5127 return MM_ERROR_NONE;
5131 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5133 GstElement *vol_element = NULL;
5134 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5137 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5138 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5140 /* check pipeline handle */
5141 if (!player->pipeline || !player->pipeline->audiobin) {
5142 LOGD("'%s' will be applied when audiobin is created", prop_name);
5144 /* NOTE : stored value will be used in create_audiobin
5145 * returning MM_ERROR_NONE here makes application to able to
5146 * set audio volume or mute at anytime.
5148 return MM_ERROR_NONE;
5151 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5152 volume_elem_id = MMPLAYER_A_SINK;
5154 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5156 LOGE("failed to get vol element %d", volume_elem_id);
5157 return MM_ERROR_PLAYER_INTERNAL;
5160 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5162 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5163 LOGE("there is no '%s' property", prop_name);
5164 return MM_ERROR_PLAYER_INTERNAL;
5167 if (!strcmp(prop_name, "volume")) {
5168 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5169 } else if (!strcmp(prop_name, "mute")) {
5170 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5172 LOGE("invalid property %s", prop_name);
5173 return MM_ERROR_PLAYER_INTERNAL;
5176 return MM_ERROR_NONE;
5180 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5182 int ret = MM_ERROR_NONE;
5183 mmplayer_t *player = (mmplayer_t *)hplayer;
5186 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5188 LOGD("volume = %f", volume);
5190 /* invalid factor range or not */
5191 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5192 LOGE("Invalid volume value");
5193 return MM_ERROR_INVALID_ARGUMENT;
5196 player->sound.volume = volume;
5198 ret = __mmplayer_gst_set_volume_property(player, "volume");
5205 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5207 mmplayer_t *player = (mmplayer_t *)hplayer;
5211 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5212 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5214 *volume = player->sound.volume;
5216 LOGD("current vol = %f", *volume);
5219 return MM_ERROR_NONE;
5223 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5225 int ret = MM_ERROR_NONE;
5226 mmplayer_t *player = (mmplayer_t *)hplayer;
5229 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5231 LOGD("mute = %d", mute);
5233 player->sound.mute = mute;
5235 ret = __mmplayer_gst_set_volume_property(player, "mute");
5242 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5244 mmplayer_t *player = (mmplayer_t *)hplayer;
5248 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5249 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5251 *mute = player->sound.mute;
5253 LOGD("current mute = %d", *mute);
5257 return MM_ERROR_NONE;
5261 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5263 mmplayer_t *player = (mmplayer_t *)hplayer;
5267 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5269 player->audio_stream_changed_cb = callback;
5270 player->audio_stream_changed_cb_user_param = user_param;
5271 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5275 return MM_ERROR_NONE;
5279 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5281 mmplayer_t *player = (mmplayer_t *)hplayer;
5285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5287 player->audio_decoded_cb = callback;
5288 player->audio_decoded_cb_user_param = user_param;
5289 player->audio_extract_opt = opt;
5290 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5294 return MM_ERROR_NONE;
5298 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5300 mmplayer_t *player = (mmplayer_t *)hplayer;
5304 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5306 if (callback && !player->bufmgr)
5307 player->bufmgr = tbm_bufmgr_init(-1);
5309 player->set_mode.video_export = (callback) ? true : false;
5310 player->video_decoded_cb = callback;
5311 player->video_decoded_cb_user_param = user_param;
5313 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5317 return MM_ERROR_NONE;
5321 _mmplayer_start(MMHandleType hplayer)
5323 mmplayer_t *player = (mmplayer_t *)hplayer;
5324 gint ret = MM_ERROR_NONE;
5328 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5330 /* check current state */
5331 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5333 /* start pipeline */
5334 ret = _mmplayer_gst_start(player);
5335 if (ret != MM_ERROR_NONE)
5336 LOGE("failed to start player.");
5338 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5339 LOGD("force playing start even during buffering");
5340 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5348 /* NOTE: post "not supported codec message" to application
5349 * when one codec is not found during AUTOPLUGGING in MSL.
5350 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5351 * And, if any codec is not found, don't send message here.
5352 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5355 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5357 MMMessageParamType msg_param;
5358 memset(&msg_param, 0, sizeof(MMMessageParamType));
5359 gboolean post_msg_direct = FALSE;
5363 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5365 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5366 player->not_supported_codec, player->can_support_codec);
5368 if (player->not_found_demuxer) {
5369 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5370 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5372 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5373 MMPLAYER_FREEIF(msg_param.data);
5375 return MM_ERROR_NONE;
5378 if (player->not_supported_codec) {
5379 if (player->can_support_codec) {
5380 // There is one codec to play
5381 post_msg_direct = TRUE;
5383 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5384 post_msg_direct = TRUE;
5387 if (post_msg_direct) {
5388 MMMessageParamType msg_param;
5389 memset(&msg_param, 0, sizeof(MMMessageParamType));
5391 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5392 LOGW("not found AUDIO codec, posting error code to application.");
5394 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5395 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5396 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5397 LOGW("not found VIDEO codec, posting error code to application.");
5399 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5400 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5403 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5405 MMPLAYER_FREEIF(msg_param.data);
5407 return MM_ERROR_NONE;
5409 // no any supported codec case
5410 LOGW("not found any codec, posting error code to application.");
5412 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5413 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5414 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5416 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5417 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5420 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5422 MMPLAYER_FREEIF(msg_param.data);
5428 return MM_ERROR_NONE;
5432 __mmplayer_check_pipeline(mmplayer_t *player)
5434 GstState element_state = GST_STATE_VOID_PENDING;
5435 GstState element_pending_state = GST_STATE_VOID_PENDING;
5437 int ret = MM_ERROR_NONE;
5439 if (!player->gapless.reconfigure)
5442 LOGW("pipeline is under construction.");
5444 MMPLAYER_PLAYBACK_LOCK(player);
5445 MMPLAYER_PLAYBACK_UNLOCK(player);
5447 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5449 /* wait for state transition */
5450 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5451 if (ret == GST_STATE_CHANGE_FAILURE)
5452 LOGE("failed to change pipeline state within %d sec", timeout);
5455 /* NOTE : it should be able to call 'stop' anytime*/
5457 _mmplayer_stop(MMHandleType hplayer)
5459 mmplayer_t *player = (mmplayer_t *)hplayer;
5460 int ret = MM_ERROR_NONE;
5464 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5466 /* check current state */
5467 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5469 /* check pipline building state */
5470 __mmplayer_check_pipeline(player);
5471 __mmplayer_reset_gapless_state(player);
5473 /* NOTE : application should not wait for EOS after calling STOP */
5474 _mmplayer_cancel_eos_timer(player);
5477 player->seek_state = MMPLAYER_SEEK_NONE;
5480 ret = _mmplayer_gst_stop(player);
5482 if (ret != MM_ERROR_NONE)
5483 LOGE("failed to stop player.");
5491 _mmplayer_pause(MMHandleType hplayer)
5493 mmplayer_t *player = (mmplayer_t *)hplayer;
5494 gint64 pos_nsec = 0;
5495 gboolean async = FALSE;
5496 gint ret = MM_ERROR_NONE;
5500 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5502 /* check current state */
5503 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5505 /* check pipline building state */
5506 __mmplayer_check_pipeline(player);
5508 switch (MMPLAYER_CURRENT_STATE(player)) {
5509 case MM_PLAYER_STATE_READY:
5511 /* check prepare async or not.
5512 * In the case of streaming playback, it's recommned to avoid blocking wait.
5514 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5515 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5517 /* Changing back sync of rtspsrc to async */
5518 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5519 LOGD("async prepare working mode for rtsp");
5525 case MM_PLAYER_STATE_PLAYING:
5527 /* NOTE : store current point to overcome some bad operation
5528 *(returning zero when getting current position in paused state) of some
5531 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5532 LOGW("getting current position failed in paused");
5534 player->last_position = pos_nsec;
5536 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5537 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5538 This causes problem is position calculation during normal pause resume scenarios also.
5539 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5540 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5541 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5542 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5548 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5549 LOGD("doing async pause in case of ms buff src");
5553 /* pause pipeline */
5554 ret = _mmplayer_gst_pause(player, async);
5556 if (ret != MM_ERROR_NONE)
5557 LOGE("failed to pause player. ret : 0x%x", ret);
5559 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5560 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5561 LOGE("failed to update display_rotation");
5569 /* in case of streaming, pause could take long time.*/
5571 _mmplayer_abort_pause(MMHandleType hplayer)
5573 mmplayer_t *player = (mmplayer_t *)hplayer;
5574 int ret = MM_ERROR_NONE;
5578 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5580 player->pipeline->mainbin,
5581 MM_ERROR_PLAYER_NOT_INITIALIZED);
5583 LOGD("set the pipeline state to READY");
5585 /* set state to READY */
5586 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5587 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5588 if (ret != MM_ERROR_NONE) {
5589 LOGE("fail to change state to READY");
5590 return MM_ERROR_PLAYER_INTERNAL;
5593 LOGD("succeeded in changing state to READY");
5598 _mmplayer_resume(MMHandleType hplayer)
5600 mmplayer_t *player = (mmplayer_t *)hplayer;
5601 int ret = MM_ERROR_NONE;
5602 gboolean async = FALSE;
5606 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5608 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5609 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5610 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5614 /* Changing back sync mode rtspsrc to async */
5615 LOGD("async resume for rtsp case");
5619 /* check current state */
5620 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5622 ret = _mmplayer_gst_resume(player, async);
5623 if (ret != MM_ERROR_NONE)
5624 LOGE("failed to resume player.");
5626 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5627 LOGD("force resume even during buffering");
5628 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5637 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5639 mmplayer_t *player = (mmplayer_t *)hplayer;
5640 gint64 pos_nsec = 0;
5641 int ret = MM_ERROR_NONE;
5643 signed long long start = 0, stop = 0;
5644 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5647 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5648 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5650 /* The sound of video is not supported under 0.0 and over 2.0. */
5651 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5652 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5655 _mmplayer_set_mute(hplayer, mute);
5657 if (player->playback_rate == rate)
5658 return MM_ERROR_NONE;
5660 /* If the position is reached at start potion during fast backward, EOS is posted.
5661 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5663 player->playback_rate = rate;
5665 current_state = MMPLAYER_CURRENT_STATE(player);
5667 if (current_state != MM_PLAYER_STATE_PAUSED)
5668 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5670 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5672 if ((current_state == MM_PLAYER_STATE_PAUSED)
5673 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5674 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5675 pos_nsec = player->last_position;
5680 stop = GST_CLOCK_TIME_NONE;
5682 start = GST_CLOCK_TIME_NONE;
5686 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5687 player->playback_rate,
5689 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5690 GST_SEEK_TYPE_SET, start,
5691 GST_SEEK_TYPE_SET, stop)) {
5692 LOGE("failed to set speed playback");
5693 return MM_ERROR_PLAYER_SEEK;
5696 LOGD("succeeded to set speed playback as %0.1f", rate);
5700 return MM_ERROR_NONE;;
5704 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5706 mmplayer_t *player = (mmplayer_t *)hplayer;
5707 int ret = MM_ERROR_NONE;
5711 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5713 /* check pipline building state */
5714 __mmplayer_check_pipeline(player);
5716 ret = _mmplayer_gst_set_position(player, position, FALSE);
5724 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5726 mmplayer_t *player = (mmplayer_t *)hplayer;
5727 int ret = MM_ERROR_NONE;
5729 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5730 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5732 if (g_strrstr(player->type, "video/mpegts"))
5733 __mmplayer_update_duration_value(player);
5735 *duration = player->duration;
5740 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5742 mmplayer_t *player = (mmplayer_t *)hplayer;
5743 int ret = MM_ERROR_NONE;
5745 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5747 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5753 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5755 mmplayer_t *player = (mmplayer_t *)hplayer;
5756 int ret = MM_ERROR_NONE;
5760 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5762 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5770 __mmplayer_is_midi_type(gchar *str_caps)
5772 if ((g_strrstr(str_caps, "audio/midi")) ||
5773 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5774 (g_strrstr(str_caps, "application/x-smaf")) ||
5775 (g_strrstr(str_caps, "audio/x-imelody")) ||
5776 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5777 (g_strrstr(str_caps, "audio/xmf")) ||
5778 (g_strrstr(str_caps, "audio/mxmf"))) {
5787 __mmplayer_is_only_mp3_type(gchar *str_caps)
5789 if (g_strrstr(str_caps, "application/x-id3") ||
5790 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5796 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5798 GstStructure *caps_structure = NULL;
5799 gint samplerate = 0;
5803 MMPLAYER_RETURN_IF_FAIL(player && caps);
5805 caps_structure = gst_caps_get_structure(caps, 0);
5807 /* set stream information */
5808 gst_structure_get_int(caps_structure, "rate", &samplerate);
5809 gst_structure_get_int(caps_structure, "channels", &channels);
5811 mm_player_set_attribute((MMHandleType)player, NULL,
5812 "content_audio_samplerate", samplerate,
5813 "content_audio_channels", channels, NULL);
5815 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5819 __mmplayer_update_content_type_info(mmplayer_t *player)
5822 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5824 if (__mmplayer_is_midi_type(player->type)) {
5825 player->bypass_audio_effect = TRUE;
5829 if (!player->streamer) {
5830 LOGD("no need to check streaming type");
5834 if (g_strrstr(player->type, "application/x-hls")) {
5835 /* If it can't know exact type when it parses uri because of redirection case,
5836 * it will be fixed by typefinder or when doing autoplugging.
5838 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5839 player->streamer->is_adaptive_streaming = TRUE;
5840 } else if (g_strrstr(player->type, "application/dash+xml")) {
5841 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5842 player->streamer->is_adaptive_streaming = TRUE;
5845 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5846 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5847 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5849 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5850 if (player->streamer->is_adaptive_streaming)
5851 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5853 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5857 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5862 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5863 GstCaps *caps, gpointer data)
5865 mmplayer_t *player = (mmplayer_t *)data;
5870 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5872 /* store type string */
5873 MMPLAYER_FREEIF(player->type);
5874 player->type = gst_caps_to_string(caps);
5876 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5877 player, player->type, probability, gst_caps_get_size(caps));
5879 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5880 (g_strrstr(player->type, "audio/x-raw-int"))) {
5881 LOGE("not support media format");
5883 if (player->msg_posted == FALSE) {
5884 MMMessageParamType msg_param;
5885 memset(&msg_param, 0, sizeof(MMMessageParamType));
5887 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5888 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5890 /* don't post more if one was sent already */
5891 player->msg_posted = TRUE;
5896 __mmplayer_update_content_type_info(player);
5898 pad = gst_element_get_static_pad(tf, "src");
5900 LOGE("fail to get typefind src pad.");
5904 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5905 gboolean async = FALSE;
5906 LOGE("failed to autoplug %s", player->type);
5908 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5910 if (async && player->msg_posted == FALSE)
5911 __mmplayer_handle_missed_plugin(player);
5915 gst_object_unref(GST_OBJECT(pad));
5923 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5925 GstElement *decodebin = NULL;
5929 /* create decodebin */
5930 decodebin = gst_element_factory_make("decodebin", NULL);
5933 LOGE("fail to create decodebin");
5937 /* raw pad handling signal */
5938 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5939 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5941 /* no-more-pad pad handling signal */
5942 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5943 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5945 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5946 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5948 /* This signal is emitted when a pad for which there is no further possible
5949 decoding is added to the decodebin.*/
5950 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5951 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5953 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5954 before looking for any elements that can handle that stream.*/
5955 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5956 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5958 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5959 before looking for any elements that can handle that stream.*/
5960 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5961 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5963 /* This signal is emitted once decodebin has finished decoding all the data.*/
5964 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5965 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5967 /* This signal is emitted when a element is added to the bin.*/
5968 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5969 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5976 __mmplayer_gst_make_queue2(mmplayer_t *player)
5978 GstElement *queue2 = NULL;
5979 gint64 dur_bytes = 0L;
5980 mmplayer_gst_element_t *mainbin = NULL;
5981 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5984 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5986 mainbin = player->pipeline->mainbin;
5988 queue2 = gst_element_factory_make("queue2", "queue2");
5990 LOGE("failed to create buffering queue element");
5994 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5995 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5997 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5999 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6000 * skip the pull mode(file or ring buffering) setting. */
6001 if (dur_bytes > 0) {
6002 if (!g_strrstr(player->type, "video/mpegts")) {
6003 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6004 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6010 _mm_player_streaming_set_queue2(player->streamer,
6014 (guint64)dur_bytes); /* no meaning at the moment */
6020 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6022 mmplayer_gst_element_t *mainbin = NULL;
6023 GstElement *decodebin = NULL;
6024 GstElement *queue2 = NULL;
6025 GstPad *sinkpad = NULL;
6026 GstPad *qsrcpad = NULL;
6029 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6031 mainbin = player->pipeline->mainbin;
6033 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6035 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6036 LOGW("need to check: muxed buffer is not null");
6039 queue2 = __mmplayer_gst_make_queue2(player);
6041 LOGE("failed to make queue2");
6045 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6046 LOGE("failed to add buffering queue");
6050 sinkpad = gst_element_get_static_pad(queue2, "sink");
6051 qsrcpad = gst_element_get_static_pad(queue2, "src");
6053 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6054 LOGE("failed to link [%s:%s]-[%s:%s]",
6055 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6059 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6060 LOGE("failed to sync queue2 state with parent");
6064 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6065 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6069 gst_object_unref(GST_OBJECT(sinkpad));
6073 /* create decodebin */
6074 decodebin = _mmplayer_gst_make_decodebin(player);
6076 LOGE("failed to make decodebin");
6080 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6081 LOGE("failed to add decodebin");
6085 /* to force caps on the decodebin element and avoid reparsing stuff by
6086 * typefind. It also avoids a deadlock in the way typefind activates pads in
6087 * the state change */
6088 g_object_set(decodebin, "sink-caps", caps, NULL);
6090 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6092 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6093 LOGE("failed to link [%s:%s]-[%s:%s]",
6094 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6098 gst_object_unref(GST_OBJECT(sinkpad));
6100 gst_object_unref(GST_OBJECT(qsrcpad));
6103 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6104 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6106 /* set decodebin property about buffer in streaming playback. *
6107 * in case of HLS/DASH, it does not need to have big buffer *
6108 * because it is kind of adaptive streaming. */
6109 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6110 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6111 gint high_percent = 0;
6113 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6114 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6116 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6118 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6120 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6121 "high-percent", high_percent,
6122 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6123 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6124 "max-size-buffers", 0, NULL); // disable or automatic
6127 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6128 LOGE("failed to sync decodebin state with parent");
6139 gst_object_unref(GST_OBJECT(sinkpad));
6142 gst_object_unref(GST_OBJECT(qsrcpad));
6145 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6146 * You need to explicitly set elements to the NULL state before
6147 * dropping the final reference, to allow them to clean up.
6149 gst_element_set_state(queue2, GST_STATE_NULL);
6151 /* And, it still has a parent "player".
6152 * You need to let the parent manage the object instead of unreffing the object directly.
6154 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6155 gst_object_unref(queue2);
6160 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6161 * You need to explicitly set elements to the NULL state before
6162 * dropping the final reference, to allow them to clean up.
6164 gst_element_set_state(decodebin, GST_STATE_NULL);
6166 /* And, it still has a parent "player".
6167 * You need to let the parent manage the object instead of unreffing the object directly.
6170 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6171 gst_object_unref(decodebin);
6179 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6183 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6184 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6186 LOGD("class : %s, mime : %s", factory_class, mime);
6188 /* add missing plugin */
6189 /* NOTE : msl should check missing plugin for image mime type.
6190 * Some motion jpeg clips can have playable audio track.
6191 * So, msl have to play audio after displaying popup written video format not supported.
6193 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6194 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6195 LOGD("not found demuxer");
6196 player->not_found_demuxer = TRUE;
6197 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6203 if (!g_strrstr(factory_class, "Demuxer")) {
6204 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6205 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6206 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6208 /* check that clip have multi tracks or not */
6209 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6210 LOGD("video plugin is already linked");
6212 LOGW("add VIDEO to missing plugin");
6213 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6214 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6216 } else if (g_str_has_prefix(mime, "audio")) {
6217 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6218 LOGD("audio plugin is already linked");
6220 LOGW("add AUDIO to missing plugin");
6221 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6222 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6230 return MM_ERROR_NONE;
6234 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6236 mmplayer_t *player = (mmplayer_t *)data;
6240 MMPLAYER_RETURN_IF_FAIL(player);
6242 /* remove fakesink. */
6243 if (!_mmplayer_gst_remove_fakesink(player,
6244 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6245 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6246 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6247 * source element are not same. To overcome this situation, this function will called
6248 * several places and several times. Therefore, this is not an error case.
6253 LOGD("[handle: %p] pipeline has completely constructed", player);
6255 if ((player->ini.async_start) &&
6256 (player->msg_posted == FALSE) &&
6257 (player->cmd >= MMPLAYER_COMMAND_START))
6258 __mmplayer_handle_missed_plugin(player);
6260 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6264 __mmplayer_check_profile(void)
6267 static int profile_tv = -1;
6269 if (__builtin_expect(profile_tv != -1, 1))
6272 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6273 switch (*profileName) {
6288 __mmplayer_get_next_uri(mmplayer_t *player)
6290 mmplayer_parse_profile_t profile;
6292 guint num_of_list = 0;
6295 num_of_list = g_list_length(player->uri_info.uri_list);
6296 uri_idx = player->uri_info.uri_idx;
6298 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6299 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6300 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6302 LOGW("next uri does not exist");
6306 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6307 LOGE("failed to parse profile");
6311 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6312 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6313 LOGW("uri type is not supported(%d)", profile.uri_type);
6317 LOGD("success to find next uri %d", uri_idx);
6321 if (!uri || uri_idx == num_of_list) {
6322 LOGE("failed to find next uri");
6326 player->uri_info.uri_idx = uri_idx;
6327 if (mm_player_set_attribute((MMHandleType)player, NULL,
6328 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6329 LOGE("failed to set attribute");
6333 SECURE_LOGD("next playback uri: %s", uri);
6338 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6340 #define REPEAT_COUNT_INFINITE -1
6341 #define REPEAT_COUNT_MIN 2
6342 #define ORIGINAL_URI_ONLY 1
6344 MMHandleType attrs = 0;
6348 guint num_of_uri = 0;
6349 int profile_tv = -1;
6353 LOGD("checking for gapless play option");
6355 if (player->build_audio_offload) {
6356 LOGE("offload path is not supportable.");
6360 if (player->pipeline->textbin) {
6361 LOGE("subtitle path is enabled. gapless play is not supported.");
6365 attrs = MMPLAYER_GET_ATTRS(player);
6367 LOGE("fail to get attributes.");
6371 mm_attrs_multiple_get(player->attrs, NULL,
6372 "content_video_found", &video,
6373 "profile_play_count", &count,
6374 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6376 /* gapless playback is not supported in case of video at TV profile. */
6377 profile_tv = __mmplayer_check_profile();
6378 if (profile_tv && video) {
6379 LOGW("not support video gapless playback");
6383 /* check repeat count in case of audio */
6385 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6386 LOGW("gapless is disabled");
6390 num_of_uri = g_list_length(player->uri_info.uri_list);
6392 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6394 if (num_of_uri == ORIGINAL_URI_ONLY) {
6395 /* audio looping path */
6396 if (count >= REPEAT_COUNT_MIN) {
6397 /* decrease play count */
6398 /* we succeeded to rewind. update play count and then wait for next EOS */
6400 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6401 } else if (count != REPEAT_COUNT_INFINITE) {
6402 LOGD("there is no next uri and no repeat");
6405 LOGD("looping cnt %d", count);
6407 /* gapless playback path */
6408 if (!__mmplayer_get_next_uri(player)) {
6409 LOGE("failed to get next uri");
6416 LOGE("unable to play gapless path. EOS will be posted soon");
6421 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6423 mmplayer_selector_t *selector = &player->selector[type];
6424 mmplayer_gst_element_t *sinkbin = NULL;
6425 main_element_id_e selectorId = MMPLAYER_M_NUM;
6426 main_element_id_e sinkId = MMPLAYER_M_NUM;
6427 GstPad *srcpad = NULL;
6428 GstPad *sinkpad = NULL;
6429 gboolean send_notice = FALSE;
6432 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6434 LOGD("type %d", type);
6437 case MM_PLAYER_TRACK_TYPE_AUDIO:
6438 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6439 sinkId = MMPLAYER_A_BIN;
6440 sinkbin = player->pipeline->audiobin;
6442 case MM_PLAYER_TRACK_TYPE_VIDEO:
6443 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6444 sinkId = MMPLAYER_V_BIN;
6445 sinkbin = player->pipeline->videobin;
6448 case MM_PLAYER_TRACK_TYPE_TEXT:
6449 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6450 sinkId = MMPLAYER_T_BIN;
6451 sinkbin = player->pipeline->textbin;
6454 LOGE("requested type is not supportable");
6459 if (player->pipeline->mainbin[selectorId].gst) {
6462 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6464 if (selector->event_probe_id != 0)
6465 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6466 selector->event_probe_id = 0;
6468 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6469 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6471 if (srcpad && sinkpad) {
6472 /* after getting drained signal there is no data flows, so no need to do pad_block */
6473 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6474 gst_pad_unlink(srcpad, sinkpad);
6476 /* send custom event to sink pad to handle it at video sink */
6478 LOGD("send custom event to sinkpad");
6479 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6480 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6481 gst_pad_send_event(sinkpad, event);
6485 gst_object_unref(sinkpad);
6488 gst_object_unref(srcpad);
6491 LOGD("selector release");
6493 /* release and unref requests pad from the selector */
6494 for (n = 0; n < selector->channels->len; n++) {
6495 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6496 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6498 g_ptr_array_set_size(selector->channels, 0);
6500 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6501 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6503 player->pipeline->mainbin[selectorId].gst = NULL;
6511 __mmplayer_deactivate_old_path(mmplayer_t *player)
6514 MMPLAYER_RETURN_IF_FAIL(player);
6516 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6517 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6518 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6519 LOGE("deactivate selector error");
6523 _mmplayer_track_destroy(player);
6524 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6526 if (player->streamer) {
6527 _mm_player_streaming_initialize(player->streamer, FALSE);
6528 _mm_player_streaming_destroy(player->streamer);
6529 player->streamer = NULL;
6532 MMPLAYER_PLAYBACK_LOCK(player);
6533 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6540 if (!player->msg_posted) {
6541 MMMessageParamType msg = {0,};
6544 msg.code = MM_ERROR_PLAYER_INTERNAL;
6545 LOGE("gapless_uri_play> deactivate error");
6547 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6548 player->msg_posted = TRUE;
6554 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6556 int result = MM_ERROR_NONE;
6557 mmplayer_t *player = (mmplayer_t *)hplayer;
6560 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6561 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6563 if (mm_player_set_attribute(hplayer, NULL,
6564 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6565 LOGE("failed to set attribute");
6566 result = MM_ERROR_PLAYER_INTERNAL;
6568 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6569 LOGE("failed to add the original uri in the uri list.");
6577 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6579 mmplayer_t *player = (mmplayer_t *)hplayer;
6580 guint num_of_list = 0;
6584 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6585 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6587 if (player->pipeline && player->pipeline->textbin) {
6588 LOGE("subtitle path is enabled.");
6589 return MM_ERROR_PLAYER_INVALID_STATE;
6592 num_of_list = g_list_length(player->uri_info.uri_list);
6594 if (is_first_path) {
6595 if (num_of_list == 0) {
6596 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6597 SECURE_LOGD("add original path : %s", uri);
6599 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6600 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6602 SECURE_LOGD("change original path : %s", uri);
6605 MMHandleType attrs = 0;
6606 attrs = MMPLAYER_GET_ATTRS(player);
6608 if (num_of_list == 0) {
6609 char *original_uri = NULL;
6612 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6614 if (!original_uri) {
6615 LOGE("there is no original uri.");
6616 return MM_ERROR_PLAYER_INVALID_STATE;
6619 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6620 player->uri_info.uri_idx = 0;
6622 SECURE_LOGD("add original path at first : %s", original_uri);
6626 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6627 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6631 return MM_ERROR_NONE;
6635 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6637 mmplayer_t *player = (mmplayer_t *)hplayer;
6638 char *next_uri = NULL;
6639 guint num_of_list = 0;
6642 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6644 num_of_list = g_list_length(player->uri_info.uri_list);
6646 if (num_of_list > 0) {
6647 gint uri_idx = player->uri_info.uri_idx;
6649 if (uri_idx < num_of_list-1)
6654 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6655 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6657 *uri = g_strdup(next_uri);
6661 return MM_ERROR_NONE;
6665 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6666 GstCaps *caps, gpointer data)
6668 mmplayer_t *player = (mmplayer_t *)data;
6669 const gchar *klass = NULL;
6670 const gchar *mime = NULL;
6671 gchar *caps_str = NULL;
6673 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6674 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6675 caps_str = gst_caps_to_string(caps);
6677 LOGW("unknown type of caps : %s from %s",
6678 caps_str, GST_ELEMENT_NAME(elem));
6680 MMPLAYER_FREEIF(caps_str);
6682 /* There is no available codec. */
6683 __mmplayer_check_not_supported_codec(player, klass, mime);
6687 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6688 GstCaps *caps, gpointer data)
6690 mmplayer_t *player = (mmplayer_t *)data;
6691 const char *mime = NULL;
6692 gboolean ret = TRUE;
6694 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6695 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6697 if (g_str_has_prefix(mime, "audio")) {
6698 GstStructure *caps_structure = NULL;
6699 gint samplerate = 0;
6701 gchar *caps_str = NULL;
6703 caps_structure = gst_caps_get_structure(caps, 0);
6704 gst_structure_get_int(caps_structure, "rate", &samplerate);
6705 gst_structure_get_int(caps_structure, "channels", &channels);
6707 if ((channels > 0 && samplerate == 0)) {
6708 LOGD("exclude audio...");
6712 caps_str = gst_caps_to_string(caps);
6713 /* set it directly because not sent by TAG */
6714 if (g_strrstr(caps_str, "mobile-xmf"))
6715 mm_player_set_attribute((MMHandleType)player, NULL,
6716 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6718 MMPLAYER_FREEIF(caps_str);
6719 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6720 MMMessageParamType msg_param;
6721 memset(&msg_param, 0, sizeof(MMMessageParamType));
6722 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6723 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6724 LOGD("video file is not supported on this device");
6726 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6727 LOGD("already video linked");
6730 LOGD("found new stream");
6737 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6739 gboolean ret = TRUE;
6740 GDBusConnection *conn = NULL;
6742 GVariant *result = NULL;
6743 const gchar *dbus_device_type = NULL;
6744 const gchar *dbus_ret = NULL;
6747 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6749 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6755 result = g_dbus_connection_call_sync(conn,
6756 "org.pulseaudio.Server",
6757 "/org/pulseaudio/StreamManager",
6758 "org.pulseaudio.StreamManager",
6759 "GetCurrentMediaRoutingPath",
6760 g_variant_new("(s)", "out"),
6761 G_VARIANT_TYPE("(ss)"),
6762 G_DBUS_CALL_FLAGS_NONE,
6766 if (!result || err) {
6767 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6773 /* device type is listed in stream-map.json at mmfw-sysconf */
6774 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6776 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6777 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6782 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6783 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6784 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6785 LOGD("audio offload is supportable");
6791 LOGD("audio offload is not supportable");
6795 g_variant_unref(result);
6796 g_object_unref(conn);
6801 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6803 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6804 gint64 position = 0;
6806 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6807 player->pipeline && player->pipeline->mainbin);
6809 MMPLAYER_CMD_LOCK(player);
6810 current_state = MMPLAYER_CURRENT_STATE(player);
6812 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6813 LOGW("getting current position failed in paused");
6815 _mmplayer_unrealize((MMHandleType)player);
6816 _mmplayer_realize((MMHandleType)player);
6818 _mmplayer_set_position((MMHandleType)player, position);
6820 /* async not to be blocked in streaming case */
6821 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6823 _mmplayer_pause((MMHandleType)player);
6825 if (current_state == MM_PLAYER_STATE_PLAYING)
6826 _mmplayer_start((MMHandleType)player);
6827 MMPLAYER_CMD_UNLOCK(player);
6829 LOGD("rebuilding audio pipeline is completed.");
6832 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6834 mmplayer_t *player = (mmplayer_t *)user_data;
6835 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6836 gboolean is_supportable = FALSE;
6838 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6839 LOGW("failed to get device type");
6841 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6843 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6844 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6845 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6846 LOGD("ignore this dev connected info");
6850 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6851 if (player->build_audio_offload == is_supportable) {
6852 LOGD("keep current pipeline without re-building");
6856 /* rebuild pipeline */
6857 LOGD("re-build pipeline - offload: %d", is_supportable);
6858 player->build_audio_offload = FALSE;
6859 __mmplayer_rebuild_audio_pipeline(player);
6865 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6867 unsigned int id = 0;
6869 if (player->audio_device_cb_id != 0) {
6870 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6874 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6875 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6876 LOGD("added device connected cb (%u)", id);
6877 player->audio_device_cb_id = id;
6879 LOGW("failed to add device connected cb");
6887 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6889 gboolean ret = FALSE;
6890 GstElementFactory *factory = NULL;
6893 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6895 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6896 if (!__mmplayer_is_only_mp3_type(player->type))
6899 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6900 LOGD("there is no audio offload sink");
6904 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6905 LOGW("there is no audio device type to support offload");
6909 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6911 LOGW("there is no installed audio offload sink element");
6914 gst_object_unref(factory);
6916 if (__mmplayer_acquire_hw_resource(player,
6917 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6918 LOGE("failed to acquire audio offload decoder resource");
6922 if (!__mmplayer_add_audio_device_connected_cb(player))
6925 if (!__mmplayer_is_audio_offload_device_type(player))
6928 LOGD("audio offload can be built");
6933 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6939 static GstAutoplugSelectResult
6940 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6942 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6944 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6945 int audio_offload = 0;
6947 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6948 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6950 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6951 LOGD("expose audio path to build offload output path");
6952 player->build_audio_offload = TRUE;
6953 /* update codec info */
6954 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6955 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6956 player->audiodec_linked = 1;
6958 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6962 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6964 LOGD("audio codec type: %d", codec_type);
6965 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6966 /* sw codec will be skipped */
6967 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6968 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6969 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6970 ret = GST_AUTOPLUG_SELECT_SKIP;
6974 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6975 /* hw codec will be skipped */
6976 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6977 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6978 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6979 ret = GST_AUTOPLUG_SELECT_SKIP;
6984 /* set stream information */
6985 if (!player->audiodec_linked)
6986 __mmplayer_set_audio_attrs(player, caps);
6988 /* update codec info */
6989 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6990 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6991 player->audiodec_linked = 1;
6993 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6995 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6997 LOGD("video codec type: %d", codec_type);
6998 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6999 /* sw codec is skipped */
7000 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7001 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7002 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7003 ret = GST_AUTOPLUG_SELECT_SKIP;
7007 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7008 /* hw codec is skipped */
7009 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7010 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7011 ret = GST_AUTOPLUG_SELECT_SKIP;
7016 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7017 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7019 /* mark video decoder for acquire */
7020 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7021 LOGW("video decoder resource is already acquired, skip it.");
7022 ret = GST_AUTOPLUG_SELECT_SKIP;
7026 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7027 LOGE("failed to acquire video decoder resource");
7028 ret = GST_AUTOPLUG_SELECT_SKIP;
7031 player->interrupted_by_resource = FALSE;
7034 /* update codec info */
7035 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7036 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7037 player->videodec_linked = 1;
7045 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7046 GstCaps *caps, GstElementFactory *factory, gpointer data)
7048 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7049 mmplayer_t *player = (mmplayer_t *)data;
7051 gchar *factory_name = NULL;
7052 gchar *caps_str = NULL;
7053 const gchar *klass = NULL;
7056 factory_name = GST_OBJECT_NAME(factory);
7057 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7058 caps_str = gst_caps_to_string(caps);
7060 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7062 /* store type string */
7063 if (player->type == NULL) {
7064 player->type = gst_caps_to_string(caps);
7065 __mmplayer_update_content_type_info(player);
7068 /* filtering exclude keyword */
7069 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7070 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7071 LOGW("skipping [%s] by exculde keyword [%s]",
7072 factory_name, player->ini.exclude_element_keyword[idx]);
7074 result = GST_AUTOPLUG_SELECT_SKIP;
7079 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7080 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7081 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7082 factory_name, player->ini.unsupported_codec_keyword[idx]);
7083 result = GST_AUTOPLUG_SELECT_SKIP;
7088 /* exclude webm format */
7089 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7090 * because webm format is not supportable.
7091 * If webm is disabled in "autoplug-continue", there is no state change
7092 * failure or error because the decodebin will expose the pad directly.
7093 * It make MSL invoke _prepare_async_callback.
7094 * So, we need to disable webm format in "autoplug-select" */
7095 if (caps_str && strstr(caps_str, "webm")) {
7096 LOGW("webm is not supported");
7097 result = GST_AUTOPLUG_SELECT_SKIP;
7101 /* check factory class for filtering */
7102 /* NOTE : msl don't need to use image plugins.
7103 * So, those plugins should be skipped for error handling.
7105 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7106 LOGD("skipping [%s] by not required", factory_name);
7107 result = GST_AUTOPLUG_SELECT_SKIP;
7111 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7112 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7113 // TO CHECK : subtitle if needed, add subparse exception.
7114 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7115 result = GST_AUTOPLUG_SELECT_SKIP;
7119 if (g_strrstr(factory_name, "mpegpsdemux")) {
7120 LOGD("skipping PS container - not support");
7121 result = GST_AUTOPLUG_SELECT_SKIP;
7125 if (g_strrstr(factory_name, "mssdemux"))
7126 player->smooth_streaming = TRUE;
7128 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7129 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7132 GstStructure *str = NULL;
7133 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7135 /* don't make video because of not required */
7136 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7137 (!player->set_mode.video_export)) {
7138 LOGD("no need video decoding, expose pad");
7139 result = GST_AUTOPLUG_SELECT_EXPOSE;
7143 /* get w/h for omx state-tune */
7144 /* FIXME: deprecated? */
7145 str = gst_caps_get_structure(caps, 0);
7146 gst_structure_get_int(str, "width", &width);
7149 if (player->v_stream_caps) {
7150 gst_caps_unref(player->v_stream_caps);
7151 player->v_stream_caps = NULL;
7154 player->v_stream_caps = gst_caps_copy(caps);
7155 LOGD("take caps for video state tune");
7156 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7160 if (g_strrstr(klass, "Codec/Decoder")) {
7161 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7162 if (result != GST_AUTOPLUG_SELECT_TRY) {
7163 LOGW("skip add decoder");
7169 MMPLAYER_FREEIF(caps_str);
7175 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7178 //mmplayer_t *player = (mmplayer_t *)data;
7179 GstCaps *caps = NULL;
7181 LOGD("[Decodebin2] pad-removed signal");
7183 caps = gst_pad_query_caps(new_pad, NULL);
7185 LOGW("query caps is NULL");
7189 gchar *caps_str = NULL;
7190 caps_str = gst_caps_to_string(caps);
7192 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7194 MMPLAYER_FREEIF(caps_str);
7195 gst_caps_unref(caps);
7199 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7201 mmplayer_t *player = (mmplayer_t *)data;
7202 GstIterator *iter = NULL;
7203 GValue item = { 0, };
7205 gboolean done = FALSE;
7206 gboolean is_all_drained = TRUE;
7209 MMPLAYER_RETURN_IF_FAIL(player);
7211 LOGD("__mmplayer_gst_decode_drained");
7213 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7214 LOGW("Fail to get cmd lock");
7218 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7219 !__mmplayer_verify_gapless_play_path(player)) {
7220 LOGD("decoding is finished.");
7221 __mmplayer_reset_gapless_state(player);
7222 MMPLAYER_CMD_UNLOCK(player);
7226 player->gapless.reconfigure = TRUE;
7228 /* check decodebin src pads whether they received EOS or not */
7229 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7232 switch (gst_iterator_next(iter, &item)) {
7233 case GST_ITERATOR_OK:
7234 pad = g_value_get_object(&item);
7235 if (pad && !GST_PAD_IS_EOS(pad)) {
7236 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7237 is_all_drained = FALSE;
7240 g_value_reset(&item);
7242 case GST_ITERATOR_RESYNC:
7243 gst_iterator_resync(iter);
7245 case GST_ITERATOR_ERROR:
7246 case GST_ITERATOR_DONE:
7251 g_value_unset(&item);
7252 gst_iterator_free(iter);
7254 if (!is_all_drained) {
7255 LOGD("Wait util the all pads get EOS.");
7256 MMPLAYER_CMD_UNLOCK(player);
7261 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7262 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7264 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7265 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7266 __mmplayer_deactivate_old_path(player);
7267 MMPLAYER_CMD_UNLOCK(player);
7273 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7275 mmplayer_t *player = (mmplayer_t *)data;
7276 const gchar *klass = NULL;
7277 gchar *factory_name = NULL;
7279 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7280 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7282 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7284 if (__mmplayer_add_dump_buffer_probe(player, element))
7285 LOGD("add buffer probe");
7287 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7288 gchar *selected = NULL;
7289 selected = g_strdup(GST_ELEMENT_NAME(element));
7290 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7293 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7294 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7295 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7297 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7298 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7300 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7301 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7302 "max-video-width", player->adaptive_info.limit.width,
7303 "max-video-height", player->adaptive_info.limit.height, NULL);
7305 } else if (g_strrstr(klass, "Demuxer")) {
7307 LOGD("plugged element is demuxer. take it");
7309 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7310 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7313 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7314 int surface_type = 0;
7316 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7319 // to support trust-zone only
7320 if (g_strrstr(factory_name, "asfdemux")) {
7321 LOGD("set file-location %s", player->profile.uri);
7322 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7323 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7324 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7325 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7326 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7327 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7328 (__mmplayer_is_only_mp3_type(player->type))) {
7329 LOGD("[mpegaudioparse] set streaming pull mode.");
7330 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7332 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7333 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7336 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7337 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7338 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7340 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7341 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7343 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7344 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7345 (MMPLAYER_IS_DASH_STREAMING(player))) {
7346 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7347 _mm_player_streaming_set_multiqueue(player->streamer, element);
7348 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7357 __mmplayer_release_misc(mmplayer_t *player)
7360 bool cur_mode = player->set_mode.rich_audio;
7363 MMPLAYER_RETURN_IF_FAIL(player);
7365 player->video_decoded_cb = NULL;
7366 player->video_decoded_cb_user_param = NULL;
7367 player->video_stream_prerolled = false;
7369 player->audio_decoded_cb = NULL;
7370 player->audio_decoded_cb_user_param = NULL;
7371 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7373 player->audio_stream_changed_cb = NULL;
7374 player->audio_stream_changed_cb_user_param = NULL;
7376 player->sent_bos = FALSE;
7377 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7379 player->seek_state = MMPLAYER_SEEK_NONE;
7381 player->total_bitrate = 0;
7382 player->total_maximum_bitrate = 0;
7384 player->not_found_demuxer = 0;
7386 player->last_position = 0;
7387 player->duration = 0;
7388 player->http_content_size = 0;
7389 player->not_supported_codec = MISSING_PLUGIN_NONE;
7390 player->can_support_codec = FOUND_PLUGIN_NONE;
7391 player->pending_seek.is_pending = false;
7392 player->pending_seek.pos = 0;
7393 player->msg_posted = FALSE;
7394 player->has_many_types = FALSE;
7395 player->is_subtitle_force_drop = FALSE;
7396 player->play_subtitle = FALSE;
7397 player->adjust_subtitle_pos = 0;
7398 player->has_closed_caption = FALSE;
7399 player->set_mode.video_export = false;
7400 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7401 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7403 player->set_mode.rich_audio = cur_mode;
7405 if (player->audio_device_cb_id > 0 &&
7406 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7407 LOGW("failed to remove audio device_connected_callback");
7408 player->audio_device_cb_id = 0;
7410 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7411 player->bitrate[i] = 0;
7412 player->maximum_bitrate[i] = 0;
7415 /* free memory related to audio effect */
7416 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7418 if (player->adaptive_info.var_list) {
7419 g_list_free_full(player->adaptive_info.var_list, g_free);
7420 player->adaptive_info.var_list = NULL;
7423 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7424 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7425 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7427 /* Reset video360 settings to their defaults in case if the pipeline is to be
7430 player->video360_metadata.is_spherical = -1;
7431 player->is_openal_plugin_used = FALSE;
7433 player->is_content_spherical = FALSE;
7434 player->is_video360_enabled = TRUE;
7435 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7436 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7437 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7438 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7439 player->video360_zoom = 1.0f;
7440 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7441 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7443 player->sound.rg_enable = false;
7445 __mmplayer_initialize_video_roi(player);
7450 __mmplayer_release_misc_post(mmplayer_t *player)
7452 char *original_uri = NULL;
7455 /* player->pipeline is already released before. */
7457 MMPLAYER_RETURN_IF_FAIL(player);
7459 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7461 /* clean found audio decoders */
7462 if (player->audio_decoders) {
7463 GList *a_dec = player->audio_decoders;
7464 for (; a_dec; a_dec = g_list_next(a_dec)) {
7465 gchar *name = a_dec->data;
7466 MMPLAYER_FREEIF(name);
7468 g_list_free(player->audio_decoders);
7469 player->audio_decoders = NULL;
7472 /* clean the uri list except original uri */
7473 if (player->uri_info.uri_list) {
7474 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7477 LOGW("failed to get original uri info");
7479 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7480 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7482 GList *uri_list = player->uri_info.uri_list;
7483 for (; uri_list; uri_list = g_list_next(uri_list)) {
7484 gchar *uri = uri_list->data;
7485 MMPLAYER_FREEIF(uri);
7487 g_list_free(player->uri_info.uri_list);
7488 player->uri_info.uri_list = NULL;
7491 /* clear the audio stream buffer list */
7492 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7494 /* clear the video stream bo list */
7495 __mmplayer_video_stream_destroy_bo_list(player);
7496 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7498 if (player->profile.input_mem.buf) {
7499 free(player->profile.input_mem.buf);
7500 player->profile.input_mem.buf = NULL;
7502 player->profile.input_mem.len = 0;
7503 player->profile.input_mem.offset = 0;
7505 player->uri_info.uri_idx = 0;
7510 __mmplayer_check_subtitle(mmplayer_t *player)
7512 MMHandleType attrs = 0;
7513 char *subtitle_uri = NULL;
7517 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7519 /* get subtitle attribute */
7520 attrs = MMPLAYER_GET_ATTRS(player);
7524 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7525 if (!subtitle_uri || !strlen(subtitle_uri))
7528 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7529 player->is_external_subtitle_present = TRUE;
7537 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7539 MMPLAYER_RETURN_IF_FAIL(player);
7541 if (player->eos_timer) {
7542 LOGD("cancel eos timer");
7543 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7544 player->eos_timer = 0;
7551 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7555 MMPLAYER_RETURN_IF_FAIL(player);
7556 MMPLAYER_RETURN_IF_FAIL(sink);
7558 player->sink_elements = g_list_append(player->sink_elements, sink);
7564 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7568 MMPLAYER_RETURN_IF_FAIL(player);
7569 MMPLAYER_RETURN_IF_FAIL(sink);
7571 player->sink_elements = g_list_remove(player->sink_elements, sink);
7577 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7578 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7580 mmplayer_signal_item_t *item = NULL;
7583 MMPLAYER_RETURN_IF_FAIL(player);
7585 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7586 LOGE("invalid signal type [%d]", type);
7590 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7592 LOGE("cannot connect signal [%s]", signal);
7597 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7598 player->signals[type] = g_list_append(player->signals[type], item);
7604 /* NOTE : be careful with calling this api. please refer to below glib comment
7605 * glib comment : Note that there is a bug in GObject that makes this function much
7606 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7607 * will no longer be called, but, the signal handler is not currently disconnected.
7608 * If the instance is itself being freed at the same time than this doesn't matter,
7609 * since the signal will automatically be removed, but if instance persists,
7610 * then the signal handler will leak. You should not remove the signal yourself
7611 * because in a future versions of GObject, the handler will automatically be
7614 * It's possible to work around this problem in a way that will continue to work
7615 * with future versions of GObject by checking that the signal handler is still
7616 * connected before disconnected it:
7618 * if (g_signal_handler_is_connected(instance, id))
7619 * g_signal_handler_disconnect(instance, id);
7622 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7624 GList *sig_list = NULL;
7625 mmplayer_signal_item_t *item = NULL;
7629 MMPLAYER_RETURN_IF_FAIL(player);
7631 LOGD("release signals type : %d", type);
7633 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7634 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7635 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7636 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7637 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7638 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7642 sig_list = player->signals[type];
7644 for (; sig_list; sig_list = sig_list->next) {
7645 item = sig_list->data;
7647 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7648 if (g_signal_handler_is_connected(item->obj, item->sig))
7649 g_signal_handler_disconnect(item->obj, item->sig);
7652 MMPLAYER_FREEIF(item);
7655 g_list_free(player->signals[type]);
7656 player->signals[type] = NULL;
7664 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, void *display_overlay)
7666 mmplayer_t *player = 0;
7667 int prev_display_surface_type = 0;
7668 void *prev_display_overlay = NULL;
7672 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7673 MMPLAYER_RETURN_VAL_IF_FAIL(display_overlay, MM_ERROR_COMMON_INVALID_ARGUMENT);
7675 player = MM_PLAYER_CAST(handle);
7677 /* check video sinkbin is created */
7678 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7679 LOGW("Videosink is already created");
7680 return MM_ERROR_NONE;
7683 LOGD("videosink element is not yet ready");
7685 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7686 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7688 return MM_ERROR_INVALID_ARGUMENT;
7691 /* load previous attributes */
7692 if (player->attrs) {
7693 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7694 mm_attrs_get_data_by_name(player->attrs, "display_overlay", &prev_display_overlay);
7695 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7696 if (prev_display_surface_type == surface_type) {
7697 LOGD("incoming display surface type is same as previous one, do nothing..");
7699 return MM_ERROR_NONE;
7702 LOGE("failed to load attributes");
7704 return MM_ERROR_PLAYER_INTERNAL;
7707 /* videobin is not created yet, so we just set attributes related to display surface */
7708 LOGD("store display attribute for given surface type(%d)", surface_type);
7709 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7710 "display_overlay", display_overlay, sizeof(display_overlay), NULL);
7713 return MM_ERROR_NONE;
7716 /* Note : if silent is true, then subtitle would not be displayed. :*/
7718 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7720 mmplayer_t *player = (mmplayer_t *)hplayer;
7724 /* check player handle */
7725 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7727 player->set_mode.subtitle_off = silent;
7729 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7733 return MM_ERROR_NONE;
7737 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7739 mmplayer_gst_element_t *mainbin = NULL;
7740 mmplayer_gst_element_t *textbin = NULL;
7741 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7742 GstState current_state = GST_STATE_VOID_PENDING;
7743 GstState element_state = GST_STATE_VOID_PENDING;
7744 GstState element_pending_state = GST_STATE_VOID_PENDING;
7746 GstEvent *event = NULL;
7747 int result = MM_ERROR_NONE;
7749 GstClock *curr_clock = NULL;
7750 GstClockTime base_time, start_time, curr_time;
7755 /* check player handle */
7756 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7758 player->pipeline->mainbin &&
7759 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7761 mainbin = player->pipeline->mainbin;
7762 textbin = player->pipeline->textbin;
7764 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7766 // sync clock with current pipeline
7767 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7768 curr_time = gst_clock_get_time(curr_clock);
7770 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7771 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7773 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7774 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7776 if (current_state > GST_STATE_READY) {
7777 // sync state with current pipeline
7778 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7779 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7780 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7782 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7783 if (GST_STATE_CHANGE_FAILURE == ret) {
7784 LOGE("fail to state change.");
7785 result = MM_ERROR_PLAYER_INTERNAL;
7789 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7790 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7793 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7794 gst_object_unref(curr_clock);
7797 // seek to current position
7798 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7799 result = MM_ERROR_PLAYER_INVALID_STATE;
7800 LOGE("gst_element_query_position failed, invalid state");
7804 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7805 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);
7807 _mmplayer_gst_send_event_to_sink(player, event);
7809 result = MM_ERROR_PLAYER_INTERNAL;
7810 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7814 /* sync state with current pipeline */
7815 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7816 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7817 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7819 return MM_ERROR_NONE;
7822 /* release text pipeline resource */
7823 player->textsink_linked = 0;
7825 /* release signal */
7826 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7828 /* release textbin with it's childs */
7829 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7830 MMPLAYER_FREEIF(player->pipeline->textbin);
7831 player->pipeline->textbin = NULL;
7833 /* release subtitle elem */
7834 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7835 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7841 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7843 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7844 GstState current_state = GST_STATE_VOID_PENDING;
7846 MMHandleType attrs = 0;
7847 mmplayer_gst_element_t *mainbin = NULL;
7848 mmplayer_gst_element_t *textbin = NULL;
7850 gchar *subtitle_uri = NULL;
7851 int result = MM_ERROR_NONE;
7852 const gchar *charset = NULL;
7856 /* check player handle */
7857 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7859 player->pipeline->mainbin &&
7860 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7861 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7863 mainbin = player->pipeline->mainbin;
7864 textbin = player->pipeline->textbin;
7866 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7867 if (current_state < GST_STATE_READY) {
7868 result = MM_ERROR_PLAYER_INVALID_STATE;
7869 LOGE("Pipeline is not in proper state");
7873 attrs = MMPLAYER_GET_ATTRS(player);
7875 LOGE("cannot get content attribute");
7876 result = MM_ERROR_PLAYER_INTERNAL;
7880 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7881 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7882 LOGE("subtitle uri is not proper filepath");
7883 result = MM_ERROR_PLAYER_INVALID_URI;
7887 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7888 LOGE("failed to get storage info of subtitle path");
7889 result = MM_ERROR_PLAYER_INVALID_URI;
7893 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7894 SECURE_LOGD("new subtitle file path is [%s]", filepath);
7896 if (!strcmp(filepath, subtitle_uri)) {
7897 LOGD("subtitle path is not changed");
7900 if (mm_player_set_attribute((MMHandleType)player, NULL,
7901 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7902 LOGE("failed to set attribute");
7907 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7908 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7909 player->subtitle_language_list = NULL;
7910 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7912 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7913 if (ret != GST_STATE_CHANGE_SUCCESS) {
7914 LOGE("failed to change state of textbin to READY");
7915 result = MM_ERROR_PLAYER_INTERNAL;
7919 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7920 if (ret != GST_STATE_CHANGE_SUCCESS) {
7921 LOGE("failed to change state of subparse to READY");
7922 result = MM_ERROR_PLAYER_INTERNAL;
7926 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7927 if (ret != GST_STATE_CHANGE_SUCCESS) {
7928 LOGE("failed to change state of filesrc to READY");
7929 result = MM_ERROR_PLAYER_INTERNAL;
7933 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7935 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7937 charset = _mmplayer_get_charset(filepath);
7939 LOGD("detected charset is %s", charset);
7940 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7943 result = _mmplayer_sync_subtitle_pipeline(player);
7950 /* API to switch between external subtitles */
7952 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7954 int result = MM_ERROR_NONE;
7955 mmplayer_t *player = (mmplayer_t *)hplayer;
7960 /* check player handle */
7961 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7963 /* filepath can be null in idle state */
7965 /* check file path */
7966 if ((path = strstr(filepath, "file://")))
7967 result = _mmplayer_exist_file_path(path + 7);
7969 result = _mmplayer_exist_file_path(filepath);
7971 if (result != MM_ERROR_NONE) {
7972 LOGE("invalid subtitle path 0x%X", result);
7973 return result; /* file not found or permission denied */
7977 if (!player->pipeline) {
7979 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
7980 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
7981 LOGE("failed to set attribute");
7982 return MM_ERROR_PLAYER_INTERNAL;
7985 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7986 /* check filepath */
7987 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7989 if (!__mmplayer_check_subtitle(player)) {
7990 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
7991 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7992 LOGE("failed to set attribute");
7993 return MM_ERROR_PLAYER_INTERNAL;
7996 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
7997 LOGE("fail to create text pipeline");
7998 return MM_ERROR_PLAYER_INTERNAL;
8001 result = _mmplayer_sync_subtitle_pipeline(player);
8003 result = __mmplayer_change_external_subtitle_language(player, filepath);
8006 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8007 player->is_external_subtitle_added_now = TRUE;
8009 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8010 if (!player->subtitle_language_list) {
8011 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8012 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8013 LOGW("subtitle language list is not updated yet");
8015 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8023 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8025 int result = MM_ERROR_NONE;
8026 gchar *change_pad_name = NULL;
8027 GstPad *sinkpad = NULL;
8028 mmplayer_gst_element_t *mainbin = NULL;
8029 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8030 GstCaps *caps = NULL;
8031 gint total_track_num = 0;
8035 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8036 MM_ERROR_PLAYER_NOT_INITIALIZED);
8038 LOGD("Change Track(%d) to %d", type, index);
8040 mainbin = player->pipeline->mainbin;
8042 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8043 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8044 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8045 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8047 /* Changing Video Track is not supported. */
8048 LOGE("Track Type Error");
8052 if (mainbin[elem_idx].gst == NULL) {
8053 result = MM_ERROR_PLAYER_NO_OP;
8054 LOGD("Req track doesn't exist");
8058 total_track_num = player->selector[type].total_track_num;
8059 if (total_track_num <= 0) {
8060 result = MM_ERROR_PLAYER_NO_OP;
8061 LOGD("Language list is not available");
8065 if ((index < 0) || (index >= total_track_num)) {
8066 result = MM_ERROR_INVALID_ARGUMENT;
8067 LOGD("Not a proper index : %d", index);
8071 /*To get the new pad from the selector*/
8072 change_pad_name = g_strdup_printf("sink_%u", index);
8073 if (change_pad_name == NULL) {
8074 result = MM_ERROR_PLAYER_INTERNAL;
8075 LOGD("Pad does not exists");
8079 LOGD("new active pad name: %s", change_pad_name);
8081 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8082 if (sinkpad == NULL) {
8083 LOGD("sinkpad is NULL");
8084 result = MM_ERROR_PLAYER_INTERNAL;
8088 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8089 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8091 caps = gst_pad_get_current_caps(sinkpad);
8092 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8095 gst_object_unref(sinkpad);
8097 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8098 __mmplayer_set_audio_attrs(player, caps);
8101 MMPLAYER_FREEIF(change_pad_name);
8106 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8108 int result = MM_ERROR_NONE;
8109 mmplayer_t *player = NULL;
8110 mmplayer_gst_element_t *mainbin = NULL;
8112 gint current_active_index = 0;
8114 GstState current_state = GST_STATE_VOID_PENDING;
8115 GstEvent *event = NULL;
8120 player = (mmplayer_t *)hplayer;
8121 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8123 if (!player->pipeline) {
8124 LOGE("Track %d pre setting -> %d", type, index);
8126 player->selector[type].active_pad_index = index;
8130 mainbin = player->pipeline->mainbin;
8132 current_active_index = player->selector[type].active_pad_index;
8134 /*If index is same as running index no need to change the pad*/
8135 if (current_active_index == index)
8138 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8139 result = MM_ERROR_PLAYER_INVALID_STATE;
8143 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8144 if (current_state < GST_STATE_PAUSED) {
8145 result = MM_ERROR_PLAYER_INVALID_STATE;
8146 LOGW("Pipeline not in porper state");
8150 result = __mmplayer_change_selector_pad(player, type, index);
8151 if (result != MM_ERROR_NONE) {
8152 LOGE("change selector pad error");
8156 player->selector[type].active_pad_index = index;
8158 if (current_state == GST_STATE_PLAYING) {
8159 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8160 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8161 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8163 _mmplayer_gst_send_event_to_sink(player, event);
8165 result = MM_ERROR_PLAYER_INTERNAL;
8175 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8177 mmplayer_t *player = (mmplayer_t *)hplayer;
8181 /* check player handle */
8182 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8184 *silent = player->set_mode.subtitle_off;
8186 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8190 return MM_ERROR_NONE;
8194 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8196 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8197 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8199 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8200 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8204 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8205 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8206 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8207 mmplayer_dump_t *dump_s;
8208 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8209 if (dump_s == NULL) {
8210 LOGE("malloc fail");
8214 dump_s->dump_element_file = NULL;
8215 dump_s->dump_pad = NULL;
8216 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8218 if (dump_s->dump_pad) {
8219 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8220 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]);
8221 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8222 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);
8223 /* add list for removed buffer probe and close FILE */
8224 player->dump_list = g_list_append(player->dump_list, dump_s);
8225 LOGD("%s sink pad added buffer probe for dump", factory_name);
8228 MMPLAYER_FREEIF(dump_s);
8229 LOGE("failed to get %s sink pad added", factory_name);
8236 static GstPadProbeReturn
8237 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8239 FILE *dump_data = (FILE *)u_data;
8241 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8242 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8244 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8246 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8248 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8250 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8252 gst_buffer_unmap(buffer, &probe_info);
8254 return GST_PAD_PROBE_OK;
8258 __mmplayer_release_dump_list(GList *dump_list)
8260 GList *d_list = dump_list;
8265 for (; d_list; d_list = g_list_next(d_list)) {
8266 mmplayer_dump_t *dump_s = d_list->data;
8267 if (dump_s->dump_pad) {
8268 if (dump_s->probe_handle_id)
8269 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8270 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8272 if (dump_s->dump_element_file) {
8273 fclose(dump_s->dump_element_file);
8274 dump_s->dump_element_file = NULL;
8276 MMPLAYER_FREEIF(dump_s);
8278 g_list_free(dump_list);
8283 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8285 mmplayer_t *player = (mmplayer_t *)hplayer;
8289 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8290 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8292 *exist = (bool)player->has_closed_caption;
8296 return MM_ERROR_NONE;
8300 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8305 LOGD("unref internal gst buffer %p", buffer);
8307 gst_buffer_unref((GstBuffer *)buffer);
8314 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8316 mmplayer_t *player = (mmplayer_t *)hplayer;
8320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8321 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8323 if (MMPLAYER_IS_STREAMING(player))
8324 *timeout = (int)player->ini.live_state_change_timeout;
8326 *timeout = (int)player->ini.localplayback_state_change_timeout;
8328 LOGD("timeout = %d", *timeout);
8331 return MM_ERROR_NONE;
8335 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8339 MMPLAYER_RETURN_IF_FAIL(player);
8341 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8343 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8344 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8345 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8346 player->storage_info[i].id = -1;
8347 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8349 if (path_type != MMPLAYER_PATH_MAX)
8358 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8360 int ret = MM_ERROR_NONE;
8361 mmplayer_t *player = (mmplayer_t *)hplayer;
8362 MMMessageParamType msg_param = {0, };
8365 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8367 LOGW("state changed storage %d:%d", id, state);
8369 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8370 return MM_ERROR_NONE;
8372 /* FIXME: text path should be handled seperately. */
8373 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8374 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8375 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8376 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8377 LOGW("external storage is removed");
8379 if (player->msg_posted == FALSE) {
8380 memset(&msg_param, 0, sizeof(MMMessageParamType));
8381 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8382 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8383 player->msg_posted = TRUE;
8386 /* unrealize the player */
8387 ret = _mmplayer_unrealize(hplayer);
8388 if (ret != MM_ERROR_NONE)
8389 LOGE("failed to unrealize");
8397 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8399 int ret = MM_ERROR_NONE;
8400 mmplayer_t *player = (mmplayer_t *)hplayer;
8401 int idx = 0, total = 0;
8402 gchar *result = NULL, *tmp = NULL;
8405 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8406 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8408 total = *num = g_list_length(player->adaptive_info.var_list);
8410 LOGW("There is no stream variant info.");
8414 result = g_strdup("");
8415 for (idx = 0 ; idx < total ; idx++) {
8416 stream_variant_t *v_data = NULL;
8417 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8420 gchar data[64] = {0};
8421 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8423 tmp = g_strconcat(result, data, NULL);
8427 LOGW("There is no variant data in %d", idx);
8432 *var_info = (char *)result;
8434 LOGD("variant info %d:%s", *num, *var_info);
8440 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8442 int ret = MM_ERROR_NONE;
8443 mmplayer_t *player = (mmplayer_t *)hplayer;
8446 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8448 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8450 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8451 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8452 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8454 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8455 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8456 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8457 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8459 /* FIXME: seek to current position for applying new variant limitation */
8468 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8470 int ret = MM_ERROR_NONE;
8471 mmplayer_t *player = (mmplayer_t *)hplayer;
8474 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8475 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8477 *bandwidth = player->adaptive_info.limit.bandwidth;
8478 *width = player->adaptive_info.limit.width;
8479 *height = player->adaptive_info.limit.height;
8481 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8488 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8490 int ret = MM_ERROR_NONE;
8491 mmplayer_t *player = (mmplayer_t *)hplayer;
8494 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8495 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8496 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8498 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8500 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8501 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8502 else /* live case */
8503 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8505 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8512 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8514 #define IDX_FIRST_SW_CODEC 0
8515 mmplayer_t *player = (mmplayer_t *)hplayer;
8516 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8519 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8521 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8522 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8523 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8525 switch (stream_type) {
8526 case MM_PLAYER_STREAM_TYPE_AUDIO:
8527 /* to support audio codec selection, codec info have to be added in ini file as below.
8528 audio codec element hw = xxxx
8529 audio codec element sw = avdec */
8530 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8531 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8532 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8533 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8534 LOGE("There is no audio codec info for codec_type %d", codec_type);
8535 return MM_ERROR_PLAYER_NO_OP;
8538 case MM_PLAYER_STREAM_TYPE_VIDEO:
8539 /* to support video codec selection, codec info have to be added in ini file as below.
8540 video codec element hw = omx
8541 video codec element sw = avdec */
8542 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8543 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8544 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8545 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8546 LOGE("There is no video codec info for codec_type %d", codec_type);
8547 return MM_ERROR_PLAYER_NO_OP;
8551 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8552 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8556 LOGD("update %s codec_type to %d", attr_name, codec_type);
8557 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8560 return MM_ERROR_NONE;
8564 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8566 mmplayer_t *player = (mmplayer_t *)hplayer;
8567 GstElement *rg_vol_element = NULL;
8571 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8573 player->sound.rg_enable = enabled;
8575 /* just hold rgvolume enable value if pipeline is not ready */
8576 if (!player->pipeline || !player->pipeline->audiobin) {
8577 LOGD("pipeline is not ready. holding rgvolume enable value");
8578 return MM_ERROR_NONE;
8581 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8583 if (!rg_vol_element) {
8584 LOGD("rgvolume element is not created");
8585 return MM_ERROR_PLAYER_INTERNAL;
8589 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8591 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8595 return MM_ERROR_NONE;
8599 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8601 mmplayer_t *player = (mmplayer_t *)hplayer;
8602 GstElement *rg_vol_element = NULL;
8603 gboolean enable = FALSE;
8607 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8608 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8610 /* just hold enable_rg value if pipeline is not ready */
8611 if (!player->pipeline || !player->pipeline->audiobin) {
8612 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8613 *enabled = player->sound.rg_enable;
8614 return MM_ERROR_NONE;
8617 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8619 if (!rg_vol_element) {
8620 LOGD("rgvolume element is not created");
8621 return MM_ERROR_PLAYER_INTERNAL;
8624 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8625 *enabled = (bool)enable;
8629 return MM_ERROR_NONE;
8633 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8635 mmplayer_t *player = (mmplayer_t *)hplayer;
8636 MMHandleType attrs = 0;
8637 void *handle = NULL;
8638 int ret = MM_ERROR_NONE;
8642 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8644 attrs = MMPLAYER_GET_ATTRS(player);
8645 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8647 mm_attrs_get_data_by_name(attrs, "display_overlay", &handle);
8649 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8650 return MM_ERROR_PLAYER_INTERNAL;
8653 player->video_roi.scale_x = scale_x;
8654 player->video_roi.scale_y = scale_y;
8655 player->video_roi.scale_width = scale_width;
8656 player->video_roi.scale_height = scale_height;
8658 /* check video sinkbin is created */
8659 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8660 return MM_ERROR_NONE;
8662 if (!gst_video_overlay_set_video_roi_area(
8663 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8664 scale_x, scale_y, scale_width, scale_height))
8665 ret = MM_ERROR_PLAYER_INTERNAL;
8667 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8668 scale_x, scale_y, scale_width, scale_height);
8676 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8678 mmplayer_t *player = (mmplayer_t *)hplayer;
8679 int ret = MM_ERROR_NONE;
8683 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8684 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8686 *scale_x = player->video_roi.scale_x;
8687 *scale_y = player->video_roi.scale_y;
8688 *scale_width = player->video_roi.scale_width;
8689 *scale_height = player->video_roi.scale_height;
8691 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8692 *scale_x, *scale_y, *scale_width, *scale_height);
8698 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8700 mmplayer_t* player = (mmplayer_t*)hplayer;
8704 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8706 player->client_pid = pid;
8708 LOGD("client pid[%d] %p", pid, player);
8712 return MM_ERROR_NONE;
8716 __mmplayer_update_duration_value(mmplayer_t *player)
8718 gboolean ret = FALSE;
8719 gint64 dur_nsec = 0;
8720 LOGD("try to update duration");
8722 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8723 player->duration = dur_nsec;
8724 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8728 if (player->duration < 0) {
8729 LOGW("duration is Non-Initialized !!!");
8730 player->duration = 0;
8733 /* update streaming service type */
8734 player->streaming_type = _mmplayer_get_stream_service_type(player);
8736 /* check duration is OK */
8737 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8738 /* FIXIT : find another way to get duration here. */
8739 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8745 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8747 /* update audio params
8748 NOTE : We need original audio params and it can be only obtained from src pad of audio
8749 decoder. Below code only valid when we are not using 'resampler' just before
8750 'audioconverter'. */
8751 GstCaps *caps_a = NULL;
8753 gint samplerate = 0, channels = 0;
8754 GstStructure *p = NULL;
8755 GstElement *aconv = NULL;
8757 LOGD("try to update audio attrs");
8759 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8761 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8762 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8763 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8764 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8766 LOGE("there is no audio converter");
8770 pad = gst_element_get_static_pad(aconv, "sink");
8773 LOGW("failed to get pad from audio converter");
8777 caps_a = gst_pad_get_current_caps(pad);
8779 LOGW("not ready to get audio caps");
8780 gst_object_unref(pad);
8784 p = gst_caps_get_structure(caps_a, 0);
8786 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8788 gst_structure_get_int(p, "rate", &samplerate);
8789 gst_structure_get_int(p, "channels", &channels);
8791 mm_player_set_attribute((MMHandleType)player, NULL,
8792 "content_audio_samplerate", samplerate,
8793 "content_audio_channels", channels, NULL);
8795 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8797 gst_caps_unref(caps_a);
8798 gst_object_unref(pad);
8804 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8806 LOGD("try to update video attrs");
8808 GstCaps *caps_v = NULL;
8812 GstStructure *p = NULL;
8814 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8815 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8817 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8819 LOGD("no videosink sink pad");
8823 caps_v = gst_pad_get_current_caps(pad);
8824 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8825 if (!caps_v && player->v_stream_caps) {
8826 caps_v = player->v_stream_caps;
8827 gst_caps_ref(caps_v);
8831 LOGD("no negitiated caps from videosink");
8832 gst_object_unref(pad);
8836 p = gst_caps_get_structure(caps_v, 0);
8837 gst_structure_get_int(p, "width", &width);
8838 gst_structure_get_int(p, "height", &height);
8840 mm_player_set_attribute((MMHandleType)player, NULL,
8841 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
8843 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8845 SECURE_LOGD("width : %d height : %d", width, height);
8847 gst_caps_unref(caps_v);
8848 gst_object_unref(pad);
8851 mm_player_set_attribute((MMHandleType)player, NULL,
8852 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
8853 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8860 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8862 gboolean ret = FALSE;
8863 guint64 data_size = 0;
8867 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8868 if (!player->duration)
8871 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8872 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8873 if (stat(path, &sb) == 0)
8874 data_size = (guint64)sb.st_size;
8876 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8877 data_size = player->http_content_size;
8880 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8883 guint64 bitrate = 0;
8884 guint64 msec_dur = 0;
8886 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8888 bitrate = data_size * 8 * 1000 / msec_dur;
8889 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
8890 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8891 mm_player_set_attribute((MMHandleType)player, NULL,
8892 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
8895 LOGD("player duration is less than 0");
8899 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8900 if (player->total_bitrate) {
8901 mm_player_set_attribute((MMHandleType)player, NULL,
8902 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
8911 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8913 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8914 data->uri_type = uri_type;
8918 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8920 int ret = MM_ERROR_PLAYER_INVALID_URI;
8922 char *buffer = NULL;
8923 char *seperator = strchr(path, ',');
8924 char ext[100] = {0,}, size[100] = {0,};
8927 if ((buffer = strstr(path, "ext="))) {
8928 buffer += strlen("ext=");
8930 if (strlen(buffer)) {
8931 strncpy(ext, buffer, 99);
8933 if ((seperator = strchr(ext, ','))
8934 || (seperator = strchr(ext, ' '))
8935 || (seperator = strchr(ext, '\0'))) {
8936 seperator[0] = '\0';
8941 if ((buffer = strstr(path, "size="))) {
8942 buffer += strlen("size=");
8944 if (strlen(buffer) > 0) {
8945 strncpy(size, buffer, 99);
8947 if ((seperator = strchr(size, ','))
8948 || (seperator = strchr(size, ' '))
8949 || (seperator = strchr(size, '\0'))) {
8950 seperator[0] = '\0';
8953 mem_size = atoi(size);
8958 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8960 if (mem_size && param) {
8961 if (data->input_mem.buf)
8962 free(data->input_mem.buf);
8963 data->input_mem.buf = malloc(mem_size);
8965 if (data->input_mem.buf) {
8966 memcpy(data->input_mem.buf, param, mem_size);
8967 data->input_mem.len = mem_size;
8968 ret = MM_ERROR_NONE;
8970 LOGE("failed to alloc mem %d", mem_size);
8971 ret = MM_ERROR_PLAYER_INTERNAL;
8974 data->input_mem.offset = 0;
8975 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8982 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
8984 gchar *location = NULL;
8987 int ret = MM_ERROR_NONE;
8989 if ((path = strstr(uri, "file://"))) {
8990 location = g_filename_from_uri(uri, NULL, &err);
8991 if (!location || (err != NULL)) {
8992 LOGE("Invalid URI '%s' for filesrc: %s", path,
8993 (err != NULL) ? err->message : "unknown error");
8997 MMPLAYER_FREEIF(location);
8999 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9000 return MM_ERROR_PLAYER_INVALID_URI;
9002 LOGD("path from uri: %s", location);
9005 path = (location != NULL) ? (location) : ((char *)uri);
9008 ret = _mmplayer_exist_file_path(path);
9010 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9011 if (ret == MM_ERROR_NONE) {
9012 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9013 if (_mmplayer_is_sdp_file(path)) {
9014 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9015 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9017 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9019 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9020 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9022 LOGE("invalid uri, could not play..");
9023 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9026 MMPLAYER_FREEIF(location);
9031 static mmplayer_video_decoded_data_info_t *
9032 __mmplayer_create_stream_from_pad(GstPad *pad)
9034 GstCaps *caps = NULL;
9035 GstStructure *structure = NULL;
9036 unsigned int fourcc = 0;
9037 const gchar *string_format = NULL;
9038 mmplayer_video_decoded_data_info_t *stream = NULL;
9040 MMPixelFormatType format;
9043 caps = gst_pad_get_current_caps(pad);
9045 LOGE("Caps is NULL.");
9050 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9052 structure = gst_caps_get_structure(caps, 0);
9053 gst_structure_get_int(structure, "width", &width);
9054 gst_structure_get_int(structure, "height", &height);
9055 string_format = gst_structure_get_string(structure, "format");
9058 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9059 format = _mmplayer_get_pixtype(fourcc);
9060 gst_video_info_from_caps(&info, caps);
9061 gst_caps_unref(caps);
9064 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9065 LOGE("Wrong condition!!");
9069 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9071 LOGE("failed to alloc mem for video data");
9075 stream->width = width;
9076 stream->height = height;
9077 stream->format = format;
9078 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9084 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9086 unsigned int pitch = 0;
9087 unsigned int size = 0;
9089 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9092 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9093 bo = gst_tizen_memory_get_bos(mem, index);
9095 stream->bo[index] = tbm_bo_ref(bo);
9097 LOGE("failed to get bo for index %d", index);
9100 for (index = 0; index < stream->plane_num; index++) {
9101 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9102 stream->stride[index] = pitch;
9104 stream->elevation[index] = size / pitch;
9106 stream->elevation[index] = stream->height;
9111 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9113 if (stream->format == MM_PIXEL_FORMAT_I420) {
9114 int ret = TBM_SURFACE_ERROR_NONE;
9115 tbm_surface_h surface;
9116 tbm_surface_info_s info;
9118 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9120 ret = tbm_surface_get_info(surface, &info);
9121 if (ret != TBM_SURFACE_ERROR_NONE) {
9122 tbm_surface_destroy(surface);
9126 tbm_surface_destroy(surface);
9127 stream->stride[0] = info.planes[0].stride;
9128 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9129 stream->stride[1] = info.planes[1].stride;
9130 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9131 stream->stride[2] = info.planes[2].stride;
9132 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9133 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9134 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9135 stream->stride[0] = stream->width * 4;
9136 stream->elevation[0] = stream->height;
9137 stream->bo_size = stream->stride[0] * stream->height;
9139 LOGE("Not support format %d", stream->format);
9147 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9149 tbm_bo_handle thandle;
9151 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9152 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9153 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9157 unsigned char *src = NULL;
9158 unsigned char *dest = NULL;
9159 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9161 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9163 LOGE("fail to gst_memory_map");
9167 if (!mapinfo.data) {
9168 LOGE("data pointer is wrong");
9172 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9173 if (!stream->bo[0]) {
9174 LOGE("Fail to tbm_bo_alloc!!");
9178 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9180 LOGE("thandle pointer is wrong");
9184 if (stream->format == MM_PIXEL_FORMAT_I420) {
9185 src_stride[0] = GST_ROUND_UP_4(stream->width);
9186 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9187 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9188 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9191 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9192 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9194 for (i = 0; i < 3; i++) {
9195 src = mapinfo.data + src_offset[i];
9196 dest = thandle.ptr + dest_offset[i];
9201 for (j = 0; j < stream->height >> k; j++) {
9202 memcpy(dest, src, stream->width>>k);
9203 src += src_stride[i];
9204 dest += stream->stride[i];
9207 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9208 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9210 LOGE("Not support format %d", stream->format);
9214 tbm_bo_unmap(stream->bo[0]);
9215 gst_memory_unmap(mem, &mapinfo);
9221 tbm_bo_unmap(stream->bo[0]);
9224 gst_memory_unmap(mem, &mapinfo);
9230 __mmplayer_set_pause_state(mmplayer_t *player)
9232 if (player->sent_bos)
9235 /* rtsp case, get content attrs by GstMessage */
9236 if (MMPLAYER_IS_RTSP_STREAMING(player))
9239 /* it's first time to update all content attrs. */
9240 _mmplayer_update_content_attrs(player, ATTR_ALL);
9244 __mmplayer_set_playing_state(mmplayer_t *player)
9246 gchar *audio_codec = NULL;
9248 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9249 /* initialize because auto resume is done well. */
9250 player->resumed_by_rewind = FALSE;
9251 player->playback_rate = 1.0;
9254 if (player->sent_bos)
9257 /* try to get content metadata */
9259 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9260 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9261 * legacy mmfw-player api
9263 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9265 if ((player->cmd == MMPLAYER_COMMAND_START)
9266 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9267 __mmplayer_handle_missed_plugin(player);
9270 /* check audio codec field is set or not
9271 * we can get it from typefinder or codec's caps.
9273 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9275 /* The codec format can't be sent for audio only case like amr, mid etc.
9276 * Because, parser don't make related TAG.
9277 * So, if it's not set yet, fill it with found data.
9280 if (g_strrstr(player->type, "audio/midi"))
9281 audio_codec = "MIDI";
9282 else if (g_strrstr(player->type, "audio/x-amr"))
9283 audio_codec = "AMR";
9284 else if (g_strrstr(player->type, "audio/mpeg")
9285 && !g_strrstr(player->type, "mpegversion=(int)1"))
9286 audio_codec = "AAC";
9288 audio_codec = "unknown";
9290 if (mm_player_set_attribute((MMHandleType)player, NULL,
9291 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9292 LOGE("failed to set attribute");
9294 LOGD("set audio codec type with caps");