4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
212 /* This function should be called after the pipeline goes PAUSED or higher
215 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
217 static gboolean has_duration = FALSE;
218 static gboolean has_video_attrs = FALSE;
219 static gboolean has_audio_attrs = FALSE;
220 static gboolean has_bitrate = FALSE;
221 gboolean missing_only = FALSE;
222 gboolean all = FALSE;
223 MMHandleType attrs = 0;
227 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
229 /* check player state here */
230 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
231 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
232 /* give warning now only */
233 LOGW("be careful. content attributes may not available in this state ");
236 /* get content attribute first */
237 attrs = MMPLAYER_GET_ATTRS(player);
239 LOGE("cannot get content attribute");
243 /* get update flag */
245 if (flag & ATTR_MISSING_ONLY) {
247 LOGD("updating missed attr only");
250 if (flag & ATTR_ALL) {
252 has_duration = FALSE;
253 has_video_attrs = FALSE;
254 has_audio_attrs = FALSE;
257 LOGD("updating all attrs");
260 if (missing_only && all) {
261 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
262 missing_only = FALSE;
265 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
266 has_duration = __mmplayer_update_duration_value(player);
268 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
269 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
271 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
272 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
274 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
275 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
283 _mmplayer_get_stream_service_type(mmplayer_t *player)
285 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
289 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
291 player->pipeline->mainbin &&
292 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
293 STREAMING_SERVICE_NONE);
295 /* streaming service type if streaming */
296 if (!MMPLAYER_IS_STREAMING(player))
297 return STREAMING_SERVICE_NONE;
299 streaming_type = (player->duration == 0) ?
300 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
302 switch (streaming_type) {
303 case STREAMING_SERVICE_LIVE:
304 LOGD("it's live streaming");
306 case STREAMING_SERVICE_VOD:
307 LOGD("it's vod streaming");
310 LOGE("should not get here");
316 return streaming_type;
319 /* this function sets the player state and also report
320 * it to applicaton by calling callback function
323 _mmplayer_set_state(mmplayer_t *player, int state)
325 MMMessageParamType msg = {0, };
327 MMPLAYER_RETURN_IF_FAIL(player);
329 if (MMPLAYER_CURRENT_STATE(player) == state) {
330 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
331 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
335 /* update player states */
336 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
337 MMPLAYER_CURRENT_STATE(player) = state;
339 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
340 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
343 MMPLAYER_PRINT_STATE(player);
345 switch (MMPLAYER_CURRENT_STATE(player)) {
346 case MM_PLAYER_STATE_NULL:
347 case MM_PLAYER_STATE_READY:
349 case MM_PLAYER_STATE_PAUSED:
350 __mmplayer_set_pause_state(player);
352 case MM_PLAYER_STATE_PLAYING:
353 __mmplayer_set_playing_state(player);
355 case MM_PLAYER_STATE_NONE:
357 LOGW("invalid target state, there is nothing to do.");
362 /* post message to application */
363 if (MMPLAYER_TARGET_STATE(player) == state) {
364 /* fill the message with state of player */
365 msg.union_type = MM_MSG_UNION_STATE;
366 msg.state.previous = MMPLAYER_PREV_STATE(player);
367 msg.state.current = MMPLAYER_CURRENT_STATE(player);
369 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
371 /* state changed by resource callback */
372 if (player->interrupted_by_resource)
373 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
374 else /* state changed by usecase */
375 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
378 LOGD("intermediate state, do nothing.");
379 MMPLAYER_PRINT_STATE(player);
383 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
384 && !player->sent_bos) {
385 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
386 player->sent_bos = TRUE;
393 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
395 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
396 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
398 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
400 LOGD("incomming command : %d ", command);
402 current_state = MMPLAYER_CURRENT_STATE(player);
403 pending_state = MMPLAYER_PENDING_STATE(player);
405 MMPLAYER_PRINT_STATE(player);
408 case MMPLAYER_COMMAND_CREATE:
410 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
412 if (current_state == MM_PLAYER_STATE_NULL ||
413 current_state == MM_PLAYER_STATE_READY ||
414 current_state == MM_PLAYER_STATE_PAUSED ||
415 current_state == MM_PLAYER_STATE_PLAYING)
420 case MMPLAYER_COMMAND_DESTROY:
422 /* destroy can called anytime */
424 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
428 case MMPLAYER_COMMAND_REALIZE:
430 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
432 if (pending_state != MM_PLAYER_STATE_NONE) {
435 /* need ready state to realize */
436 if (current_state == MM_PLAYER_STATE_READY)
439 if (current_state != MM_PLAYER_STATE_NULL)
445 case MMPLAYER_COMMAND_UNREALIZE:
447 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
449 if (current_state == MM_PLAYER_STATE_NULL)
454 case MMPLAYER_COMMAND_START:
456 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
458 if (pending_state == MM_PLAYER_STATE_NONE) {
459 if (current_state == MM_PLAYER_STATE_PLAYING)
461 else if (current_state != MM_PLAYER_STATE_READY &&
462 current_state != MM_PLAYER_STATE_PAUSED)
464 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
466 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
467 LOGD("player is going to paused state, just change the pending state as playing");
474 case MMPLAYER_COMMAND_STOP:
476 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
478 if (current_state == MM_PLAYER_STATE_READY)
481 /* need playing/paused state to stop */
482 if (current_state != MM_PLAYER_STATE_PLAYING &&
483 current_state != MM_PLAYER_STATE_PAUSED)
488 case MMPLAYER_COMMAND_PAUSE:
490 if (MMPLAYER_IS_LIVE_STREAMING(player))
493 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
494 goto NOT_COMPLETED_SEEK;
496 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
498 if (pending_state == MM_PLAYER_STATE_NONE) {
499 if (current_state == MM_PLAYER_STATE_PAUSED)
501 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
503 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
505 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
506 if (current_state == MM_PLAYER_STATE_PAUSED)
507 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
514 case MMPLAYER_COMMAND_RESUME:
516 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
517 goto NOT_COMPLETED_SEEK;
519 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
521 if (pending_state == MM_PLAYER_STATE_NONE) {
522 if (current_state == MM_PLAYER_STATE_PLAYING)
524 else if (current_state != MM_PLAYER_STATE_PAUSED)
526 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
528 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
529 LOGD("player is going to paused state, just change the pending state as playing");
539 player->cmd = command;
541 return MM_ERROR_NONE;
544 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
545 MMPLAYER_STATE_GET_NAME(current_state), command);
546 return MM_ERROR_PLAYER_INVALID_STATE;
549 LOGW("not completed seek");
550 return MM_ERROR_PLAYER_DOING_SEEK;
553 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
554 return MM_ERROR_PLAYER_NO_OP;
557 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
558 return MM_ERROR_PLAYER_NO_OP;
561 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
563 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
564 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
567 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
568 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
570 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
571 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
573 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
574 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
577 LOGE("invalid mmplayer resource type %d", type);
578 return MM_ERROR_PLAYER_INTERNAL;
581 if (player->hw_resource[type] != NULL) {
582 LOGD("[%d type] resource was already acquired", type);
583 return MM_ERROR_NONE;
586 LOGD("mark for acquire [%d type] resource", type);
587 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
588 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
589 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
590 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
591 return MM_ERROR_PLAYER_INTERNAL;
594 rm_ret = mm_resource_manager_commit(player->resource_manager);
595 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
596 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
597 return MM_ERROR_PLAYER_INTERNAL;
601 return MM_ERROR_NONE;
604 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
606 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
610 if (player->hw_resource[type] == NULL) {
611 LOGD("there is no acquired [%d type] resource", type);
612 return MM_ERROR_NONE;
615 LOGD("mark for release [%d type] resource", type);
616 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
617 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
618 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
619 return MM_ERROR_PLAYER_INTERNAL;
622 player->hw_resource[type] = NULL;
624 rm_ret = mm_resource_manager_commit(player->resource_manager);
625 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
626 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
627 return MM_ERROR_PLAYER_INTERNAL;
631 return MM_ERROR_NONE;
635 __mmplayer_initialize_gapless_play(mmplayer_t *player)
641 player->smooth_streaming = FALSE;
642 player->videodec_linked = 0;
643 player->audiodec_linked = 0;
644 player->textsink_linked = 0;
645 player->is_external_subtitle_present = FALSE;
646 player->is_external_subtitle_added_now = FALSE;
647 player->not_supported_codec = MISSING_PLUGIN_NONE;
648 player->can_support_codec = FOUND_PLUGIN_NONE;
649 player->pending_seek.is_pending = false;
650 player->pending_seek.pos = 0;
651 player->msg_posted = FALSE;
652 player->has_many_types = FALSE;
653 player->no_more_pad = FALSE;
654 player->not_found_demuxer = 0;
655 player->seek_state = MMPLAYER_SEEK_NONE;
656 player->is_subtitle_force_drop = FALSE;
657 player->play_subtitle = FALSE;
658 player->adjust_subtitle_pos = 0;
660 player->total_bitrate = 0;
661 player->total_maximum_bitrate = 0;
663 _mmplayer_track_initialize(player);
664 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
666 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
667 player->bitrate[i] = 0;
668 player->maximum_bitrate[i] = 0;
671 if (player->v_stream_caps) {
672 gst_caps_unref(player->v_stream_caps);
673 player->v_stream_caps = NULL;
676 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
678 /* clean found audio decoders */
679 if (player->audio_decoders) {
680 GList *a_dec = player->audio_decoders;
681 for (; a_dec; a_dec = g_list_next(a_dec)) {
682 gchar *name = a_dec->data;
683 MMPLAYER_FREEIF(name);
685 g_list_free(player->audio_decoders);
686 player->audio_decoders = NULL;
689 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
695 __mmplayer_gapless_play_thread(gpointer data)
697 mmplayer_t *player = (mmplayer_t *)data;
698 mmplayer_gst_element_t *mainbin = NULL;
700 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
702 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
703 while (!player->gapless_play_thread_exit) {
704 LOGD("gapless play thread started. waiting for signal.");
705 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
707 LOGD("reconfigure pipeline for gapless play.");
709 if (player->gapless_play_thread_exit) {
710 if (player->gapless.reconfigure) {
711 player->gapless.reconfigure = false;
712 MMPLAYER_PLAYBACK_UNLOCK(player);
714 LOGD("exiting gapless play thread");
718 mainbin = player->pipeline->mainbin;
720 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
721 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
722 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
723 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
724 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
726 /* Initialize Player values */
727 __mmplayer_initialize_gapless_play(player);
729 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
731 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
737 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
739 GSource *source = NULL;
743 source = g_main_context_find_source_by_id(context, source_id);
744 if (source != NULL) {
745 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
746 g_source_destroy(source);
753 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
755 mmplayer_t *player = (mmplayer_t *)hplayer;
756 GstMessage *msg = NULL;
757 GQueue *queue = NULL;
760 MMPLAYER_RETURN_IF_FAIL(player);
762 /* disconnecting bus watch */
763 if (player->bus_watcher)
764 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
765 player->bus_watcher = 0;
767 /* destroy the gst bus msg thread */
768 if (player->bus_msg_thread) {
769 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
770 player->bus_msg_thread_exit = TRUE;
771 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
772 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
774 LOGD("gst bus msg thread exit.");
775 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
776 player->bus_msg_thread = NULL;
778 g_mutex_clear(&player->bus_msg_thread_mutex);
779 g_cond_clear(&player->bus_msg_thread_cond);
782 g_mutex_lock(&player->bus_msg_q_lock);
783 queue = player->bus_msg_q;
784 while (!g_queue_is_empty(queue)) {
785 msg = (GstMessage *)g_queue_pop_head(queue);
790 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
791 gst_message_unref(msg);
793 g_mutex_unlock(&player->bus_msg_q_lock);
799 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
801 GstElement *parent = NULL;
803 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
804 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
807 MMPLAYER_FSINK_LOCK(player);
809 /* get parent of fakesink */
810 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
812 LOGD("fakesink already removed");
816 gst_element_set_locked_state(fakesink->gst, TRUE);
818 /* setting the state to NULL never returns async
819 * so no need to wait for completion of state transiton
821 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
822 LOGE("fakesink state change failure!");
823 /* FIXIT : should I return here? or try to proceed to next? */
826 /* remove fakesink from it's parent */
827 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
828 LOGE("failed to remove fakesink");
830 gst_object_unref(parent);
835 gst_object_unref(parent);
837 LOGD("state-holder removed");
839 gst_element_set_locked_state(fakesink->gst, FALSE);
841 MMPLAYER_FSINK_UNLOCK(player);
846 gst_element_set_locked_state(fakesink->gst, FALSE);
848 MMPLAYER_FSINK_UNLOCK(player);
852 static GstPadProbeReturn
853 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
855 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
856 return GST_PAD_PROBE_OK;
860 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
862 gint64 stop_running_time = 0;
863 gint64 position_running_time = 0;
867 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
868 if ((player->gapless.update_segment[idx] == TRUE) ||
869 !(player->selector[idx].event_probe_id)) {
871 LOGW("[%d] skip", idx);
876 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
878 gst_segment_to_running_time(&player->gapless.segment[idx],
879 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
880 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
882 gst_segment_to_running_time(&player->gapless.segment[idx],
883 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
885 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
887 gst_segment_to_running_time(&player->gapless.segment[idx],
888 GST_FORMAT_TIME, player->duration);
891 position_running_time =
892 gst_segment_to_running_time(&player->gapless.segment[idx],
893 GST_FORMAT_TIME, player->gapless.segment[idx].position);
895 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
896 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
898 GST_TIME_ARGS(stop_running_time),
899 GST_TIME_ARGS(position_running_time),
900 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
901 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
903 position_running_time = MAX(position_running_time, stop_running_time);
904 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
905 GST_FORMAT_TIME, player->gapless.segment[idx].start);
906 position_running_time = MAX(0, position_running_time);
907 position = MAX(position, position_running_time);
911 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
912 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
913 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
915 player->gapless.start_time[stream_type] += position;
921 static GstPadProbeReturn
922 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
924 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
925 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
926 mmplayer_t *player = (mmplayer_t *)data;
927 GstCaps *caps = NULL;
928 GstStructure *str = NULL;
929 const gchar *name = NULL;
930 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
931 gboolean caps_ret = TRUE;
933 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
934 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
935 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
936 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
937 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
940 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
944 if (strstr(name, "audio")) {
945 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
946 } else if (strstr(name, "video")) {
947 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
949 /* text track is not supportable */
950 LOGE("invalid name %s", name);
954 switch (GST_EVENT_TYPE(event)) {
957 /* in case of gapless, drop eos event not to send it to sink */
958 if (player->gapless.reconfigure && !player->msg_posted) {
959 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
960 ret = GST_PAD_PROBE_DROP;
964 case GST_EVENT_STREAM_START:
966 __mmplayer_gst_selector_update_start_time(player, stream_type);
969 case GST_EVENT_FLUSH_STOP:
971 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
972 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
973 player->gapless.start_time[stream_type] = 0;
976 case GST_EVENT_SEGMENT:
981 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
982 gst_event_copy_segment(event, &segment);
984 if (segment.format != GST_FORMAT_TIME)
987 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
988 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
989 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
990 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
991 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
992 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
994 /* keep the all the segment ev to cover the seeking */
995 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
996 player->gapless.update_segment[stream_type] = TRUE;
998 if (!player->gapless.running)
1001 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1003 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1005 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1006 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1007 gst_event_unref(event);
1008 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1014 gdouble proportion = 0.0;
1015 GstClockTimeDiff diff = 0;
1016 GstClockTime timestamp = 0;
1017 gint64 running_time_diff = -1;
1018 GstQOSType type = 0;
1019 GstEvent *tmpev = NULL;
1021 running_time_diff = player->gapless.segment[stream_type].base;
1023 if (running_time_diff <= 0) /* don't need to adjust */
1026 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1027 gst_event_unref(event);
1029 if (timestamp < running_time_diff) {
1030 LOGW("QOS event from previous group");
1031 ret = GST_PAD_PROBE_DROP;
1036 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1037 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1038 stream_type, GST_TIME_ARGS(timestamp),
1039 GST_TIME_ARGS(running_time_diff),
1040 GST_TIME_ARGS(timestamp - running_time_diff));
1043 timestamp -= running_time_diff;
1045 /* That case is invalid for QoS events */
1046 if (diff < 0 && -diff > timestamp) {
1047 LOGW("QOS event from previous group");
1048 ret = GST_PAD_PROBE_DROP;
1052 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1053 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1063 gst_caps_unref(caps);
1067 /* create fakesink for audio or video path witout audiobin or videobin */
1069 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1071 GstElement *pipeline = NULL;
1072 GstElement *fakesink = NULL;
1073 GstPad *sinkpad = NULL;
1076 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1078 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1081 fakesink = gst_element_factory_make("fakesink", NULL);
1082 if (fakesink == NULL) {
1083 LOGE("failed to create fakesink");
1087 /* store it as it's sink element */
1088 __mmplayer_add_sink(player, fakesink);
1090 gst_bin_add(GST_BIN(pipeline), fakesink);
1093 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1095 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1097 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1098 LOGE("failed to link fakesink");
1099 gst_object_unref(GST_OBJECT(fakesink));
1103 if (strstr(name, "video")) {
1104 if (player->v_stream_caps) {
1105 gst_caps_unref(player->v_stream_caps);
1106 player->v_stream_caps = NULL;
1108 if (player->ini.set_dump_element_flag)
1109 __mmplayer_add_dump_buffer_probe(player, fakesink);
1112 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1113 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1117 gst_object_unref(GST_OBJECT(sinkpad));
1124 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1126 GstElement *pipeline = NULL;
1127 GstElement *selector = NULL;
1128 GstPad *srcpad = NULL;
1131 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1133 selector = gst_element_factory_make("input-selector", NULL);
1135 LOGE("failed to create input-selector");
1138 g_object_set(selector, "sync-streams", TRUE, NULL);
1140 player->pipeline->mainbin[elem_idx].id = elem_idx;
1141 player->pipeline->mainbin[elem_idx].gst = selector;
1143 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1145 srcpad = gst_element_get_static_pad(selector, "src");
1147 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1148 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1149 __mmplayer_gst_selector_blocked, NULL, NULL);
1150 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1151 __mmplayer_gst_selector_event_probe, player, NULL);
1153 gst_element_set_state(selector, GST_STATE_PAUSED);
1155 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1156 gst_bin_add(GST_BIN(pipeline), selector);
1158 gst_object_unref(GST_OBJECT(srcpad));
1165 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1167 mmplayer_t *player = (mmplayer_t *)data;
1168 GstElement *selector = NULL;
1169 GstCaps *caps = NULL;
1170 GstStructure *str = NULL;
1171 const gchar *name = NULL;
1172 GstPad *sinkpad = NULL;
1173 gboolean first_track = FALSE;
1174 gboolean caps_ret = TRUE;
1176 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1177 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1180 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1181 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1183 LOGD("pad-added signal handling");
1185 /* get mimetype from caps */
1186 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1190 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1192 LOGD("detected mimetype : %s", name);
1195 if (strstr(name, "video")) {
1197 gchar *caps_str = NULL;
1199 caps_str = gst_caps_to_string(caps);
1200 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1201 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1202 player->set_mode.video_zc = true;
1204 MMPLAYER_FREEIF(caps_str);
1206 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1207 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1209 LOGD("surface type : %d", stype);
1211 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1212 __mmplayer_gst_create_sinkbin(elem, pad, player);
1216 /* in case of exporting video frame, it requires the 360 video filter.
1217 * it will be handled in _no_more_pads(). */
1218 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1219 __mmplayer_gst_make_fakesink(player, pad, name);
1223 LOGD("video selector is required");
1224 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1225 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1226 } else if (strstr(name, "audio")) {
1227 gint samplerate = 0;
1230 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1231 if (player->build_audio_offload)
1232 player->no_more_pad = TRUE; /* remove state holder */
1233 __mmplayer_gst_create_sinkbin(elem, pad, player);
1237 gst_structure_get_int(str, "rate", &samplerate);
1238 gst_structure_get_int(str, "channels", &channels);
1240 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1241 __mmplayer_gst_make_fakesink(player, pad, name);
1245 LOGD("audio selector is required");
1246 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1247 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1249 } else if (strstr(name, "text")) {
1250 LOGD("text selector is required");
1251 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1252 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1254 LOGE("invalid caps info");
1258 /* check selector and create it */
1259 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1260 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1265 LOGD("input-selector is already created.");
1269 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1271 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1273 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1274 LOGE("failed to link selector");
1275 gst_object_unref(GST_OBJECT(selector));
1280 LOGD("this track will be activated");
1281 g_object_set(selector, "active-pad", sinkpad, NULL);
1284 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1290 gst_caps_unref(caps);
1293 gst_object_unref(GST_OBJECT(sinkpad));
1301 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1303 GstPad *srcpad = NULL;
1306 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1308 LOGD("type %d", type);
1311 LOGD("there is no %d track", type);
1315 srcpad = gst_element_get_static_pad(selector, "src");
1317 LOGE("failed to get srcpad from selector");
1321 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1323 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1325 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1326 if (player->selector[type].block_id) {
1327 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1328 player->selector[type].block_id = 0;
1332 gst_object_unref(GST_OBJECT(srcpad));
1341 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1343 gint active_index = 0;
1346 MMPLAYER_RETURN_IF_FAIL(player);
1348 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1350 /* change track to active pad */
1351 active_index = player->selector[type].active_pad_index;
1352 if ((active_index != DEFAULT_TRACK) &&
1353 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1354 LOGW("failed to change %d type track to %d", type, active_index);
1355 player->selector[type].active_pad_index = DEFAULT_TRACK;
1359 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1360 mm_player_set_attribute((MMHandleType)player, NULL,
1361 "content_text_track_num", player->selector[type].total_track_num,
1362 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1369 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1372 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1374 if (!audio_selector) {
1375 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1377 /* in case the source is changed, output can be changed. */
1378 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1379 LOGD("remove previous audiobin if it exist");
1381 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1382 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1384 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1385 MMPLAYER_FREEIF(player->pipeline->audiobin);
1388 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1389 __mmplayer_pipeline_complete(NULL, player);
1394 /* apply the audio track information */
1395 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1397 /* create audio sink path */
1398 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1399 LOGE("failed to create audio sink path");
1408 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1411 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1413 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1414 LOGD("text path is not supproted");
1418 /* apply the text track information */
1419 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1421 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1422 player->has_closed_caption = TRUE;
1424 /* create text decode path */
1425 player->no_more_pad = TRUE;
1427 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1428 LOGE("failed to create text sink path");
1437 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1439 gint64 dur_bytes = 0L;
1442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1443 player->pipeline->mainbin && player->streamer, FALSE);
1445 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1446 LOGE("fail to get duration.");
1448 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1449 * use file information was already set on Q2 when it was created. */
1450 _mm_player_streaming_set_queue2(player->streamer,
1451 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1452 TRUE, /* use_buffering */
1453 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1454 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1461 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1463 mmplayer_t *player = NULL;
1464 GstElement *video_selector = NULL;
1465 GstElement *audio_selector = NULL;
1466 GstElement *text_selector = NULL;
1469 player = (mmplayer_t *)data;
1471 LOGD("no-more-pad signal handling");
1473 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1474 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1475 LOGW("player is shutting down");
1479 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1480 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1481 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1482 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1483 LOGE("failed to set queue2 buffering");
1488 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1489 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1490 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1492 if (!video_selector && !audio_selector && !text_selector) {
1493 LOGW("there is no selector");
1494 player->no_more_pad = TRUE;
1498 /* create video path followed by video-select */
1499 if (video_selector && !audio_selector && !text_selector)
1500 player->no_more_pad = TRUE;
1502 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1505 /* create audio path followed by audio-select */
1506 if (audio_selector && !text_selector)
1507 player->no_more_pad = TRUE;
1509 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1512 /* create text path followed by text-select */
1513 __mmplayer_create_text_sink_path(player, text_selector);
1516 if (player->gapless.reconfigure) {
1517 player->gapless.reconfigure = FALSE;
1518 MMPLAYER_PLAYBACK_UNLOCK(player);
1525 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1527 gboolean ret = FALSE;
1528 GstElement *pipeline = NULL;
1529 GstPad *sinkpad = NULL;
1532 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1533 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1535 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1537 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1539 LOGE("failed to get pad from sinkbin");
1545 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1546 LOGE("failed to link sinkbin for reusing");
1547 goto EXIT; /* exit either pass or fail */
1551 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1552 LOGE("failed to set state(READY) to sinkbin");
1557 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1558 LOGE("failed to add sinkbin to pipeline");
1563 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1564 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1569 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1570 LOGE("failed to set state(PAUSED) to sinkbin");
1579 gst_object_unref(GST_OBJECT(sinkpad));
1587 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1589 mmplayer_t *player = NULL;
1590 GstCaps *caps = NULL;
1591 gchar *caps_str = NULL;
1592 GstStructure *str = NULL;
1593 const gchar *name = NULL;
1594 GstElement *sinkbin = NULL;
1595 gboolean reusing = FALSE;
1596 gboolean caps_ret = TRUE;
1597 gchar *sink_pad_name = "sink";
1600 player = (mmplayer_t *)data;
1603 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1604 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1606 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1610 caps_str = gst_caps_to_string(caps);
1612 LOGD("detected mimetype : %s", name);
1614 if (strstr(name, "audio")) {
1615 if (player->pipeline->audiobin == NULL) {
1616 const gchar *audio_format = gst_structure_get_string(str, "format");
1618 LOGD("original audio format %s", audio_format);
1619 mm_player_set_attribute((MMHandleType)player, NULL,
1620 "content_audio_format", audio_format, strlen(audio_format), NULL);
1623 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1624 LOGE("failed to create audiobin. continuing without audio");
1628 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1629 LOGD("creating audiobin success");
1632 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1633 LOGD("reusing audiobin");
1634 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1636 } else if (strstr(name, "video")) {
1637 /* 1. zero copy is updated at _decode_pad_added()
1638 * 2. NULL surface type is handled in _decode_pad_added() */
1639 LOGD("zero copy %d", player->set_mode.video_zc);
1640 if (player->pipeline->videobin == NULL) {
1641 int surface_type = 0;
1642 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1643 LOGD("display_surface_type (%d)", surface_type);
1645 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1646 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1647 LOGE("failed to acquire video overlay resource");
1651 player->interrupted_by_resource = FALSE;
1653 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1654 LOGE("failed to create videobin. continuing without video");
1658 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1659 LOGD("creating videosink bin success");
1662 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1663 LOGD("re-using videobin");
1664 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1666 } else if (strstr(name, "text")) {
1667 if (player->pipeline->textbin == NULL) {
1668 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1669 LOGE("failed to create text sink bin. continuing without text");
1673 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1674 player->textsink_linked = 1;
1675 LOGD("creating textsink bin success");
1677 if (!player->textsink_linked) {
1678 LOGD("re-using textbin");
1680 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1681 player->textsink_linked = 1;
1683 /* linked textbin exist which means that the external subtitle path exist already */
1684 LOGW("ignoring internal subtutle since external subtitle is available");
1687 sink_pad_name = "text_sink";
1689 LOGW("unknown mime type %s, ignoring it", name);
1693 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1696 LOGD("[handle: %p] success to create and link sink bin", player);
1698 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1699 * streaming task. if the task blocked, then buffer will not flow to the next element
1700 *(autoplugging element). so this is special hack for streaming. please try to remove it
1702 /* dec stream count. we can remove fakesink if it's zero */
1703 if (player->num_dynamic_pad)
1704 player->num_dynamic_pad--;
1706 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1708 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1709 __mmplayer_pipeline_complete(NULL, player);
1713 MMPLAYER_FREEIF(caps_str);
1716 gst_caps_unref(caps);
1722 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1724 int required_angle = 0; /* Angle required for straight view */
1725 int rotation_angle = 0;
1727 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1728 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1730 /* Counter clockwise */
1731 switch (orientation) {
1736 required_angle = 270;
1739 required_angle = 180;
1742 required_angle = 90;
1746 rotation_angle = display_angle + required_angle;
1747 if (rotation_angle >= 360)
1748 rotation_angle -= 360;
1750 /* chech if supported or not */
1751 if (rotation_angle % 90) {
1752 LOGD("not supported rotation angle = %d", rotation_angle);
1756 switch (rotation_angle) {
1758 *value = MM_DISPLAY_ROTATION_NONE;
1761 *value = MM_DISPLAY_ROTATION_90;
1764 *value = MM_DISPLAY_ROTATION_180;
1767 *value = MM_DISPLAY_ROTATION_270;
1771 LOGD("setting rotation property value : %d", *value);
1777 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1779 int display_rotation = 0;
1780 gchar *org_orient = NULL;
1781 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1784 LOGE("cannot get content attribute");
1785 return MM_ERROR_PLAYER_INTERNAL;
1788 if (display_angle) {
1789 /* update user roation */
1790 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1792 /* Counter clockwise */
1793 switch (display_rotation) {
1794 case MM_DISPLAY_ROTATION_NONE:
1797 case MM_DISPLAY_ROTATION_90:
1798 *display_angle = 90;
1800 case MM_DISPLAY_ROTATION_180:
1801 *display_angle = 180;
1803 case MM_DISPLAY_ROTATION_270:
1804 *display_angle = 270;
1807 LOGW("wrong angle type : %d", display_rotation);
1810 LOGD("check user angle: %d", *display_angle);
1814 /* Counter clockwise */
1815 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1818 if (!strcmp(org_orient, "rotate-90"))
1820 else if (!strcmp(org_orient, "rotate-180"))
1822 else if (!strcmp(org_orient, "rotate-270"))
1825 LOGD("original rotation is %s", org_orient);
1827 LOGD("content_video_orientation get fail");
1830 LOGD("check orientation: %d", *orientation);
1833 return MM_ERROR_NONE;
1836 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1838 int rotation_value = 0;
1839 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1840 int display_angle = 0;
1843 /* check video sinkbin is created */
1844 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1847 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1849 /* get rotation value to set */
1850 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1851 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1852 LOGD("set video param : rotate %d", rotation_value);
1855 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1857 MMHandleType attrs = 0;
1861 /* check video sinkbin is created */
1862 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1865 attrs = MMPLAYER_GET_ATTRS(player);
1866 MMPLAYER_RETURN_IF_FAIL(attrs);
1868 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1869 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1870 LOGD("set video param : visible %d", visible);
1873 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1875 MMHandleType attrs = 0;
1876 int display_method = 0;
1879 /* check video sinkbin is created */
1880 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1883 attrs = MMPLAYER_GET_ATTRS(player);
1884 MMPLAYER_RETURN_IF_FAIL(attrs);
1886 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1887 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1888 LOGD("set video param : method %d", display_method);
1891 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1893 MMHandleType attrs = 0;
1897 /* check video sinkbin is created */
1898 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1901 attrs = MMPLAYER_GET_ATTRS(player);
1902 MMPLAYER_RETURN_IF_FAIL(attrs);
1904 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1905 MMPLAYER_RETURN_IF_FAIL(handle);
1907 gst_video_overlay_set_video_roi_area(
1908 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1909 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1910 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1911 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1914 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1916 MMHandleType attrs = 0;
1921 int win_roi_width = 0;
1922 int win_roi_height = 0;
1925 /* check video sinkbin is created */
1926 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1929 attrs = MMPLAYER_GET_ATTRS(player);
1930 MMPLAYER_RETURN_IF_FAIL(attrs);
1932 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1933 MMPLAYER_RETURN_IF_FAIL(handle);
1935 /* It should be set after setting window */
1936 mm_attrs_multiple_get(attrs, NULL,
1937 "display_win_roi_x", &win_roi_x,
1938 "display_win_roi_y", &win_roi_y,
1939 "display_win_roi_width", &win_roi_width,
1940 "display_win_roi_height", &win_roi_height, NULL);
1942 /* After setting window handle, set display roi area */
1943 gst_video_overlay_set_display_roi_area(
1944 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1945 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1946 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1947 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1950 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1952 MMHandleType attrs = 0;
1955 /* check video sinkbin is created */
1956 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1959 attrs = MMPLAYER_GET_ATTRS(player);
1960 MMPLAYER_RETURN_IF_FAIL(attrs);
1962 /* common case if using overlay surface */
1963 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1964 MMPLAYER_RETURN_IF_FAIL(handle);
1966 /* default is using wl_surface_id */
1967 LOGD("set video param : wl_surface_id %d", handle);
1968 gst_video_overlay_set_wl_window_wl_surface_id(
1969 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1974 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1976 gboolean update_all_param = FALSE;
1980 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1981 LOGW("videosink is not ready yet");
1982 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1985 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1986 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1987 return MM_ERROR_PLAYER_INTERNAL;
1990 LOGD("param_name : %s", param_name);
1991 if (!g_strcmp0(param_name, "update_all_param"))
1992 update_all_param = TRUE;
1994 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1995 __mmplayer_video_param_set_display_overlay(player);
1996 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1997 __mmplayer_video_param_set_display_method(player);
1998 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1999 __mmplayer_video_param_set_display_visible(player);
2000 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2001 __mmplayer_video_param_set_display_rotation(player);
2002 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2003 __mmplayer_video_param_set_roi_area(player);
2004 if (update_all_param)
2005 __mmplayer_video_param_set_video_roi_area(player);
2009 return MM_ERROR_NONE;
2013 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2015 gboolean disable_overlay = FALSE;
2016 mmplayer_t *player = (mmplayer_t *)hplayer;
2019 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2020 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2021 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2022 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2024 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2025 LOGW("Display control is not supported");
2026 return MM_ERROR_PLAYER_INTERNAL;
2029 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2031 if (audio_only == (bool)disable_overlay) {
2032 LOGE("It's the same with current setting: (%d)", audio_only);
2033 return MM_ERROR_NONE;
2037 LOGE("disable overlay");
2038 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2040 /* release overlay resource */
2041 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2042 LOGE("failed to release overlay resource");
2046 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2047 LOGE("failed to acquire video overlay resource");
2050 player->interrupted_by_resource = FALSE;
2052 LOGD("enable overlay");
2053 __mmplayer_video_param_set_display_overlay(player);
2054 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2059 return MM_ERROR_NONE;
2063 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2065 mmplayer_t *player = (mmplayer_t *)hplayer;
2066 gboolean disable_overlay = FALSE;
2070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2071 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2072 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2073 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2074 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2076 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2077 LOGW("Display control is not supported");
2078 return MM_ERROR_PLAYER_INTERNAL;
2081 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2083 *paudio_only = (bool)disable_overlay;
2085 LOGD("audio_only : %d", *paudio_only);
2089 return MM_ERROR_NONE;
2093 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2095 GList *bucket = element_bucket;
2096 mmplayer_gst_element_t *element = NULL;
2097 mmplayer_gst_element_t *prv_element = NULL;
2098 GstElement *tee_element = NULL;
2099 gint successful_link_count = 0;
2103 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2105 prv_element = (mmplayer_gst_element_t *)bucket->data;
2106 bucket = bucket->next;
2108 for (; bucket; bucket = bucket->next) {
2109 element = (mmplayer_gst_element_t *)bucket->data;
2111 if (element && element->gst) {
2112 if (prv_element && prv_element->gst) {
2113 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2115 prv_element->gst = tee_element;
2117 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2118 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2119 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2123 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2124 LOGD("linking [%s] to [%s] success",
2125 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2126 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2127 successful_link_count++;
2128 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2129 LOGD("keep audio-tee element for next audio pipeline branch");
2130 tee_element = prv_element->gst;
2133 LOGD("linking [%s] to [%s] failed",
2134 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2135 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2141 prv_element = element;
2146 return successful_link_count;
2150 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2152 GList *bucket = element_bucket;
2153 mmplayer_gst_element_t *element = NULL;
2154 int successful_add_count = 0;
2158 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2159 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2161 for (; bucket; bucket = bucket->next) {
2162 element = (mmplayer_gst_element_t *)bucket->data;
2164 if (element && element->gst) {
2165 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2166 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2167 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2168 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2171 successful_add_count++;
2177 return successful_add_count;
2181 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2183 mmplayer_t *player = (mmplayer_t *)data;
2184 GstCaps *caps = NULL;
2185 GstStructure *str = NULL;
2187 gboolean caps_ret = TRUE;
2191 MMPLAYER_RETURN_IF_FAIL(pad);
2192 MMPLAYER_RETURN_IF_FAIL(unused);
2193 MMPLAYER_RETURN_IF_FAIL(data);
2195 caps = gst_pad_get_current_caps(pad);
2199 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2203 LOGD("name = %s", name);
2205 if (strstr(name, "audio")) {
2206 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2208 if (player->audio_stream_changed_cb) {
2209 LOGE("call the audio stream changed cb");
2210 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2212 } else if (strstr(name, "video")) {
2213 if ((name = gst_structure_get_string(str, "format")))
2214 player->set_mode.video_zc = name[0] == 'S';
2216 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2217 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2219 LOGW("invalid caps info");
2224 gst_caps_unref(caps);
2232 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2237 MMPLAYER_RETURN_IF_FAIL(player);
2239 if (player->audio_stream_buff_list) {
2240 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2241 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2244 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2245 __mmplayer_audio_stream_send_data(player, tmp);
2247 MMPLAYER_FREEIF(tmp->pcm_data);
2248 MMPLAYER_FREEIF(tmp);
2251 g_list_free(player->audio_stream_buff_list);
2252 player->audio_stream_buff_list = NULL;
2259 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2261 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2264 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2266 audio_stream.bitrate = a_buffer->bitrate;
2267 audio_stream.channel = a_buffer->channel;
2268 audio_stream.channel_mask = a_buffer->channel_mask;
2269 audio_stream.data_size = a_buffer->data_size;
2270 audio_stream.data = a_buffer->pcm_data;
2271 audio_stream.pcm_format = a_buffer->pcm_format;
2273 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2275 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2281 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2283 mmplayer_t *player = (mmplayer_t *)data;
2284 const gchar *pcm_format = NULL;
2287 guint64 channel_mask = 0;
2288 void *a_data = NULL;
2290 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2291 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2295 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2297 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2298 a_data = mapinfo.data;
2299 a_size = mapinfo.size;
2301 GstCaps *caps = gst_pad_get_current_caps(pad);
2302 GstStructure *structure = gst_caps_get_structure(caps, 0);
2304 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2306 pcm_format = gst_structure_get_string(structure, "format");
2307 gst_structure_get_int(structure, "rate", &rate);
2308 gst_structure_get_int(structure, "channels", &channel);
2309 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2310 gst_caps_unref(GST_CAPS(caps));
2312 /* In case of the sync is false, use buffer list. *
2313 * The num of buffer list depends on the num of audio channels */
2314 if (player->audio_stream_buff_list) {
2315 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2316 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2318 if (channel_mask == tmp->channel_mask) {
2320 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2322 if (tmp->data_size + a_size < tmp->buff_size) {
2323 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2324 tmp->data_size += a_size;
2326 /* send data to client */
2327 __mmplayer_audio_stream_send_data(player, tmp);
2329 if (a_size > tmp->buff_size) {
2330 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2331 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2332 if (tmp->pcm_data == NULL) {
2333 LOGE("failed to realloc data.");
2336 tmp->buff_size = a_size;
2338 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2339 memcpy(tmp->pcm_data, a_data, a_size);
2340 tmp->data_size = a_size;
2345 LOGE("data is empty in list.");
2351 /* create new audio stream data for newly found audio channel */
2352 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2353 if (a_buffer == NULL) {
2354 LOGE("failed to alloc data.");
2357 a_buffer->bitrate = rate;
2358 a_buffer->channel = channel;
2359 a_buffer->channel_mask = channel_mask;
2360 a_buffer->data_size = a_size;
2361 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2363 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2364 /* If sync is FALSE, use buffer list to reduce the IPC. */
2365 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2366 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2367 if (a_buffer->pcm_data == NULL) {
2368 LOGE("failed to alloc data.");
2369 MMPLAYER_FREEIF(a_buffer);
2372 memcpy(a_buffer->pcm_data, a_data, a_size);
2374 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2376 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2378 /* If sync is TRUE, send data directly. */
2379 a_buffer->pcm_data = a_data;
2380 __mmplayer_audio_stream_send_data(player, a_buffer);
2381 MMPLAYER_FREEIF(a_buffer);
2385 gst_buffer_unmap(buffer, &mapinfo);
2390 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2392 mmplayer_t *player = (mmplayer_t *)data;
2393 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2394 GstPad *sinkpad = NULL;
2395 GstElement *queue = NULL, *sink = NULL;
2398 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2400 queue = gst_element_factory_make("queue", NULL);
2401 if (queue == NULL) {
2402 LOGD("fail make queue");
2406 sink = gst_element_factory_make("fakesink", NULL);
2408 LOGD("fail make fakesink");
2412 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2414 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2415 LOGW("failed to link queue & sink");
2419 sinkpad = gst_element_get_static_pad(queue, "sink");
2421 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2422 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2426 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2428 gst_object_unref(sinkpad);
2429 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2430 g_object_set(sink, "sync", TRUE, NULL);
2431 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2433 /* keep the first sink reference only */
2434 if (!audiobin[MMPLAYER_A_SINK].gst) {
2435 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2436 audiobin[MMPLAYER_A_SINK].gst = sink;
2440 _mmplayer_add_signal_connection(player,
2442 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2444 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2447 __mmplayer_add_sink(player, sink);
2449 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2450 LOGE("failed to sync state");
2454 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2455 LOGE("failed to sync state");
2463 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2465 gst_object_unref(GST_OBJECT(queue));
2469 gst_object_unref(GST_OBJECT(sink));
2473 gst_object_unref(GST_OBJECT(sinkpad));
2481 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2483 mmplayer_t *player = (mmplayer_t *)data;
2486 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2488 player->no_more_pad = TRUE;
2489 __mmplayer_pipeline_complete(NULL, player);
2496 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2498 #define MAX_PROPS_LEN 128
2499 mmplayer_gst_element_t *audiobin = NULL;
2500 gint latency_mode = 0;
2501 gchar *stream_type = NULL;
2502 gchar *latency = NULL;
2504 gchar stream_props[MAX_PROPS_LEN] = {0,};
2505 GstStructure *props = NULL;
2508 * It should be set after player creation through attribute.
2509 * But, it can not be changed during playing.
2512 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2514 audiobin = player->pipeline->audiobin;
2516 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2517 if (player->sound.mute) {
2518 LOGD("mute enabled");
2519 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2522 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2523 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2526 snprintf(stream_props, sizeof(stream_props) - 1,
2527 "props,application.process.id.origin=%d", player->client_pid);
2529 snprintf(stream_props, sizeof(stream_props) - 1,
2530 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2531 stream_type, stream_id, player->client_pid);
2533 props = gst_structure_from_string(stream_props, NULL);
2534 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2535 LOGI("props result[%s].", stream_props);
2536 gst_structure_free(props);
2538 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2540 switch (latency_mode) {
2541 case AUDIO_LATENCY_MODE_LOW:
2542 latency = g_strndup("low", 3);
2544 case AUDIO_LATENCY_MODE_MID:
2545 latency = g_strndup("mid", 3);
2547 case AUDIO_LATENCY_MODE_HIGH:
2548 latency = g_strndup("high", 4);
2552 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2554 LOGD("audiosink property - latency=%s", latency);
2556 MMPLAYER_FREEIF(latency);
2562 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2564 mmplayer_gst_element_t *audiobin = NULL;
2567 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2569 audiobin = player->pipeline->audiobin;
2571 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2572 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2573 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2575 if (player->video360_yaw_radians <= M_PI &&
2576 player->video360_yaw_radians >= -M_PI &&
2577 player->video360_pitch_radians <= M_PI_2 &&
2578 player->video360_pitch_radians >= -M_PI_2) {
2579 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2580 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2581 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2582 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2583 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2584 "source-orientation-y", player->video360_metadata.init_view_heading,
2585 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2592 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2594 mmplayer_gst_element_t *audiobin = NULL;
2595 GstPad *sink_pad = NULL;
2596 GstCaps *acaps = NULL;
2598 int pitch_control = 0;
2599 double pitch_value = 1.0;
2602 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2603 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2605 audiobin = player->pipeline->audiobin;
2607 LOGD("make element for normal audio playback");
2609 /* audio bin structure for playback. {} means optional.
2610 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2612 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2613 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2616 /* for pitch control */
2617 mm_attrs_multiple_get(player->attrs, NULL,
2618 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2619 MM_PLAYER_PITCH_VALUE, &pitch_value,
2622 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2623 if (pitch_control && (player->videodec_linked == 0)) {
2624 GstElementFactory *factory;
2626 factory = gst_element_factory_find("pitch");
2628 gst_object_unref(factory);
2631 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2634 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2635 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2637 LOGW("there is no pitch element");
2642 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2644 /* replaygain volume */
2645 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2646 if (player->sound.rg_enable)
2647 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2649 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2652 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2654 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2655 /* currently, only openalsink uses volume element */
2656 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2659 if (player->sound.mute) {
2660 LOGD("mute enabled");
2661 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2665 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2667 /* audio effect element. if audio effect is enabled */
2668 if ((strcmp(player->ini.audioeffect_element, ""))
2670 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2671 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2673 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2675 if ((!player->bypass_audio_effect)
2676 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2677 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2678 if (!_mmplayer_audio_effect_custom_apply(player))
2679 LOGI("apply audio effect(custom) setting success");
2683 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2684 && (player->set_mode.rich_audio)) {
2685 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2689 /* create audio sink */
2690 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2691 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2692 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2694 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2695 if (player->is_360_feature_enabled &&
2696 player->is_content_spherical &&
2698 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2699 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2700 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2702 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2704 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2706 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2707 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2708 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2709 gst_caps_unref(acaps);
2711 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2713 player->is_openal_plugin_used = TRUE;
2715 if (player->is_360_feature_enabled && player->is_content_spherical)
2716 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2717 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2720 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2721 (player->videodec_linked && player->ini.use_system_clock)) {
2722 LOGD("system clock will be used.");
2723 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2726 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2727 __mmplayer_gst_set_pulsesink_property(player);
2728 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2729 __mmplayer_gst_set_openalsink_property(player);
2732 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2735 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2736 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2737 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2738 gst_object_unref(GST_OBJECT(sink_pad));
2740 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2743 return MM_ERROR_NONE;
2745 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2747 return MM_ERROR_PLAYER_INTERNAL;
2751 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2753 mmplayer_gst_element_t *audiobin = NULL;
2754 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2756 gchar *dst_format = NULL;
2758 int dst_samplerate = 0;
2759 int dst_channels = 0;
2760 GstCaps *caps = NULL;
2761 char *caps_str = NULL;
2764 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2765 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2767 audiobin = player->pipeline->audiobin;
2769 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2771 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2773 [case 1] extract interleave audio pcm without playback
2774 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2775 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2777 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2779 [case 2] deinterleave for each channel without playback
2780 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2781 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2783 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2784 - fakesink (sync or not)
2787 [case 3] [case 1(sync only)] + playback
2788 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2790 * src - ... - tee - queue1 - playback path
2791 - queue2 - [case1 pipeline with sync]
2793 [case 4] [case 2(sync only)] + playback
2794 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2796 * src - ... - tee - queue1 - playback path
2797 - queue2 - [case2 pipeline with sync]
2801 /* 1. create tee and playback path
2802 'tee' should be added at first to copy the decoded stream
2804 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2805 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2806 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2808 /* tee - path 1 : for playback path */
2809 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2810 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2812 /* tee - path 2 : for extract path */
2813 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2814 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2817 /* if there is tee, 'tee - path 2' is linked here */
2819 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2822 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2824 /* 2. decide the extract pcm format */
2825 mm_attrs_multiple_get(player->attrs, NULL,
2826 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2827 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2828 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2831 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2832 dst_format, dst_len, dst_samplerate, dst_channels);
2834 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2835 mm_attrs_multiple_get(player->attrs, NULL,
2836 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2837 "content_audio_samplerate", &dst_samplerate,
2838 "content_audio_channels", &dst_channels,
2841 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2842 dst_format, dst_len, dst_samplerate, dst_channels);
2844 /* If there is no enough information, set it to platform default value. */
2845 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2846 LOGD("set platform default format");
2847 dst_format = DEFAULT_PCM_OUT_FORMAT;
2849 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2850 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2853 /* 3. create capsfilter */
2854 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2855 caps = gst_caps_new_simple("audio/x-raw",
2856 "format", G_TYPE_STRING, dst_format,
2857 "rate", G_TYPE_INT, dst_samplerate,
2858 "channels", G_TYPE_INT, dst_channels,
2861 caps_str = gst_caps_to_string(caps);
2862 LOGD("new caps : %s", caps_str);
2864 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2867 gst_caps_unref(caps);
2868 MMPLAYER_FREEIF(caps_str);
2870 /* 4-1. create deinterleave to extract pcm for each channel */
2871 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2872 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2873 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2875 /* audiosink will be added after getting signal for each channel */
2876 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2877 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2878 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2879 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2880 player->no_more_pad = FALSE;
2882 /* 4-2. create fakesink to extract interlevaed pcm */
2883 LOGD("add audio fakesink for interleaved audio");
2884 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2885 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2886 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2887 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2889 _mmplayer_add_signal_connection(player,
2890 G_OBJECT(audiobin[extract_sink_id].gst),
2891 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2893 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2896 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2900 return MM_ERROR_NONE;
2902 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2904 return MM_ERROR_PLAYER_INTERNAL;
2908 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2910 int ret = MM_ERROR_NONE;
2911 mmplayer_gst_element_t *audiobin = NULL;
2912 GList *element_bucket = NULL;
2915 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2916 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2918 audiobin = player->pipeline->audiobin;
2920 if (player->build_audio_offload) { /* skip all the audio filters */
2921 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2923 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2924 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2925 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2927 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2931 /* FIXME: need to mention the supportable condition at API reference */
2932 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2933 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2935 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2937 if (ret != MM_ERROR_NONE)
2940 LOGD("success to make audio bin element");
2941 *bucket = element_bucket;
2944 return MM_ERROR_NONE;
2947 LOGE("failed to make audio bin element");
2948 g_list_free(element_bucket);
2952 return MM_ERROR_PLAYER_INTERNAL;
2956 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2958 mmplayer_gst_element_t *first_element = NULL;
2959 mmplayer_gst_element_t *audiobin = NULL;
2961 GstPad *ghostpad = NULL;
2962 GList *element_bucket = NULL;
2966 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2969 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2971 LOGE("failed to allocate memory for audiobin");
2972 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2976 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2977 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2978 if (!audiobin[MMPLAYER_A_BIN].gst) {
2979 LOGE("failed to create audiobin");
2984 player->pipeline->audiobin = audiobin;
2986 /* create audio filters and audiosink */
2987 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2990 /* adding created elements to bin */
2991 LOGD("adding created elements to bin");
2992 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
2995 /* linking elements in the bucket by added order. */
2996 LOGD("Linking elements in the bucket by added order.");
2997 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3000 /* get first element's sinkpad for creating ghostpad */
3001 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3002 if (!first_element) {
3003 LOGE("failed to get first elem");
3007 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3009 LOGE("failed to get pad from first element of audiobin");
3013 ghostpad = gst_ghost_pad_new("sink", pad);
3015 LOGE("failed to create ghostpad");
3019 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3020 LOGE("failed to add ghostpad to audiobin");
3024 gst_object_unref(pad);
3026 g_list_free(element_bucket);
3029 return MM_ERROR_NONE;
3032 LOGD("ERROR : releasing audiobin");
3035 gst_object_unref(GST_OBJECT(pad));
3038 gst_object_unref(GST_OBJECT(ghostpad));
3041 g_list_free(element_bucket);
3043 /* release element which are not added to bin */
3044 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3045 /* NOTE : skip bin */
3046 if (audiobin[i].gst) {
3047 GstObject *parent = NULL;
3048 parent = gst_element_get_parent(audiobin[i].gst);
3051 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3052 audiobin[i].gst = NULL;
3054 gst_object_unref(GST_OBJECT(parent));
3058 /* release audiobin with it's childs */
3059 if (audiobin[MMPLAYER_A_BIN].gst)
3060 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3062 MMPLAYER_FREEIF(audiobin);
3064 player->pipeline->audiobin = NULL;
3066 return MM_ERROR_PLAYER_INTERNAL;
3070 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3072 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3076 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3078 int ret = MM_ERROR_NONE;
3080 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3081 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3083 MMPLAYER_VIDEO_BO_LOCK(player);
3085 if (player->video_bo_list) {
3086 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3087 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3088 if (tmp && tmp->bo == bo) {
3090 LOGD("release bo %p", bo);
3091 tbm_bo_unref(tmp->bo);
3092 MMPLAYER_VIDEO_BO_UNLOCK(player);
3093 MMPLAYER_VIDEO_BO_SIGNAL(player);
3098 /* hw codec is running or the list was reset for DRC. */
3099 LOGW("there is no bo list.");
3101 MMPLAYER_VIDEO_BO_UNLOCK(player);
3103 LOGW("failed to find bo %p", bo);
3108 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3113 MMPLAYER_RETURN_IF_FAIL(player);
3115 MMPLAYER_VIDEO_BO_LOCK(player);
3116 if (player->video_bo_list) {
3117 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3118 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3119 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3122 tbm_bo_unref(tmp->bo);
3126 g_list_free(player->video_bo_list);
3127 player->video_bo_list = NULL;
3129 player->video_bo_size = 0;
3130 MMPLAYER_VIDEO_BO_UNLOCK(player);
3137 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3140 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3141 gboolean ret = TRUE;
3143 /* check DRC, if it is, destroy the prev bo list to create again */
3144 if (player->video_bo_size != size) {
3145 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3146 __mmplayer_video_stream_destroy_bo_list(player);
3147 player->video_bo_size = size;
3150 MMPLAYER_VIDEO_BO_LOCK(player);
3152 if ((!player->video_bo_list) ||
3153 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3155 /* create bo list */
3157 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3159 if (player->video_bo_list) {
3160 /* if bo list did not created all, try it again. */
3161 idx = g_list_length(player->video_bo_list);
3162 LOGD("bo list exist(len: %d)", idx);
3165 for (; idx < player->ini.num_of_video_bo; idx++) {
3166 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3168 LOGE("Fail to alloc bo_info.");
3171 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3173 LOGE("Fail to tbm_bo_alloc.");
3174 MMPLAYER_FREEIF(bo_info);
3177 bo_info->used = FALSE;
3178 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3181 /* update video num buffers */
3182 LOGD("video_num_buffers : %d", idx);
3183 mm_player_set_attribute((MMHandleType)player, NULL,
3184 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3185 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3189 MMPLAYER_VIDEO_BO_UNLOCK(player);
3195 /* get bo from list*/
3196 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3197 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3198 if (tmp && (tmp->used == FALSE)) {
3199 LOGD("found bo %p to use", tmp->bo);
3201 MMPLAYER_VIDEO_BO_UNLOCK(player);
3202 return tbm_bo_ref(tmp->bo);
3206 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3207 MMPLAYER_VIDEO_BO_UNLOCK(player);
3211 if (player->ini.video_bo_timeout <= 0) {
3212 MMPLAYER_VIDEO_BO_WAIT(player);
3214 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3215 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3222 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3224 mmplayer_t *player = (mmplayer_t *)data;
3226 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3228 /* send prerolled pkt */
3229 player->video_stream_prerolled = false;
3231 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3233 /* not to send prerolled pkt again */
3234 player->video_stream_prerolled = true;
3238 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3240 mmplayer_t *player = (mmplayer_t *)data;
3241 mmplayer_video_decoded_data_info_t *stream = NULL;
3242 GstMemory *mem = NULL;
3245 MMPLAYER_RETURN_IF_FAIL(player);
3246 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3248 if (player->video_stream_prerolled) {
3249 player->video_stream_prerolled = false;
3250 LOGD("skip the prerolled pkt not to send it again");
3254 /* clear stream data structure */
3255 stream = __mmplayer_create_stream_from_pad(pad);
3257 LOGE("failed to alloc stream");
3261 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3263 /* set size and timestamp */
3264 mem = gst_buffer_peek_memory(buffer, 0);
3265 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3266 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3268 /* check zero-copy */
3269 if (player->set_mode.video_zc &&
3270 player->set_mode.video_export &&
3271 gst_is_tizen_memory(mem)) {
3272 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3273 stream->internal_buffer = gst_buffer_ref(buffer);
3274 } else { /* sw codec */
3275 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3278 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3282 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3283 LOGE("failed to send video decoded data.");
3290 LOGE("release video stream resource.");
3291 if (gst_is_tizen_memory(mem)) {
3293 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3295 tbm_bo_unref(stream->bo[i]);
3298 /* unref gst buffer */
3299 if (stream->internal_buffer)
3300 gst_buffer_unref(stream->internal_buffer);
3303 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3305 MMPLAYER_FREEIF(stream);
3310 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3312 mmplayer_gst_element_t *videobin = NULL;
3315 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3317 videobin = player->pipeline->videobin;
3319 /* Set spatial media metadata and/or user settings to the element.
3321 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3322 "projection-type", player->video360_metadata.projection_type, NULL);
3324 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3325 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3327 if (player->video360_metadata.full_pano_width_pixels &&
3328 player->video360_metadata.full_pano_height_pixels &&
3329 player->video360_metadata.cropped_area_image_width &&
3330 player->video360_metadata.cropped_area_image_height) {
3331 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3332 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3333 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3334 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3335 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3336 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3337 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3341 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3342 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3343 "horizontal-fov", player->video360_horizontal_fov,
3344 "vertical-fov", player->video360_vertical_fov, NULL);
3347 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3348 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3349 "zoom", 1.0f / player->video360_zoom, NULL);
3352 if (player->video360_yaw_radians <= M_PI &&
3353 player->video360_yaw_radians >= -M_PI &&
3354 player->video360_pitch_radians <= M_PI_2 &&
3355 player->video360_pitch_radians >= -M_PI_2) {
3356 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3357 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3358 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3359 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3360 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3361 "pose-yaw", player->video360_metadata.init_view_heading,
3362 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3365 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3366 "passthrough", !player->is_video360_enabled, NULL);
3373 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3375 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3376 GList *element_bucket = NULL;
3379 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3381 /* create video360 filter */
3382 if (player->is_360_feature_enabled && player->is_content_spherical) {
3383 LOGD("create video360 element");
3384 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3385 __mmplayer_gst_set_video360_property(player);
3389 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3390 LOGD("skip creating the videoconv and rotator");
3391 return MM_ERROR_NONE;
3394 /* in case of sw codec & overlay surface type, except 360 playback.
3395 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3396 LOGD("create video converter: %s", video_csc);
3397 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3400 *bucket = element_bucket;
3402 return MM_ERROR_NONE;
3404 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3405 g_list_free(element_bucket);
3409 return MM_ERROR_PLAYER_INTERNAL;
3413 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3415 gchar *factory_name = NULL;
3417 switch (surface_type) {
3418 case MM_DISPLAY_SURFACE_OVERLAY:
3419 if (strlen(player->ini.videosink_element_overlay) > 0)
3420 factory_name = player->ini.videosink_element_overlay;
3422 case MM_DISPLAY_SURFACE_REMOTE:
3423 case MM_DISPLAY_SURFACE_NULL:
3424 if (strlen(player->ini.videosink_element_fake) > 0)
3425 factory_name = player->ini.videosink_element_fake;
3428 LOGE("unidentified surface type");
3432 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3433 return factory_name;
3437 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3439 gchar *factory_name = NULL;
3440 mmplayer_gst_element_t *videobin = NULL;
3445 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3447 videobin = player->pipeline->videobin;
3448 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3450 attrs = MMPLAYER_GET_ATTRS(player);
3452 LOGE("cannot get content attribute");
3453 return MM_ERROR_PLAYER_INTERNAL;
3456 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3457 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3458 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3460 /* support shard memory with S/W codec on HawkP */
3461 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3462 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3463 "use-tbm", use_tbm, NULL);
3467 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3468 return MM_ERROR_PLAYER_INTERNAL;
3470 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3471 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3474 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3476 LOGD("disable last-sample");
3477 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3480 if (player->set_mode.video_export) {
3482 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3483 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3484 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3486 _mmplayer_add_signal_connection(player,
3487 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3488 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3490 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3493 _mmplayer_add_signal_connection(player,
3494 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3495 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3497 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3501 if (videobin[MMPLAYER_V_SINK].gst) {
3502 GstPad *sink_pad = NULL;
3503 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3505 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3506 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3507 gst_object_unref(GST_OBJECT(sink_pad));
3509 LOGE("failed to get sink pad from videosink");
3513 return MM_ERROR_NONE;
3518 * - video overlay surface(arm/x86) : tizenwlsink
3521 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3524 GList *element_bucket = NULL;
3525 mmplayer_gst_element_t *first_element = NULL;
3526 mmplayer_gst_element_t *videobin = NULL;
3527 gchar *videosink_factory_name = NULL;
3530 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3533 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3535 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3537 player->pipeline->videobin = videobin;
3540 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3541 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3542 if (!videobin[MMPLAYER_V_BIN].gst) {
3543 LOGE("failed to create videobin");
3547 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3550 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3551 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3553 /* additional setting for sink plug-in */
3554 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3555 LOGE("failed to set video property");
3559 /* store it as it's sink element */
3560 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3562 /* adding created elements to bin */
3563 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3564 LOGE("failed to add elements");
3568 /* Linking elements in the bucket by added order */
3569 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3570 LOGE("failed to link elements");
3574 /* get first element's sinkpad for creating ghostpad */
3575 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3576 if (!first_element) {
3577 LOGE("failed to get first element from bucket");
3581 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3583 LOGE("failed to get pad from first element");
3587 /* create ghostpad */
3588 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3589 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3590 LOGE("failed to add ghostpad to videobin");
3593 gst_object_unref(pad);
3595 /* done. free allocated variables */
3596 g_list_free(element_bucket);
3600 return MM_ERROR_NONE;
3603 LOGE("ERROR : releasing videobin");
3604 g_list_free(element_bucket);
3607 gst_object_unref(GST_OBJECT(pad));
3609 /* release videobin with it's childs */
3610 if (videobin[MMPLAYER_V_BIN].gst)
3611 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3613 MMPLAYER_FREEIF(videobin);
3614 player->pipeline->videobin = NULL;
3616 return MM_ERROR_PLAYER_INTERNAL;
3620 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3622 GList *element_bucket = NULL;
3623 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3625 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3626 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3627 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3628 "signal-handoffs", FALSE,
3631 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3632 _mmplayer_add_signal_connection(player,
3633 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3634 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3636 G_CALLBACK(__mmplayer_update_subtitle),
3639 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3640 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3642 if (!player->play_subtitle) {
3643 LOGD("add textbin sink as sink element of whole pipeline.");
3644 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3647 /* adding created elements to bin */
3648 LOGD("adding created elements to bin");
3649 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3650 LOGE("failed to add elements");
3654 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3655 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3656 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3658 /* linking elements in the bucket by added order. */
3659 LOGD("Linking elements in the bucket by added order.");
3660 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3661 LOGE("failed to link elements");
3665 /* done. free allocated variables */
3666 g_list_free(element_bucket);
3668 if (textbin[MMPLAYER_T_QUEUE].gst) {
3670 GstPad *ghostpad = NULL;
3672 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3674 LOGE("failed to get sink pad of text queue");
3678 ghostpad = gst_ghost_pad_new("text_sink", pad);
3679 gst_object_unref(pad);
3682 LOGE("failed to create ghostpad of textbin");
3686 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3687 LOGE("failed to add ghostpad to textbin");
3688 gst_object_unref(ghostpad);
3693 return MM_ERROR_NONE;
3696 g_list_free(element_bucket);
3698 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3699 LOGE("remove textbin sink from sink list");
3700 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3703 /* release element at __mmplayer_gst_create_text_sink_bin */
3704 return MM_ERROR_PLAYER_INTERNAL;
3708 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3710 mmplayer_gst_element_t *textbin = NULL;
3711 GList *element_bucket = NULL;
3712 int surface_type = 0;
3717 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3720 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3722 LOGE("failed to allocate memory for textbin");
3723 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3727 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3728 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3729 if (!textbin[MMPLAYER_T_BIN].gst) {
3730 LOGE("failed to create textbin");
3735 player->pipeline->textbin = textbin;
3738 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3739 LOGD("surface type for subtitle : %d", surface_type);
3740 switch (surface_type) {
3741 case MM_DISPLAY_SURFACE_OVERLAY:
3742 case MM_DISPLAY_SURFACE_NULL:
3743 case MM_DISPLAY_SURFACE_REMOTE:
3744 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3745 LOGE("failed to make plain text elements");
3756 return MM_ERROR_NONE;
3760 LOGD("ERROR : releasing textbin");
3762 g_list_free(element_bucket);
3764 /* release signal */
3765 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3767 /* release element which are not added to bin */
3768 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3769 /* NOTE : skip bin */
3770 if (textbin[i].gst) {
3771 GstObject *parent = NULL;
3772 parent = gst_element_get_parent(textbin[i].gst);
3775 gst_object_unref(GST_OBJECT(textbin[i].gst));
3776 textbin[i].gst = NULL;
3778 gst_object_unref(GST_OBJECT(parent));
3783 /* release textbin with it's childs */
3784 if (textbin[MMPLAYER_T_BIN].gst)
3785 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3787 MMPLAYER_FREEIF(player->pipeline->textbin);
3788 player->pipeline->textbin = NULL;
3791 return MM_ERROR_PLAYER_INTERNAL;
3795 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3797 mmplayer_gst_element_t *mainbin = NULL;
3798 mmplayer_gst_element_t *textbin = NULL;
3799 MMHandleType attrs = 0;
3800 GstElement *subsrc = NULL;
3801 GstElement *subparse = NULL;
3802 gchar *subtitle_uri = NULL;
3803 const gchar *charset = NULL;
3809 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3811 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3813 mainbin = player->pipeline->mainbin;
3815 attrs = MMPLAYER_GET_ATTRS(player);
3817 LOGE("cannot get content attribute");
3818 return MM_ERROR_PLAYER_INTERNAL;
3821 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3822 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3823 LOGE("subtitle uri is not proper filepath.");
3824 return MM_ERROR_PLAYER_INVALID_URI;
3827 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3828 LOGE("failed to get storage info of subtitle path");
3829 return MM_ERROR_PLAYER_INVALID_URI;
3832 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3834 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3835 player->subtitle_language_list = NULL;
3836 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3838 /* create the subtitle source */
3839 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3841 LOGE("failed to create filesrc element");
3844 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3846 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3847 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3849 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3850 LOGW("failed to add queue");
3851 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3852 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3853 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3858 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3860 LOGE("failed to create subparse element");
3864 charset = _mmplayer_get_charset(subtitle_uri);
3866 LOGD("detected charset is %s", charset);
3867 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3870 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3871 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3873 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3874 LOGW("failed to add subparse");
3875 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3876 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3877 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3881 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3882 LOGW("failed to link subsrc and subparse");
3886 player->play_subtitle = TRUE;
3887 player->adjust_subtitle_pos = 0;
3889 LOGD("play subtitle using subtitle file");
3891 if (player->pipeline->textbin == NULL) {
3892 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3893 LOGE("failed to create text sink bin. continuing without text");
3897 textbin = player->pipeline->textbin;
3899 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3900 LOGW("failed to add textbin");
3902 /* release signal */
3903 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3905 /* release textbin with it's childs */
3906 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3907 MMPLAYER_FREEIF(player->pipeline->textbin);
3908 player->pipeline->textbin = textbin = NULL;
3912 LOGD("link text input selector and textbin ghost pad");
3914 player->textsink_linked = 1;
3915 player->external_text_idx = 0;
3916 LOGI("textsink is linked");
3918 textbin = player->pipeline->textbin;
3919 LOGD("text bin has been created. reuse it.");
3920 player->external_text_idx = 1;
3923 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3924 LOGW("failed to link subparse and textbin");
3928 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3930 LOGE("failed to get sink pad from textsink to probe data");
3934 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3935 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3937 gst_object_unref(pad);
3940 /* create dot. for debugging */
3941 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3944 return MM_ERROR_NONE;
3947 /* release text pipeline resource */
3948 player->textsink_linked = 0;
3950 /* release signal */
3951 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3953 if (player->pipeline->textbin) {
3954 LOGE("remove textbin");
3956 /* release textbin with it's childs */
3957 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3958 MMPLAYER_FREEIF(player->pipeline->textbin);
3959 player->pipeline->textbin = NULL;
3963 /* release subtitle elem */
3964 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3965 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3967 return MM_ERROR_PLAYER_INTERNAL;
3971 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3973 mmplayer_t *player = (mmplayer_t *)data;
3974 MMMessageParamType msg = {0, };
3975 GstClockTime duration = 0;
3976 gpointer text = NULL;
3977 guint text_size = 0;
3978 gboolean ret = TRUE;
3979 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3983 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3984 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3986 if (player->is_subtitle_force_drop) {
3987 LOGW("subtitle is dropped forcedly.");
3991 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
3992 text = mapinfo.data;
3993 text_size = mapinfo.size;
3995 if (player->set_mode.subtitle_off) {
3996 LOGD("subtitle is OFF.");
4000 if (!text || (text_size == 0)) {
4001 LOGD("There is no subtitle to be displayed.");
4005 msg.data = (void *)text;
4007 duration = GST_BUFFER_DURATION(buffer);
4009 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4010 if (player->duration > GST_BUFFER_PTS(buffer))
4011 duration = player->duration - GST_BUFFER_PTS(buffer);
4014 LOGI("subtitle duration is invalid, subtitle duration change "
4015 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4017 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4019 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4021 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4022 gst_buffer_unmap(buffer, &mapinfo);
4029 static GstPadProbeReturn
4030 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4032 mmplayer_t *player = (mmplayer_t *)u_data;
4033 GstClockTime cur_timestamp = 0;
4034 gint64 adjusted_timestamp = 0;
4035 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4037 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4039 if (player->set_mode.subtitle_off) {
4040 LOGD("subtitle is OFF.");
4044 if (player->adjust_subtitle_pos == 0) {
4045 LOGD("nothing to do");
4049 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4050 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4052 if (adjusted_timestamp < 0) {
4053 LOGD("adjusted_timestamp under zero");
4058 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4059 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4060 GST_TIME_ARGS(cur_timestamp),
4061 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4063 return GST_PAD_PROBE_OK;
4067 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4071 /* check player and subtitlebin are created */
4072 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4073 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4075 if (position == 0) {
4076 LOGD("nothing to do");
4078 return MM_ERROR_NONE;
4081 /* check current postion */
4082 player->adjust_subtitle_pos = position;
4084 LOGD("save adjust_subtitle_pos in player");
4088 return MM_ERROR_NONE;
4092 * This function is to create audio or video pipeline for playing.
4094 * @param player [in] handle of player
4096 * @return This function returns zero on success.
4101 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4103 int ret = MM_ERROR_NONE;
4104 mmplayer_gst_element_t *mainbin = NULL;
4105 MMHandleType attrs = 0;
4108 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4110 /* get profile attribute */
4111 attrs = MMPLAYER_GET_ATTRS(player);
4113 LOGE("failed to get content attribute");
4117 /* create pipeline handles */
4118 if (player->pipeline) {
4119 LOGE("pipeline should be released before create new one");
4123 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4125 /* create mainbin */
4126 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4127 if (mainbin == NULL)
4130 /* create pipeline */
4131 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4132 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4133 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4134 LOGE("failed to create pipeline");
4139 player->pipeline->mainbin = mainbin;
4141 /* create the source and decoder elements */
4142 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4143 ret = _mmplayer_gst_build_es_pipeline(player);
4145 ret = _mmplayer_gst_build_pipeline(player);
4147 if (ret != MM_ERROR_NONE) {
4148 LOGE("failed to create some elements");
4152 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4153 if (__mmplayer_check_subtitle(player)
4154 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4155 LOGE("failed to create text pipeline");
4158 ret = _mmplayer_gst_add_bus_watch(player);
4159 if (ret != MM_ERROR_NONE) {
4160 LOGE("failed to add bus watch");
4165 return MM_ERROR_NONE;
4168 __mmplayer_gst_destroy_pipeline(player);
4169 return MM_ERROR_PLAYER_INTERNAL;
4173 __mmplayer_reset_gapless_state(mmplayer_t *player)
4176 MMPLAYER_RETURN_IF_FAIL(player
4178 && player->pipeline->audiobin
4179 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4181 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4188 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4191 int ret = MM_ERROR_NONE;
4195 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4197 /* cleanup stuffs */
4198 MMPLAYER_FREEIF(player->type);
4199 player->no_more_pad = FALSE;
4200 player->num_dynamic_pad = 0;
4201 player->demux_pad_index = 0;
4203 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4204 player->subtitle_language_list = NULL;
4205 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4207 __mmplayer_reset_gapless_state(player);
4209 if (player->streamer) {
4210 _mm_player_streaming_initialize(player->streamer, FALSE);
4211 _mm_player_streaming_destroy(player->streamer);
4212 player->streamer = NULL;
4215 /* cleanup unlinked mime type */
4216 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4217 MMPLAYER_FREEIF(player->unlinked_video_mime);
4218 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4220 /* cleanup running stuffs */
4221 _mmplayer_cancel_eos_timer(player);
4223 /* cleanup gst stuffs */
4224 if (player->pipeline) {
4225 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4226 GstTagList *tag_list = player->pipeline->tag_list;
4228 /* first we need to disconnect all signal hander */
4229 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4232 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4233 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4234 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4235 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4236 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4237 gst_object_unref(bus);
4239 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4240 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4241 if (ret != MM_ERROR_NONE) {
4242 LOGE("fail to change state to NULL");
4243 return MM_ERROR_PLAYER_INTERNAL;
4246 LOGW("succeeded in changing state to NULL");
4248 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4251 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4252 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4254 /* free avsysaudiosink
4255 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4256 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4258 MMPLAYER_FREEIF(audiobin);
4259 MMPLAYER_FREEIF(videobin);
4260 MMPLAYER_FREEIF(textbin);
4261 MMPLAYER_FREEIF(mainbin);
4265 gst_tag_list_unref(tag_list);
4267 MMPLAYER_FREEIF(player->pipeline);
4269 MMPLAYER_FREEIF(player->album_art);
4271 if (player->v_stream_caps) {
4272 gst_caps_unref(player->v_stream_caps);
4273 player->v_stream_caps = NULL;
4276 if (player->a_stream_caps) {
4277 gst_caps_unref(player->a_stream_caps);
4278 player->a_stream_caps = NULL;
4281 if (player->s_stream_caps) {
4282 gst_caps_unref(player->s_stream_caps);
4283 player->s_stream_caps = NULL;
4285 _mmplayer_track_destroy(player);
4287 if (player->sink_elements)
4288 g_list_free(player->sink_elements);
4289 player->sink_elements = NULL;
4291 if (player->bufmgr) {
4292 tbm_bufmgr_deinit(player->bufmgr);
4293 player->bufmgr = NULL;
4296 LOGW("finished destroy pipeline");
4304 __mmplayer_gst_realize(mmplayer_t *player)
4307 int ret = MM_ERROR_NONE;
4311 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4313 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4315 ret = __mmplayer_gst_create_pipeline(player);
4317 LOGE("failed to create pipeline");
4321 /* set pipeline state to READY */
4322 /* NOTE : state change to READY must be performed sync. */
4323 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4324 ret = _mmplayer_gst_set_state(player,
4325 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4327 if (ret != MM_ERROR_NONE) {
4328 /* return error if failed to set state */
4329 LOGE("failed to set READY state");
4333 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4335 /* create dot before error-return. for debugging */
4336 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4344 __mmplayer_gst_unrealize(mmplayer_t *player)
4346 int ret = MM_ERROR_NONE;
4350 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4352 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4353 MMPLAYER_PRINT_STATE(player);
4355 /* release miscellaneous information */
4356 __mmplayer_release_misc(player);
4358 /* destroy pipeline */
4359 ret = __mmplayer_gst_destroy_pipeline(player);
4360 if (ret != MM_ERROR_NONE) {
4361 LOGE("failed to destory pipeline");
4365 /* release miscellaneous information.
4366 these info needs to be released after pipeline is destroyed. */
4367 __mmplayer_release_misc_post(player);
4369 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4377 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4382 LOGW("set_message_callback is called with invalid player handle");
4383 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4386 player->msg_cb = callback;
4387 player->msg_cb_param = user_param;
4389 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4393 return MM_ERROR_NONE;
4397 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4399 int ret = MM_ERROR_NONE;
4404 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4405 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4406 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4408 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4410 if (strstr(uri, "es_buff://")) {
4411 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4412 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4413 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4414 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4416 tmp = g_ascii_strdown(uri, strlen(uri));
4417 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4418 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4420 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4422 } else if (strstr(uri, "mms://")) {
4423 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4424 } else if ((path = strstr(uri, "mem://"))) {
4425 ret = __mmplayer_set_mem_uri(data, path, param);
4427 ret = __mmplayer_set_file_uri(data, uri);
4430 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4431 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4432 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4433 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4435 /* dump parse result */
4436 SECURE_LOGW("incoming uri : %s", uri);
4437 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4438 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4446 __mmplayer_can_do_interrupt(mmplayer_t *player)
4448 if (!player || !player->pipeline || !player->attrs) {
4449 LOGW("not initialized");
4453 if (player->audio_decoded_cb) {
4454 LOGW("not support in pcm extraction mode");
4458 /* check if seeking */
4459 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4460 MMMessageParamType msg_param;
4461 memset(&msg_param, 0, sizeof(MMMessageParamType));
4462 msg_param.code = MM_ERROR_PLAYER_SEEK;
4463 player->seek_state = MMPLAYER_SEEK_NONE;
4464 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4468 /* check other thread */
4469 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4470 LOGW("locked already, cmd state : %d", player->cmd);
4472 /* check application command */
4473 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4474 LOGW("playing.. should wait cmd lock then, will be interrupted");
4476 /* lock will be released at mrp_resource_release_cb() */
4477 MMPLAYER_CMD_LOCK(player);
4480 LOGW("nothing to do");
4483 LOGW("can interrupt immediately");
4487 FAILED: /* with CMD UNLOCKED */
4490 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4495 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4498 mmplayer_t *player = NULL;
4499 MMMessageParamType msg = {0, };
4501 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4506 LOGE("user_data is null");
4509 player = (mmplayer_t *)user_data;
4511 if (!__mmplayer_can_do_interrupt(player)) {
4512 LOGW("no need to interrupt, so leave");
4513 /* FIXME: there is no way to avoid releasing resource. */
4517 player->interrupted_by_resource = TRUE;
4519 /* get last play position */
4520 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4521 msg.union_type = MM_MSG_UNION_TIME;
4522 msg.time.elapsed = pos;
4523 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4525 LOGW("failed to get play position.");
4528 LOGD("video resource conflict so, resource will be freed by unrealizing");
4529 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4530 LOGE("failed to unrealize");
4532 /* lock is called in __mmplayer_can_do_interrupt() */
4533 MMPLAYER_CMD_UNLOCK(player);
4535 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4536 player->hw_resource[res_idx] = NULL;
4540 return TRUE; /* release all the resources */
4544 __mmplayer_initialize_video_roi(mmplayer_t *player)
4546 player->video_roi.scale_x = 0.0;
4547 player->video_roi.scale_y = 0.0;
4548 player->video_roi.scale_width = 1.0;
4549 player->video_roi.scale_height = 1.0;
4553 _mmplayer_create_player(MMHandleType handle)
4555 int ret = MM_ERROR_PLAYER_INTERNAL;
4556 bool enabled = false;
4558 mmplayer_t *player = MM_PLAYER_CAST(handle);
4562 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4564 /* initialize player state */
4565 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4566 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4567 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4568 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4570 /* check current state */
4571 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4573 /* construct attributes */
4574 player->attrs = _mmplayer_construct_attribute(handle);
4576 if (!player->attrs) {
4577 LOGE("Failed to construct attributes");
4581 /* initialize gstreamer with configured parameter */
4582 if (!__mmplayer_init_gstreamer(player)) {
4583 LOGE("Initializing gstreamer failed");
4584 _mmplayer_deconstruct_attribute(handle);
4588 /* create lock. note that g_tread_init() has already called in gst_init() */
4589 g_mutex_init(&player->fsink_lock);
4591 /* create update tag lock */
4592 g_mutex_init(&player->update_tag_lock);
4594 /* create gapless play mutex */
4595 g_mutex_init(&player->gapless_play_thread_mutex);
4597 /* create gapless play cond */
4598 g_cond_init(&player->gapless_play_thread_cond);
4600 /* create gapless play thread */
4601 player->gapless_play_thread =
4602 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4603 if (!player->gapless_play_thread) {
4604 LOGE("failed to create gapless play thread");
4605 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4606 g_mutex_clear(&player->gapless_play_thread_mutex);
4607 g_cond_clear(&player->gapless_play_thread_cond);
4611 player->bus_msg_q = g_queue_new();
4612 if (!player->bus_msg_q) {
4613 LOGE("failed to create queue for bus_msg");
4614 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4618 ret = _mmplayer_initialize_video_capture(player);
4619 if (ret != MM_ERROR_NONE) {
4620 LOGE("failed to initialize video capture");
4624 /* initialize resource manager */
4625 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4626 __resource_release_cb, player, &player->resource_manager)
4627 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4628 LOGE("failed to initialize resource manager");
4629 ret = MM_ERROR_PLAYER_INTERNAL;
4633 /* create video bo lock and cond */
4634 g_mutex_init(&player->video_bo_mutex);
4635 g_cond_init(&player->video_bo_cond);
4637 /* create subtitle info lock and cond */
4638 g_mutex_init(&player->subtitle_info_mutex);
4639 g_cond_init(&player->subtitle_info_cond);
4641 player->streaming_type = STREAMING_SERVICE_NONE;
4643 /* give default value of audio effect setting */
4644 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4645 player->sound.rg_enable = false;
4646 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4648 player->play_subtitle = FALSE;
4649 player->has_closed_caption = FALSE;
4650 player->pending_resume = FALSE;
4651 if (player->ini.dump_element_keyword[0][0] == '\0')
4652 player->ini.set_dump_element_flag = FALSE;
4654 player->ini.set_dump_element_flag = TRUE;
4656 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4657 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4658 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4660 /* Set video360 settings to their defaults for just-created player.
4663 player->is_360_feature_enabled = FALSE;
4664 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4665 LOGI("spherical feature info: %d", enabled);
4667 player->is_360_feature_enabled = TRUE;
4669 LOGE("failed to get spherical feature info");
4672 player->is_content_spherical = FALSE;
4673 player->is_video360_enabled = TRUE;
4674 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4675 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4676 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4677 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4678 player->video360_zoom = 1.0f;
4679 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4680 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4682 __mmplayer_initialize_video_roi(player);
4684 /* set player state to null */
4685 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4686 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4690 return MM_ERROR_NONE;
4694 g_mutex_clear(&player->fsink_lock);
4695 /* free update tag lock */
4696 g_mutex_clear(&player->update_tag_lock);
4697 g_queue_free(player->bus_msg_q);
4698 player->bus_msg_q = NULL;
4699 /* free gapless play thread */
4700 if (player->gapless_play_thread) {
4701 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4702 player->gapless_play_thread_exit = TRUE;
4703 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4704 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4706 g_thread_join(player->gapless_play_thread);
4707 player->gapless_play_thread = NULL;
4709 g_mutex_clear(&player->gapless_play_thread_mutex);
4710 g_cond_clear(&player->gapless_play_thread_cond);
4713 /* release attributes */
4714 _mmplayer_deconstruct_attribute(handle);
4722 __mmplayer_init_gstreamer(mmplayer_t *player)
4724 static gboolean initialized = FALSE;
4725 static const int max_argc = 50;
4727 gchar **argv = NULL;
4728 gchar **argv2 = NULL;
4734 LOGD("gstreamer already initialized.");
4739 argc = malloc(sizeof(int));
4740 argv = malloc(sizeof(gchar *) * max_argc);
4741 argv2 = malloc(sizeof(gchar *) * max_argc);
4743 if (!argc || !argv || !argv2)
4746 memset(argv, 0, sizeof(gchar *) * max_argc);
4747 memset(argv2, 0, sizeof(gchar *) * max_argc);
4751 argv[0] = g_strdup("mmplayer");
4754 for (i = 0; i < 5; i++) {
4755 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4756 if (strlen(player->ini.gst_param[i]) > 0) {
4757 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4762 /* we would not do fork for scanning plugins */
4763 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4766 /* check disable registry scan */
4767 if (player->ini.skip_rescan) {
4768 argv[*argc] = g_strdup("--gst-disable-registry-update");
4772 /* check disable segtrap */
4773 if (player->ini.disable_segtrap) {
4774 argv[*argc] = g_strdup("--gst-disable-segtrap");
4778 LOGD("initializing gstreamer with following parameter");
4779 LOGD("argc : %d", *argc);
4782 for (i = 0; i < arg_count; i++) {
4784 LOGD("argv[%d] : %s", i, argv2[i]);
4787 /* initializing gstreamer */
4788 if (!gst_init_check(argc, &argv, &err)) {
4789 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4796 for (i = 0; i < arg_count; i++) {
4798 LOGD("release - argv[%d] : %s", i, argv2[i]);
4800 MMPLAYER_FREEIF(argv2[i]);
4803 MMPLAYER_FREEIF(argv);
4804 MMPLAYER_FREEIF(argv2);
4805 MMPLAYER_FREEIF(argc);
4815 for (i = 0; i < arg_count; i++) {
4816 LOGD("free[%d] : %s", i, argv2[i]);
4817 MMPLAYER_FREEIF(argv2[i]);
4820 MMPLAYER_FREEIF(argv);
4821 MMPLAYER_FREEIF(argv2);
4822 MMPLAYER_FREEIF(argc);
4828 __mmplayer_check_async_state_transition(mmplayer_t *player)
4830 GstState element_state = GST_STATE_VOID_PENDING;
4831 GstState element_pending_state = GST_STATE_VOID_PENDING;
4832 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4833 GstElement *element = NULL;
4834 gboolean async = FALSE;
4836 /* check player handle */
4837 MMPLAYER_RETURN_IF_FAIL(player &&
4839 player->pipeline->mainbin &&
4840 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4843 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4845 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4846 LOGD("don't need to check the pipeline state");
4850 MMPLAYER_PRINT_STATE(player);
4852 /* wait for state transition */
4853 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4854 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4856 if (ret == GST_STATE_CHANGE_FAILURE) {
4857 LOGE(" [%s] state : %s pending : %s",
4858 GST_ELEMENT_NAME(element),
4859 gst_element_state_get_name(element_state),
4860 gst_element_state_get_name(element_pending_state));
4862 /* dump state of all element */
4863 _mmplayer_dump_pipeline_state(player);
4868 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4873 _mmplayer_destroy(MMHandleType handle)
4875 mmplayer_t *player = MM_PLAYER_CAST(handle);
4879 /* check player handle */
4880 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4882 /* destroy can called at anytime */
4883 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4885 /* check async state transition */
4886 __mmplayer_check_async_state_transition(player);
4888 /* release gapless play thread */
4889 if (player->gapless_play_thread) {
4890 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4891 player->gapless_play_thread_exit = TRUE;
4892 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4893 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4895 LOGD("waitting for gapless play thread exit");
4896 g_thread_join(player->gapless_play_thread);
4897 g_mutex_clear(&player->gapless_play_thread_mutex);
4898 g_cond_clear(&player->gapless_play_thread_cond);
4899 LOGD("gapless play thread released");
4902 _mmplayer_release_video_capture(player);
4904 /* de-initialize resource manager */
4905 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4906 player->resource_manager))
4907 LOGE("failed to deinitialize resource manager");
4909 /* release pipeline */
4910 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4911 LOGE("failed to destory pipeline");
4912 return MM_ERROR_PLAYER_INTERNAL;
4915 g_queue_free(player->bus_msg_q);
4917 /* release subtitle info lock and cond */
4918 g_mutex_clear(&player->subtitle_info_mutex);
4919 g_cond_clear(&player->subtitle_info_cond);
4921 __mmplayer_release_dump_list(player->dump_list);
4923 /* release miscellaneous information */
4924 __mmplayer_release_misc(player);
4926 /* release miscellaneous information.
4927 these info needs to be released after pipeline is destroyed. */
4928 __mmplayer_release_misc_post(player);
4930 /* release attributes */
4931 _mmplayer_deconstruct_attribute(handle);
4934 g_mutex_clear(&player->fsink_lock);
4937 g_mutex_clear(&player->update_tag_lock);
4939 /* release video bo lock and cond */
4940 g_mutex_clear(&player->video_bo_mutex);
4941 g_cond_clear(&player->video_bo_cond);
4945 return MM_ERROR_NONE;
4949 _mmplayer_realize(MMHandleType hplayer)
4951 mmplayer_t *player = (mmplayer_t *)hplayer;
4954 MMHandleType attrs = 0;
4955 int ret = MM_ERROR_NONE;
4959 /* check player handle */
4960 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4962 /* check current state */
4963 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4965 attrs = MMPLAYER_GET_ATTRS(player);
4967 LOGE("fail to get attributes.");
4968 return MM_ERROR_PLAYER_INTERNAL;
4970 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4971 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4973 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4974 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4976 if (ret != MM_ERROR_NONE) {
4977 LOGE("failed to parse profile");
4982 if (uri && (strstr(uri, "es_buff://"))) {
4983 if (strstr(uri, "es_buff://push_mode"))
4984 player->es_player_push_mode = TRUE;
4986 player->es_player_push_mode = FALSE;
4989 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
4990 LOGW("mms protocol is not supported format.");
4991 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
4994 if (MMPLAYER_IS_STREAMING(player))
4995 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
4997 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4999 player->smooth_streaming = FALSE;
5000 player->videodec_linked = 0;
5001 player->audiodec_linked = 0;
5002 player->textsink_linked = 0;
5003 player->is_external_subtitle_present = FALSE;
5004 player->is_external_subtitle_added_now = FALSE;
5005 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5006 player->video360_metadata.is_spherical = -1;
5007 player->is_openal_plugin_used = FALSE;
5008 player->demux_pad_index = 0;
5009 player->subtitle_language_list = NULL;
5010 player->is_subtitle_force_drop = FALSE;
5012 _mmplayer_track_initialize(player);
5013 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5015 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5016 gint prebuffer_ms = 0, rebuffer_ms = 0;
5018 player->streamer = _mm_player_streaming_create();
5019 _mm_player_streaming_initialize(player->streamer, TRUE);
5021 mm_attrs_multiple_get(player->attrs, NULL,
5022 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5023 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5025 if (prebuffer_ms > 0) {
5026 prebuffer_ms = MAX(prebuffer_ms, 1000);
5027 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5030 if (rebuffer_ms > 0) {
5031 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5032 rebuffer_ms = MAX(rebuffer_ms, 1000);
5033 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5036 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5037 player->streamer->buffering_req.rebuffer_time);
5040 /* realize pipeline */
5041 ret = __mmplayer_gst_realize(player);
5042 if (ret != MM_ERROR_NONE)
5043 LOGE("fail to realize the player.");
5045 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5053 _mmplayer_unrealize(MMHandleType hplayer)
5055 mmplayer_t *player = (mmplayer_t *)hplayer;
5056 int ret = MM_ERROR_NONE;
5060 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5062 MMPLAYER_CMD_UNLOCK(player);
5063 /* destroy the gst bus msg thread which is created during realize.
5064 this funct have to be called before getting cmd lock. */
5065 _mmplayer_bus_msg_thread_destroy(player);
5066 MMPLAYER_CMD_LOCK(player);
5068 /* check current state */
5069 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5071 /* check async state transition */
5072 __mmplayer_check_async_state_transition(player);
5074 /* unrealize pipeline */
5075 ret = __mmplayer_gst_unrealize(player);
5077 if (!player->interrupted_by_resource) {
5078 int rm_ret = MM_ERROR_NONE;
5079 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5081 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5082 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5083 if (rm_ret != MM_ERROR_NONE)
5084 LOGE("failed to release [%d] resources", res_idx);
5093 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5095 mmplayer_t *player = (mmplayer_t *)hplayer;
5097 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5099 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5103 _mmplayer_get_state(MMHandleType hplayer, int *state)
5105 mmplayer_t *player = (mmplayer_t *)hplayer;
5107 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5109 *state = MMPLAYER_CURRENT_STATE(player);
5111 return MM_ERROR_NONE;
5115 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5117 GstElement *vol_element = NULL;
5118 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5121 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5122 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5124 /* check pipeline handle */
5125 if (!player->pipeline || !player->pipeline->audiobin) {
5126 LOGD("'%s' will be applied when audiobin is created", prop_name);
5128 /* NOTE : stored value will be used in create_audiobin
5129 * returning MM_ERROR_NONE here makes application to able to
5130 * set audio volume or mute at anytime.
5132 return MM_ERROR_NONE;
5135 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5136 volume_elem_id = MMPLAYER_A_SINK;
5138 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5140 LOGE("failed to get vol element %d", volume_elem_id);
5141 return MM_ERROR_PLAYER_INTERNAL;
5144 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5146 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5147 LOGE("there is no '%s' property", prop_name);
5148 return MM_ERROR_PLAYER_INTERNAL;
5151 if (!strcmp(prop_name, "volume")) {
5152 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5153 } else if (!strcmp(prop_name, "mute")) {
5154 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5156 LOGE("invalid property %s", prop_name);
5157 return MM_ERROR_PLAYER_INTERNAL;
5160 return MM_ERROR_NONE;
5164 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5166 int ret = MM_ERROR_NONE;
5167 mmplayer_t *player = (mmplayer_t *)hplayer;
5170 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5172 LOGD("volume = %f", volume);
5174 /* invalid factor range or not */
5175 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5176 LOGE("Invalid volume value");
5177 return MM_ERROR_INVALID_ARGUMENT;
5180 player->sound.volume = volume;
5182 ret = __mmplayer_gst_set_volume_property(player, "volume");
5189 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5191 mmplayer_t *player = (mmplayer_t *)hplayer;
5195 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5196 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5198 *volume = player->sound.volume;
5200 LOGD("current vol = %f", *volume);
5203 return MM_ERROR_NONE;
5207 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5209 int ret = MM_ERROR_NONE;
5210 mmplayer_t *player = (mmplayer_t *)hplayer;
5213 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5215 LOGD("mute = %d", mute);
5217 player->sound.mute = mute;
5219 ret = __mmplayer_gst_set_volume_property(player, "mute");
5226 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5228 mmplayer_t *player = (mmplayer_t *)hplayer;
5232 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5233 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5235 *mute = player->sound.mute;
5237 LOGD("current mute = %d", *mute);
5241 return MM_ERROR_NONE;
5245 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5247 mmplayer_t *player = (mmplayer_t *)hplayer;
5251 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5253 player->audio_stream_changed_cb = callback;
5254 player->audio_stream_changed_cb_user_param = user_param;
5255 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5259 return MM_ERROR_NONE;
5263 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5265 mmplayer_t *player = (mmplayer_t *)hplayer;
5269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5271 player->audio_decoded_cb = callback;
5272 player->audio_decoded_cb_user_param = user_param;
5273 player->audio_extract_opt = opt;
5274 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5278 return MM_ERROR_NONE;
5282 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5284 mmplayer_t *player = (mmplayer_t *)hplayer;
5288 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5290 if (callback && !player->bufmgr)
5291 player->bufmgr = tbm_bufmgr_init(-1);
5293 player->set_mode.video_export = (callback) ? true : false;
5294 player->video_decoded_cb = callback;
5295 player->video_decoded_cb_user_param = user_param;
5297 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5301 return MM_ERROR_NONE;
5305 _mmplayer_start(MMHandleType hplayer)
5307 mmplayer_t *player = (mmplayer_t *)hplayer;
5308 gint ret = MM_ERROR_NONE;
5312 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5314 /* check current state */
5315 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5317 /* start pipeline */
5318 ret = _mmplayer_gst_start(player);
5319 if (ret != MM_ERROR_NONE)
5320 LOGE("failed to start player.");
5322 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5323 LOGD("force playing start even during buffering");
5324 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5332 /* NOTE: post "not supported codec message" to application
5333 * when one codec is not found during AUTOPLUGGING in MSL.
5334 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5335 * And, if any codec is not found, don't send message here.
5336 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5339 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5341 MMMessageParamType msg_param;
5342 memset(&msg_param, 0, sizeof(MMMessageParamType));
5343 gboolean post_msg_direct = FALSE;
5347 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5349 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5350 player->not_supported_codec, player->can_support_codec);
5352 if (player->not_found_demuxer) {
5353 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5354 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5356 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5357 MMPLAYER_FREEIF(msg_param.data);
5359 return MM_ERROR_NONE;
5362 if (player->not_supported_codec) {
5363 if (player->can_support_codec) {
5364 // There is one codec to play
5365 post_msg_direct = TRUE;
5367 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5368 post_msg_direct = TRUE;
5371 if (post_msg_direct) {
5372 MMMessageParamType msg_param;
5373 memset(&msg_param, 0, sizeof(MMMessageParamType));
5375 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5376 LOGW("not found AUDIO codec, posting error code to application.");
5378 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5379 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5380 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5381 LOGW("not found VIDEO codec, posting error code to application.");
5383 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5384 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5387 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5389 MMPLAYER_FREEIF(msg_param.data);
5391 return MM_ERROR_NONE;
5393 // no any supported codec case
5394 LOGW("not found any codec, posting error code to application.");
5396 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5397 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5398 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5400 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5401 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5404 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5406 MMPLAYER_FREEIF(msg_param.data);
5412 return MM_ERROR_NONE;
5416 __mmplayer_check_pipeline(mmplayer_t *player)
5418 GstState element_state = GST_STATE_VOID_PENDING;
5419 GstState element_pending_state = GST_STATE_VOID_PENDING;
5421 int ret = MM_ERROR_NONE;
5423 if (!player->gapless.reconfigure)
5426 LOGW("pipeline is under construction.");
5428 MMPLAYER_PLAYBACK_LOCK(player);
5429 MMPLAYER_PLAYBACK_UNLOCK(player);
5431 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5433 /* wait for state transition */
5434 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5435 if (ret == GST_STATE_CHANGE_FAILURE)
5436 LOGE("failed to change pipeline state within %d sec", timeout);
5439 /* NOTE : it should be able to call 'stop' anytime*/
5441 _mmplayer_stop(MMHandleType hplayer)
5443 mmplayer_t *player = (mmplayer_t *)hplayer;
5444 int ret = MM_ERROR_NONE;
5448 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5450 /* check current state */
5451 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5453 /* check pipline building state */
5454 __mmplayer_check_pipeline(player);
5455 __mmplayer_reset_gapless_state(player);
5457 /* NOTE : application should not wait for EOS after calling STOP */
5458 _mmplayer_cancel_eos_timer(player);
5461 player->seek_state = MMPLAYER_SEEK_NONE;
5464 ret = _mmplayer_gst_stop(player);
5466 if (ret != MM_ERROR_NONE)
5467 LOGE("failed to stop player.");
5475 _mmplayer_pause(MMHandleType hplayer)
5477 mmplayer_t *player = (mmplayer_t *)hplayer;
5478 gint64 pos_nsec = 0;
5479 gboolean async = FALSE;
5480 gint ret = MM_ERROR_NONE;
5484 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5486 /* check current state */
5487 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5489 /* check pipline building state */
5490 __mmplayer_check_pipeline(player);
5492 switch (MMPLAYER_CURRENT_STATE(player)) {
5493 case MM_PLAYER_STATE_READY:
5495 /* check prepare async or not.
5496 * In the case of streaming playback, it's recommned to avoid blocking wait.
5498 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5499 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5501 /* Changing back sync of rtspsrc to async */
5502 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5503 LOGD("async prepare working mode for rtsp");
5509 case MM_PLAYER_STATE_PLAYING:
5511 /* NOTE : store current point to overcome some bad operation
5512 *(returning zero when getting current position in paused state) of some
5515 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5516 LOGW("getting current position failed in paused");
5518 player->last_position = pos_nsec;
5520 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5521 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5522 This causes problem is position calculation during normal pause resume scenarios also.
5523 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5524 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5525 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5526 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5532 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5533 LOGD("doing async pause in case of ms buff src");
5537 /* pause pipeline */
5538 ret = _mmplayer_gst_pause(player, async);
5540 if (ret != MM_ERROR_NONE)
5541 LOGE("failed to pause player. ret : 0x%x", ret);
5543 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5544 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5545 LOGE("failed to update display_rotation");
5553 /* in case of streaming, pause could take long time.*/
5555 _mmplayer_abort_pause(MMHandleType hplayer)
5557 mmplayer_t *player = (mmplayer_t *)hplayer;
5558 int ret = MM_ERROR_NONE;
5562 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5564 player->pipeline->mainbin,
5565 MM_ERROR_PLAYER_NOT_INITIALIZED);
5567 LOGD("set the pipeline state to READY");
5569 /* set state to READY */
5570 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5571 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5572 if (ret != MM_ERROR_NONE) {
5573 LOGE("fail to change state to READY");
5574 return MM_ERROR_PLAYER_INTERNAL;
5577 LOGD("succeeded in changing state to READY");
5582 _mmplayer_resume(MMHandleType hplayer)
5584 mmplayer_t *player = (mmplayer_t *)hplayer;
5585 int ret = MM_ERROR_NONE;
5586 gboolean async = FALSE;
5590 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5592 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5593 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5594 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5598 /* Changing back sync mode rtspsrc to async */
5599 LOGD("async resume for rtsp case");
5603 /* check current state */
5604 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5606 ret = _mmplayer_gst_resume(player, async);
5607 if (ret != MM_ERROR_NONE)
5608 LOGE("failed to resume player.");
5610 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5611 LOGD("force resume even during buffering");
5612 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5621 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5623 mmplayer_t *player = (mmplayer_t *)hplayer;
5624 gint64 pos_nsec = 0;
5625 int ret = MM_ERROR_NONE;
5627 signed long long start = 0, stop = 0;
5628 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5631 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5632 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5634 /* The sound of video is not supported under 0.0 and over 2.0. */
5635 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5636 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5639 _mmplayer_set_mute(hplayer, mute);
5641 if (player->playback_rate == rate)
5642 return MM_ERROR_NONE;
5644 /* If the position is reached at start potion during fast backward, EOS is posted.
5645 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5647 player->playback_rate = rate;
5649 current_state = MMPLAYER_CURRENT_STATE(player);
5651 if (current_state != MM_PLAYER_STATE_PAUSED)
5652 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5654 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5656 if ((current_state == MM_PLAYER_STATE_PAUSED)
5657 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5658 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5659 pos_nsec = player->last_position;
5664 stop = GST_CLOCK_TIME_NONE;
5666 start = GST_CLOCK_TIME_NONE;
5670 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5671 player->playback_rate,
5673 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5674 GST_SEEK_TYPE_SET, start,
5675 GST_SEEK_TYPE_SET, stop)) {
5676 LOGE("failed to set speed playback");
5677 return MM_ERROR_PLAYER_SEEK;
5680 LOGD("succeeded to set speed playback as %0.1f", rate);
5684 return MM_ERROR_NONE;;
5688 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5690 mmplayer_t *player = (mmplayer_t *)hplayer;
5691 int ret = MM_ERROR_NONE;
5695 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5697 /* check pipline building state */
5698 __mmplayer_check_pipeline(player);
5700 ret = _mmplayer_gst_set_position(player, position, FALSE);
5708 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5710 mmplayer_t *player = (mmplayer_t *)hplayer;
5711 int ret = MM_ERROR_NONE;
5713 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5714 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5716 if (g_strrstr(player->type, "video/mpegts"))
5717 __mmplayer_update_duration_value(player);
5719 *duration = player->duration;
5724 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
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);
5731 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5737 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5739 mmplayer_t *player = (mmplayer_t *)hplayer;
5740 int ret = MM_ERROR_NONE;
5744 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5746 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5754 __mmplayer_is_midi_type(gchar *str_caps)
5756 if ((g_strrstr(str_caps, "audio/midi")) ||
5757 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5758 (g_strrstr(str_caps, "application/x-smaf")) ||
5759 (g_strrstr(str_caps, "audio/x-imelody")) ||
5760 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5761 (g_strrstr(str_caps, "audio/xmf")) ||
5762 (g_strrstr(str_caps, "audio/mxmf"))) {
5771 __mmplayer_is_only_mp3_type(gchar *str_caps)
5773 if (g_strrstr(str_caps, "application/x-id3") ||
5774 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5780 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5782 GstStructure *caps_structure = NULL;
5783 gint samplerate = 0;
5787 MMPLAYER_RETURN_IF_FAIL(player && caps);
5789 caps_structure = gst_caps_get_structure(caps, 0);
5791 /* set stream information */
5792 gst_structure_get_int(caps_structure, "rate", &samplerate);
5793 gst_structure_get_int(caps_structure, "channels", &channels);
5795 mm_player_set_attribute((MMHandleType)player, NULL,
5796 "content_audio_samplerate", samplerate,
5797 "content_audio_channels", channels, NULL);
5799 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5803 __mmplayer_update_content_type_info(mmplayer_t *player)
5806 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5808 if (__mmplayer_is_midi_type(player->type)) {
5809 player->bypass_audio_effect = TRUE;
5813 if (!player->streamer) {
5814 LOGD("no need to check streaming type");
5818 if (g_strrstr(player->type, "application/x-hls")) {
5819 /* If it can't know exact type when it parses uri because of redirection case,
5820 * it will be fixed by typefinder or when doing autoplugging.
5822 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5823 player->streamer->is_adaptive_streaming = TRUE;
5824 } else if (g_strrstr(player->type, "application/dash+xml")) {
5825 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5826 player->streamer->is_adaptive_streaming = TRUE;
5829 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5830 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5831 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5833 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5834 if (player->streamer->is_adaptive_streaming)
5835 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5837 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5841 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5846 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5847 GstCaps *caps, gpointer data)
5849 mmplayer_t *player = (mmplayer_t *)data;
5854 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5856 /* store type string */
5857 MMPLAYER_FREEIF(player->type);
5858 player->type = gst_caps_to_string(caps);
5860 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5861 player, player->type, probability, gst_caps_get_size(caps));
5863 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5864 (g_strrstr(player->type, "audio/x-raw-int"))) {
5865 LOGE("not support media format");
5867 if (player->msg_posted == FALSE) {
5868 MMMessageParamType msg_param;
5869 memset(&msg_param, 0, sizeof(MMMessageParamType));
5871 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5872 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5874 /* don't post more if one was sent already */
5875 player->msg_posted = TRUE;
5880 __mmplayer_update_content_type_info(player);
5882 pad = gst_element_get_static_pad(tf, "src");
5884 LOGE("fail to get typefind src pad.");
5888 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5889 gboolean async = FALSE;
5890 LOGE("failed to autoplug %s", player->type);
5892 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5894 if (async && player->msg_posted == FALSE)
5895 __mmplayer_handle_missed_plugin(player);
5899 gst_object_unref(GST_OBJECT(pad));
5907 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5909 GstElement *decodebin = NULL;
5913 /* create decodebin */
5914 decodebin = gst_element_factory_make("decodebin", NULL);
5917 LOGE("fail to create decodebin");
5921 /* raw pad handling signal */
5922 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5923 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5925 /* no-more-pad pad handling signal */
5926 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5927 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5929 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5930 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5932 /* This signal is emitted when a pad for which there is no further possible
5933 decoding is added to the decodebin.*/
5934 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5935 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5937 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5938 before looking for any elements that can handle that stream.*/
5939 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5940 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5942 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5943 before looking for any elements that can handle that stream.*/
5944 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5945 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5947 /* This signal is emitted once decodebin has finished decoding all the data.*/
5948 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5949 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5951 /* This signal is emitted when a element is added to the bin.*/
5952 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5953 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5960 __mmplayer_gst_make_queue2(mmplayer_t *player)
5962 GstElement *queue2 = NULL;
5963 gint64 dur_bytes = 0L;
5964 mmplayer_gst_element_t *mainbin = NULL;
5965 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5968 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5970 mainbin = player->pipeline->mainbin;
5972 queue2 = gst_element_factory_make("queue2", "queue2");
5974 LOGE("failed to create buffering queue element");
5978 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5979 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5981 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5983 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5984 * skip the pull mode(file or ring buffering) setting. */
5985 if (dur_bytes > 0) {
5986 if (!g_strrstr(player->type, "video/mpegts")) {
5987 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5988 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
5994 _mm_player_streaming_set_queue2(player->streamer,
5998 (guint64)dur_bytes); /* no meaning at the moment */
6004 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6006 mmplayer_gst_element_t *mainbin = NULL;
6007 GstElement *decodebin = NULL;
6008 GstElement *queue2 = NULL;
6009 GstPad *sinkpad = NULL;
6010 GstPad *qsrcpad = NULL;
6013 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6015 mainbin = player->pipeline->mainbin;
6017 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6019 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6020 LOGW("need to check: muxed buffer is not null");
6023 queue2 = __mmplayer_gst_make_queue2(player);
6025 LOGE("failed to make queue2");
6029 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6030 LOGE("failed to add buffering queue");
6034 sinkpad = gst_element_get_static_pad(queue2, "sink");
6035 qsrcpad = gst_element_get_static_pad(queue2, "src");
6037 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6038 LOGE("failed to link [%s:%s]-[%s:%s]",
6039 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6043 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6044 LOGE("failed to sync queue2 state with parent");
6048 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6049 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6053 gst_object_unref(GST_OBJECT(sinkpad));
6057 /* create decodebin */
6058 decodebin = _mmplayer_gst_make_decodebin(player);
6060 LOGE("failed to make decodebin");
6064 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6065 LOGE("failed to add decodebin");
6069 /* to force caps on the decodebin element and avoid reparsing stuff by
6070 * typefind. It also avoids a deadlock in the way typefind activates pads in
6071 * the state change */
6072 g_object_set(decodebin, "sink-caps", caps, NULL);
6074 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6076 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6077 LOGE("failed to link [%s:%s]-[%s:%s]",
6078 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6082 gst_object_unref(GST_OBJECT(sinkpad));
6084 gst_object_unref(GST_OBJECT(qsrcpad));
6087 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6088 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6090 /* set decodebin property about buffer in streaming playback. *
6091 * in case of HLS/DASH, it does not need to have big buffer *
6092 * because it is kind of adaptive streaming. */
6093 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6094 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6095 gint high_percent = 0;
6097 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6098 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6100 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6102 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6104 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6105 "high-percent", high_percent,
6106 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6107 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6108 "max-size-buffers", 0, NULL); // disable or automatic
6111 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6112 LOGE("failed to sync decodebin state with parent");
6123 gst_object_unref(GST_OBJECT(sinkpad));
6126 gst_object_unref(GST_OBJECT(qsrcpad));
6129 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6130 * You need to explicitly set elements to the NULL state before
6131 * dropping the final reference, to allow them to clean up.
6133 gst_element_set_state(queue2, GST_STATE_NULL);
6135 /* And, it still has a parent "player".
6136 * You need to let the parent manage the object instead of unreffing the object directly.
6138 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6139 gst_object_unref(queue2);
6144 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6145 * You need to explicitly set elements to the NULL state before
6146 * dropping the final reference, to allow them to clean up.
6148 gst_element_set_state(decodebin, GST_STATE_NULL);
6150 /* And, it still has a parent "player".
6151 * 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), decodebin);
6155 gst_object_unref(decodebin);
6163 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6167 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6168 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6170 LOGD("class : %s, mime : %s", factory_class, mime);
6172 /* add missing plugin */
6173 /* NOTE : msl should check missing plugin for image mime type.
6174 * Some motion jpeg clips can have playable audio track.
6175 * So, msl have to play audio after displaying popup written video format not supported.
6177 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6178 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6179 LOGD("not found demuxer");
6180 player->not_found_demuxer = TRUE;
6181 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6187 if (!g_strrstr(factory_class, "Demuxer")) {
6188 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6189 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6190 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6192 /* check that clip have multi tracks or not */
6193 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6194 LOGD("video plugin is already linked");
6196 LOGW("add VIDEO to missing plugin");
6197 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6198 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6200 } else if (g_str_has_prefix(mime, "audio")) {
6201 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6202 LOGD("audio plugin is already linked");
6204 LOGW("add AUDIO to missing plugin");
6205 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6206 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6214 return MM_ERROR_NONE;
6218 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6220 mmplayer_t *player = (mmplayer_t *)data;
6224 MMPLAYER_RETURN_IF_FAIL(player);
6226 /* remove fakesink. */
6227 if (!_mmplayer_gst_remove_fakesink(player,
6228 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6229 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6230 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6231 * source element are not same. To overcome this situation, this function will called
6232 * several places and several times. Therefore, this is not an error case.
6237 LOGD("[handle: %p] pipeline has completely constructed", player);
6239 if ((player->ini.async_start) &&
6240 (player->msg_posted == FALSE) &&
6241 (player->cmd >= MMPLAYER_COMMAND_START))
6242 __mmplayer_handle_missed_plugin(player);
6244 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6248 __mmplayer_check_profile(void)
6251 static int profile_tv = -1;
6253 if (__builtin_expect(profile_tv != -1, 1))
6256 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6257 switch (*profileName) {
6272 __mmplayer_get_next_uri(mmplayer_t *player)
6274 mmplayer_parse_profile_t profile;
6276 guint num_of_list = 0;
6279 num_of_list = g_list_length(player->uri_info.uri_list);
6280 uri_idx = player->uri_info.uri_idx;
6282 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6283 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6284 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6286 LOGW("next uri does not exist");
6290 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6291 LOGE("failed to parse profile");
6295 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6296 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6297 LOGW("uri type is not supported(%d)", profile.uri_type);
6301 LOGD("success to find next uri %d", uri_idx);
6305 if (!uri || uri_idx == num_of_list) {
6306 LOGE("failed to find next uri");
6310 player->uri_info.uri_idx = uri_idx;
6311 if (mm_player_set_attribute((MMHandleType)player, NULL,
6312 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6313 LOGE("failed to set attribute");
6317 SECURE_LOGD("next playback uri: %s", uri);
6322 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6324 #define REPEAT_COUNT_INFINITE -1
6325 #define REPEAT_COUNT_MIN 2
6326 #define ORIGINAL_URI_ONLY 1
6328 MMHandleType attrs = 0;
6332 guint num_of_uri = 0;
6333 int profile_tv = -1;
6337 LOGD("checking for gapless play option");
6339 if (player->build_audio_offload) {
6340 LOGE("offload path is not supportable.");
6344 if (player->pipeline->textbin) {
6345 LOGE("subtitle path is enabled. gapless play is not supported.");
6349 attrs = MMPLAYER_GET_ATTRS(player);
6351 LOGE("fail to get attributes.");
6355 mm_attrs_multiple_get(player->attrs, NULL,
6356 "content_video_found", &video,
6357 "profile_play_count", &count,
6358 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6360 /* gapless playback is not supported in case of video at TV profile. */
6361 profile_tv = __mmplayer_check_profile();
6362 if (profile_tv && video) {
6363 LOGW("not support video gapless playback");
6367 /* check repeat count in case of audio */
6369 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6370 LOGW("gapless is disabled");
6374 num_of_uri = g_list_length(player->uri_info.uri_list);
6376 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6378 if (num_of_uri == ORIGINAL_URI_ONLY) {
6379 /* audio looping path */
6380 if (count >= REPEAT_COUNT_MIN) {
6381 /* decrease play count */
6382 /* we succeeded to rewind. update play count and then wait for next EOS */
6384 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6385 } else if (count != REPEAT_COUNT_INFINITE) {
6386 LOGD("there is no next uri and no repeat");
6389 LOGD("looping cnt %d", count);
6391 /* gapless playback path */
6392 if (!__mmplayer_get_next_uri(player)) {
6393 LOGE("failed to get next uri");
6400 LOGE("unable to play gapless path. EOS will be posted soon");
6405 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6407 mmplayer_selector_t *selector = &player->selector[type];
6408 mmplayer_gst_element_t *sinkbin = NULL;
6409 main_element_id_e selectorId = MMPLAYER_M_NUM;
6410 main_element_id_e sinkId = MMPLAYER_M_NUM;
6411 GstPad *srcpad = NULL;
6412 GstPad *sinkpad = NULL;
6413 gboolean send_notice = FALSE;
6416 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6418 LOGD("type %d", type);
6421 case MM_PLAYER_TRACK_TYPE_AUDIO:
6422 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6423 sinkId = MMPLAYER_A_BIN;
6424 sinkbin = player->pipeline->audiobin;
6426 case MM_PLAYER_TRACK_TYPE_VIDEO:
6427 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6428 sinkId = MMPLAYER_V_BIN;
6429 sinkbin = player->pipeline->videobin;
6432 case MM_PLAYER_TRACK_TYPE_TEXT:
6433 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6434 sinkId = MMPLAYER_T_BIN;
6435 sinkbin = player->pipeline->textbin;
6438 LOGE("requested type is not supportable");
6443 if (player->pipeline->mainbin[selectorId].gst) {
6446 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6448 if (selector->event_probe_id != 0)
6449 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6450 selector->event_probe_id = 0;
6452 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6453 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6455 if (srcpad && sinkpad) {
6456 /* after getting drained signal there is no data flows, so no need to do pad_block */
6457 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6458 gst_pad_unlink(srcpad, sinkpad);
6460 /* send custom event to sink pad to handle it at video sink */
6462 LOGD("send custom event to sinkpad");
6463 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6464 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6465 gst_pad_send_event(sinkpad, event);
6469 gst_object_unref(sinkpad);
6472 gst_object_unref(srcpad);
6475 LOGD("selector release");
6477 /* release and unref requests pad from the selector */
6478 for (n = 0; n < selector->channels->len; n++) {
6479 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6480 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6482 g_ptr_array_set_size(selector->channels, 0);
6484 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6485 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6487 player->pipeline->mainbin[selectorId].gst = NULL;
6495 __mmplayer_deactivate_old_path(mmplayer_t *player)
6498 MMPLAYER_RETURN_IF_FAIL(player);
6500 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6501 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6502 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6503 LOGE("deactivate selector error");
6507 _mmplayer_track_destroy(player);
6508 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6510 if (player->streamer) {
6511 _mm_player_streaming_initialize(player->streamer, FALSE);
6512 _mm_player_streaming_destroy(player->streamer);
6513 player->streamer = NULL;
6516 MMPLAYER_PLAYBACK_LOCK(player);
6517 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6524 if (!player->msg_posted) {
6525 MMMessageParamType msg = {0,};
6528 msg.code = MM_ERROR_PLAYER_INTERNAL;
6529 LOGE("gapless_uri_play> deactivate error");
6531 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6532 player->msg_posted = TRUE;
6538 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6540 int result = MM_ERROR_NONE;
6541 mmplayer_t *player = (mmplayer_t *)hplayer;
6544 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6545 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6547 if (mm_player_set_attribute(hplayer, NULL,
6548 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6549 LOGE("failed to set attribute");
6550 result = MM_ERROR_PLAYER_INTERNAL;
6552 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6553 LOGE("failed to add the original uri in the uri list.");
6561 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6563 mmplayer_t *player = (mmplayer_t *)hplayer;
6564 guint num_of_list = 0;
6568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6569 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6571 if (player->pipeline && player->pipeline->textbin) {
6572 LOGE("subtitle path is enabled.");
6573 return MM_ERROR_PLAYER_INVALID_STATE;
6576 num_of_list = g_list_length(player->uri_info.uri_list);
6578 if (is_first_path) {
6579 if (num_of_list == 0) {
6580 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6581 SECURE_LOGD("add original path : %s", uri);
6583 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6584 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6586 SECURE_LOGD("change original path : %s", uri);
6589 MMHandleType attrs = 0;
6590 attrs = MMPLAYER_GET_ATTRS(player);
6592 if (num_of_list == 0) {
6593 char *original_uri = NULL;
6596 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6598 if (!original_uri) {
6599 LOGE("there is no original uri.");
6600 return MM_ERROR_PLAYER_INVALID_STATE;
6603 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6604 player->uri_info.uri_idx = 0;
6606 SECURE_LOGD("add original path at first : %s", original_uri);
6610 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6611 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6615 return MM_ERROR_NONE;
6619 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6621 mmplayer_t *player = (mmplayer_t *)hplayer;
6622 char *next_uri = NULL;
6623 guint num_of_list = 0;
6626 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6628 num_of_list = g_list_length(player->uri_info.uri_list);
6630 if (num_of_list > 0) {
6631 gint uri_idx = player->uri_info.uri_idx;
6633 if (uri_idx < num_of_list-1)
6638 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6639 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6641 *uri = g_strdup(next_uri);
6645 return MM_ERROR_NONE;
6649 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6650 GstCaps *caps, gpointer data)
6652 mmplayer_t *player = (mmplayer_t *)data;
6653 const gchar *klass = NULL;
6654 const gchar *mime = NULL;
6655 gchar *caps_str = NULL;
6657 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6658 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6659 caps_str = gst_caps_to_string(caps);
6661 LOGW("unknown type of caps : %s from %s",
6662 caps_str, GST_ELEMENT_NAME(elem));
6664 MMPLAYER_FREEIF(caps_str);
6666 /* There is no available codec. */
6667 __mmplayer_check_not_supported_codec(player, klass, mime);
6671 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6672 GstCaps *caps, gpointer data)
6674 mmplayer_t *player = (mmplayer_t *)data;
6675 const char *mime = NULL;
6676 gboolean ret = TRUE;
6678 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6679 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6681 if (g_str_has_prefix(mime, "audio")) {
6682 GstStructure *caps_structure = NULL;
6683 gint samplerate = 0;
6685 gchar *caps_str = NULL;
6687 caps_structure = gst_caps_get_structure(caps, 0);
6688 gst_structure_get_int(caps_structure, "rate", &samplerate);
6689 gst_structure_get_int(caps_structure, "channels", &channels);
6691 if ((channels > 0 && samplerate == 0)) {
6692 LOGD("exclude audio...");
6696 caps_str = gst_caps_to_string(caps);
6697 /* set it directly because not sent by TAG */
6698 if (g_strrstr(caps_str, "mobile-xmf"))
6699 mm_player_set_attribute((MMHandleType)player, NULL,
6700 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6702 MMPLAYER_FREEIF(caps_str);
6703 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6704 MMMessageParamType msg_param;
6705 memset(&msg_param, 0, sizeof(MMMessageParamType));
6706 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6707 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6708 LOGD("video file is not supported on this device");
6710 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6711 LOGD("already video linked");
6714 LOGD("found new stream");
6721 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6723 gboolean ret = FALSE;
6724 GDBusConnection *conn = NULL;
6726 GVariant *result = NULL;
6727 const gchar *dbus_device_type = NULL;
6728 const gchar *dbus_ret = NULL;
6731 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6733 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6738 result = g_dbus_connection_call_sync(conn,
6739 "org.pulseaudio.Server",
6740 "/org/pulseaudio/StreamManager",
6741 "org.pulseaudio.StreamManager",
6742 "GetCurrentMediaRoutingPath",
6743 g_variant_new("(s)", "out"),
6744 G_VARIANT_TYPE("(ss)"),
6745 G_DBUS_CALL_FLAGS_NONE,
6749 if (!result || err) {
6750 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6755 /* device type is listed in stream-map.json at mmfw-sysconf */
6756 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6758 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6759 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6762 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6763 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6764 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6765 LOGD("audio offload is supportable");
6771 LOGD("audio offload is not supportable");
6774 g_variant_unref(result);
6776 g_object_unref(conn);
6781 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6783 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6784 gint64 position = 0;
6786 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6787 player->pipeline && player->pipeline->mainbin);
6789 MMPLAYER_CMD_LOCK(player);
6790 current_state = MMPLAYER_CURRENT_STATE(player);
6792 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6793 LOGW("getting current position failed in paused");
6795 _mmplayer_unrealize((MMHandleType)player);
6796 _mmplayer_realize((MMHandleType)player);
6798 _mmplayer_set_position((MMHandleType)player, position);
6800 /* async not to be blocked in streaming case */
6801 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6803 _mmplayer_pause((MMHandleType)player);
6805 if (current_state == MM_PLAYER_STATE_PLAYING)
6806 _mmplayer_start((MMHandleType)player);
6807 MMPLAYER_CMD_UNLOCK(player);
6809 LOGD("rebuilding audio pipeline is completed.");
6812 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6814 mmplayer_t *player = (mmplayer_t *)user_data;
6815 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6816 gboolean is_supportable = FALSE;
6818 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6819 LOGW("failed to get device type");
6821 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6823 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6824 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6825 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6826 LOGD("ignore this dev connected info");
6830 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6831 if (player->build_audio_offload == is_supportable) {
6832 LOGD("keep current pipeline without re-building");
6836 /* rebuild pipeline */
6837 LOGD("re-build pipeline - offload: %d", is_supportable);
6838 player->build_audio_offload = FALSE;
6839 __mmplayer_rebuild_audio_pipeline(player);
6845 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6847 unsigned int id = 0;
6849 if (player->audio_device_cb_id != 0) {
6850 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6854 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6855 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6856 LOGD("added device connected cb (%u)", id);
6857 player->audio_device_cb_id = id;
6859 LOGW("failed to add device connected cb");
6866 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
6868 mmplayer_t *player = (mmplayer_t *)hplayer;
6871 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6872 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
6874 *activated = player->build_audio_offload;
6876 LOGD("offload activated : %d", (int)*activated);
6879 return MM_ERROR_NONE;
6883 __mmplayer_is_offload_supported_type(mmplayer_t *player)
6886 this function need to be updated according to the supported media format
6887 @see player->ini.audio_offload_media_format */
6889 if (__mmplayer_is_only_mp3_type(player->type)) {
6890 LOGD("offload supportable media format type");
6898 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6900 gboolean ret = FALSE;
6901 GstElementFactory *factory = NULL;
6904 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6906 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6907 if (!__mmplayer_is_offload_supported_type(player))
6910 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6911 LOGD("there is no audio offload sink");
6915 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6916 LOGW("there is no audio device type to support offload");
6920 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6922 LOGW("there is no installed audio offload sink element");
6925 gst_object_unref(factory);
6927 if (__mmplayer_acquire_hw_resource(player,
6928 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6929 LOGE("failed to acquire audio offload decoder resource");
6933 if (!__mmplayer_add_audio_device_connected_cb(player))
6936 if (!__mmplayer_is_audio_offload_device_type(player))
6939 LOGD("audio offload can be built");
6944 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6950 static GstAutoplugSelectResult
6951 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6953 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6955 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6956 int audio_offload = 0;
6958 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6959 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6961 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6962 LOGD("expose audio path to build offload output path");
6963 player->build_audio_offload = TRUE;
6964 /* update codec info */
6965 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6966 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6967 player->audiodec_linked = 1;
6969 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6973 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6975 LOGD("audio codec type: %d", codec_type);
6976 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6977 /* sw codec will be skipped */
6978 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6979 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6980 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6981 ret = GST_AUTOPLUG_SELECT_SKIP;
6985 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6986 /* hw codec will be skipped */
6987 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6988 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6989 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6990 ret = GST_AUTOPLUG_SELECT_SKIP;
6995 /* set stream information */
6996 if (!player->audiodec_linked)
6997 __mmplayer_set_audio_attrs(player, caps);
6999 /* update codec info */
7000 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7001 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7002 player->audiodec_linked = 1;
7004 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7006 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
7008 LOGD("video codec type: %d", codec_type);
7009 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7010 /* sw codec is skipped */
7011 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
7012 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
7013 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
7014 ret = GST_AUTOPLUG_SELECT_SKIP;
7018 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7019 /* hw codec is skipped */
7020 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7021 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7022 ret = GST_AUTOPLUG_SELECT_SKIP;
7027 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7028 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7030 /* mark video decoder for acquire */
7031 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7032 LOGW("video decoder resource is already acquired, skip it.");
7033 ret = GST_AUTOPLUG_SELECT_SKIP;
7037 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7038 LOGE("failed to acquire video decoder resource");
7039 ret = GST_AUTOPLUG_SELECT_SKIP;
7042 player->interrupted_by_resource = FALSE;
7045 /* update codec info */
7046 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7047 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7048 player->videodec_linked = 1;
7056 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7057 GstCaps *caps, GstElementFactory *factory, gpointer data)
7059 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7060 mmplayer_t *player = (mmplayer_t *)data;
7062 gchar *factory_name = NULL;
7063 gchar *caps_str = NULL;
7064 const gchar *klass = NULL;
7067 factory_name = GST_OBJECT_NAME(factory);
7068 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7069 caps_str = gst_caps_to_string(caps);
7071 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7073 /* store type string */
7074 if (player->type == NULL) {
7075 player->type = gst_caps_to_string(caps);
7076 __mmplayer_update_content_type_info(player);
7079 /* filtering exclude keyword */
7080 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7081 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7082 LOGW("skipping [%s] by exculde keyword [%s]",
7083 factory_name, player->ini.exclude_element_keyword[idx]);
7085 result = GST_AUTOPLUG_SELECT_SKIP;
7090 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7091 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7092 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7093 factory_name, player->ini.unsupported_codec_keyword[idx]);
7094 result = GST_AUTOPLUG_SELECT_SKIP;
7099 /* exclude webm format */
7100 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7101 * because webm format is not supportable.
7102 * If webm is disabled in "autoplug-continue", there is no state change
7103 * failure or error because the decodebin will expose the pad directly.
7104 * It make MSL invoke _prepare_async_callback.
7105 * So, we need to disable webm format in "autoplug-select" */
7106 if (caps_str && strstr(caps_str, "webm")) {
7107 LOGW("webm is not supported");
7108 result = GST_AUTOPLUG_SELECT_SKIP;
7112 /* check factory class for filtering */
7113 /* NOTE : msl don't need to use image plugins.
7114 * So, those plugins should be skipped for error handling.
7116 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7117 LOGD("skipping [%s] by not required", factory_name);
7118 result = GST_AUTOPLUG_SELECT_SKIP;
7122 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7123 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7124 // TO CHECK : subtitle if needed, add subparse exception.
7125 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7126 result = GST_AUTOPLUG_SELECT_SKIP;
7130 if (g_strrstr(factory_name, "mpegpsdemux")) {
7131 LOGD("skipping PS container - not support");
7132 result = GST_AUTOPLUG_SELECT_SKIP;
7136 if (g_strrstr(factory_name, "mssdemux"))
7137 player->smooth_streaming = TRUE;
7139 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7140 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7143 GstStructure *str = NULL;
7144 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7146 /* don't make video because of not required */
7147 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7148 (!player->set_mode.video_export)) {
7149 LOGD("no need video decoding, expose pad");
7150 result = GST_AUTOPLUG_SELECT_EXPOSE;
7154 /* get w/h for omx state-tune */
7155 /* FIXME: deprecated? */
7156 str = gst_caps_get_structure(caps, 0);
7157 gst_structure_get_int(str, "width", &width);
7160 if (player->v_stream_caps) {
7161 gst_caps_unref(player->v_stream_caps);
7162 player->v_stream_caps = NULL;
7165 player->v_stream_caps = gst_caps_copy(caps);
7166 LOGD("take caps for video state tune");
7167 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7171 if (g_strrstr(klass, "Codec/Decoder")) {
7172 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7173 if (result != GST_AUTOPLUG_SELECT_TRY) {
7174 LOGW("skip add decoder");
7180 MMPLAYER_FREEIF(caps_str);
7186 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7189 //mmplayer_t *player = (mmplayer_t *)data;
7190 GstCaps *caps = NULL;
7192 LOGD("[Decodebin2] pad-removed signal");
7194 caps = gst_pad_query_caps(new_pad, NULL);
7196 LOGW("query caps is NULL");
7200 gchar *caps_str = NULL;
7201 caps_str = gst_caps_to_string(caps);
7203 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7205 MMPLAYER_FREEIF(caps_str);
7206 gst_caps_unref(caps);
7210 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7212 mmplayer_t *player = (mmplayer_t *)data;
7213 GstIterator *iter = NULL;
7214 GValue item = { 0, };
7216 gboolean done = FALSE;
7217 gboolean is_all_drained = TRUE;
7220 MMPLAYER_RETURN_IF_FAIL(player);
7222 LOGD("__mmplayer_gst_decode_drained");
7224 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7225 LOGW("Fail to get cmd lock");
7229 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7230 !__mmplayer_verify_gapless_play_path(player)) {
7231 LOGD("decoding is finished.");
7232 __mmplayer_reset_gapless_state(player);
7233 MMPLAYER_CMD_UNLOCK(player);
7237 player->gapless.reconfigure = TRUE;
7239 /* check decodebin src pads whether they received EOS or not */
7240 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7243 switch (gst_iterator_next(iter, &item)) {
7244 case GST_ITERATOR_OK:
7245 pad = g_value_get_object(&item);
7246 if (pad && !GST_PAD_IS_EOS(pad)) {
7247 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7248 is_all_drained = FALSE;
7251 g_value_reset(&item);
7253 case GST_ITERATOR_RESYNC:
7254 gst_iterator_resync(iter);
7256 case GST_ITERATOR_ERROR:
7257 case GST_ITERATOR_DONE:
7262 g_value_unset(&item);
7263 gst_iterator_free(iter);
7265 if (!is_all_drained) {
7266 LOGD("Wait util the all pads get EOS.");
7267 MMPLAYER_CMD_UNLOCK(player);
7272 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7273 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7275 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7276 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7277 __mmplayer_deactivate_old_path(player);
7278 MMPLAYER_CMD_UNLOCK(player);
7284 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7286 mmplayer_t *player = (mmplayer_t *)data;
7287 const gchar *klass = NULL;
7288 gchar *factory_name = NULL;
7290 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7291 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7293 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7295 if (__mmplayer_add_dump_buffer_probe(player, element))
7296 LOGD("add buffer probe");
7298 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7299 gchar *selected = NULL;
7300 selected = g_strdup(GST_ELEMENT_NAME(element));
7301 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7304 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7305 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7306 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7308 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7309 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7311 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7312 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7313 "max-video-width", player->adaptive_info.limit.width,
7314 "max-video-height", player->adaptive_info.limit.height, NULL);
7316 } else if (g_strrstr(klass, "Demuxer")) {
7318 LOGD("plugged element is demuxer. take it");
7320 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7321 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7324 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7325 int surface_type = 0;
7327 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7330 // to support trust-zone only
7331 if (g_strrstr(factory_name, "asfdemux")) {
7332 LOGD("set file-location %s", player->profile.uri);
7333 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7334 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7335 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7336 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7337 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7338 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7339 (__mmplayer_is_only_mp3_type(player->type))) {
7340 LOGD("[mpegaudioparse] set streaming pull mode.");
7341 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7343 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7344 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7347 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7348 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7349 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7351 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7352 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7354 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7355 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7356 (MMPLAYER_IS_DASH_STREAMING(player))) {
7357 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7358 _mm_player_streaming_set_multiqueue(player->streamer, element);
7359 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7368 __mmplayer_release_misc(mmplayer_t *player)
7371 bool cur_mode = player->set_mode.rich_audio;
7374 MMPLAYER_RETURN_IF_FAIL(player);
7376 player->video_decoded_cb = NULL;
7377 player->video_decoded_cb_user_param = NULL;
7378 player->video_stream_prerolled = false;
7380 player->audio_decoded_cb = NULL;
7381 player->audio_decoded_cb_user_param = NULL;
7382 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7384 player->audio_stream_changed_cb = NULL;
7385 player->audio_stream_changed_cb_user_param = NULL;
7387 player->sent_bos = FALSE;
7388 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7390 player->seek_state = MMPLAYER_SEEK_NONE;
7392 player->total_bitrate = 0;
7393 player->total_maximum_bitrate = 0;
7395 player->not_found_demuxer = 0;
7397 player->last_position = 0;
7398 player->duration = 0;
7399 player->http_content_size = 0;
7400 player->not_supported_codec = MISSING_PLUGIN_NONE;
7401 player->can_support_codec = FOUND_PLUGIN_NONE;
7402 player->pending_seek.is_pending = false;
7403 player->pending_seek.pos = 0;
7404 player->msg_posted = FALSE;
7405 player->has_many_types = FALSE;
7406 player->is_subtitle_force_drop = FALSE;
7407 player->play_subtitle = FALSE;
7408 player->adjust_subtitle_pos = 0;
7409 player->has_closed_caption = FALSE;
7410 player->set_mode.video_export = false;
7411 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7412 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7414 player->set_mode.rich_audio = cur_mode;
7416 if (player->audio_device_cb_id > 0 &&
7417 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7418 LOGW("failed to remove audio device_connected_callback");
7419 player->audio_device_cb_id = 0;
7421 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7422 player->bitrate[i] = 0;
7423 player->maximum_bitrate[i] = 0;
7426 /* free memory related to audio effect */
7427 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7429 if (player->adaptive_info.var_list) {
7430 g_list_free_full(player->adaptive_info.var_list, g_free);
7431 player->adaptive_info.var_list = NULL;
7434 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7435 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7436 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7438 /* Reset video360 settings to their defaults in case if the pipeline is to be
7441 player->video360_metadata.is_spherical = -1;
7442 player->is_openal_plugin_used = FALSE;
7444 player->is_content_spherical = FALSE;
7445 player->is_video360_enabled = TRUE;
7446 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7447 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7448 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7449 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7450 player->video360_zoom = 1.0f;
7451 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7452 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7454 player->sound.rg_enable = false;
7456 __mmplayer_initialize_video_roi(player);
7461 __mmplayer_release_misc_post(mmplayer_t *player)
7463 char *original_uri = NULL;
7466 /* player->pipeline is already released before. */
7468 MMPLAYER_RETURN_IF_FAIL(player);
7470 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7472 /* clean found audio decoders */
7473 if (player->audio_decoders) {
7474 GList *a_dec = player->audio_decoders;
7475 for (; a_dec; a_dec = g_list_next(a_dec)) {
7476 gchar *name = a_dec->data;
7477 MMPLAYER_FREEIF(name);
7479 g_list_free(player->audio_decoders);
7480 player->audio_decoders = NULL;
7483 /* clean the uri list except original uri */
7484 if (player->uri_info.uri_list) {
7485 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7488 LOGW("failed to get original uri info");
7490 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7491 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7493 GList *uri_list = player->uri_info.uri_list;
7494 for (; uri_list; uri_list = g_list_next(uri_list)) {
7495 gchar *uri = uri_list->data;
7496 MMPLAYER_FREEIF(uri);
7498 g_list_free(player->uri_info.uri_list);
7499 player->uri_info.uri_list = NULL;
7502 /* clear the audio stream buffer list */
7503 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7505 /* clear the video stream bo list */
7506 __mmplayer_video_stream_destroy_bo_list(player);
7507 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7509 if (player->profile.input_mem.buf) {
7510 free(player->profile.input_mem.buf);
7511 player->profile.input_mem.buf = NULL;
7513 player->profile.input_mem.len = 0;
7514 player->profile.input_mem.offset = 0;
7516 player->uri_info.uri_idx = 0;
7521 __mmplayer_check_subtitle(mmplayer_t *player)
7523 MMHandleType attrs = 0;
7524 char *subtitle_uri = NULL;
7528 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7530 /* get subtitle attribute */
7531 attrs = MMPLAYER_GET_ATTRS(player);
7535 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7536 if (!subtitle_uri || !strlen(subtitle_uri))
7539 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7540 player->is_external_subtitle_present = TRUE;
7548 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7550 MMPLAYER_RETURN_IF_FAIL(player);
7552 if (player->eos_timer) {
7553 LOGD("cancel eos timer");
7554 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7555 player->eos_timer = 0;
7562 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7566 MMPLAYER_RETURN_IF_FAIL(player);
7567 MMPLAYER_RETURN_IF_FAIL(sink);
7569 player->sink_elements = g_list_append(player->sink_elements, sink);
7575 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7579 MMPLAYER_RETURN_IF_FAIL(player);
7580 MMPLAYER_RETURN_IF_FAIL(sink);
7582 player->sink_elements = g_list_remove(player->sink_elements, sink);
7588 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7589 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7591 mmplayer_signal_item_t *item = NULL;
7594 MMPLAYER_RETURN_IF_FAIL(player);
7596 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7597 LOGE("invalid signal type [%d]", type);
7601 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7603 LOGE("cannot connect signal [%s]", signal);
7608 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7609 player->signals[type] = g_list_append(player->signals[type], item);
7615 /* NOTE : be careful with calling this api. please refer to below glib comment
7616 * glib comment : Note that there is a bug in GObject that makes this function much
7617 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7618 * will no longer be called, but, the signal handler is not currently disconnected.
7619 * If the instance is itself being freed at the same time than this doesn't matter,
7620 * since the signal will automatically be removed, but if instance persists,
7621 * then the signal handler will leak. You should not remove the signal yourself
7622 * because in a future versions of GObject, the handler will automatically be
7625 * It's possible to work around this problem in a way that will continue to work
7626 * with future versions of GObject by checking that the signal handler is still
7627 * connected before disconnected it:
7629 * if (g_signal_handler_is_connected(instance, id))
7630 * g_signal_handler_disconnect(instance, id);
7633 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7635 GList *sig_list = NULL;
7636 mmplayer_signal_item_t *item = NULL;
7640 MMPLAYER_RETURN_IF_FAIL(player);
7642 LOGD("release signals type : %d", type);
7644 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7645 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7646 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7647 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7648 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7649 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7653 sig_list = player->signals[type];
7655 for (; sig_list; sig_list = sig_list->next) {
7656 item = sig_list->data;
7658 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7659 if (g_signal_handler_is_connected(item->obj, item->sig))
7660 g_signal_handler_disconnect(item->obj, item->sig);
7663 MMPLAYER_FREEIF(item);
7666 g_list_free(player->signals[type]);
7667 player->signals[type] = NULL;
7675 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7677 mmplayer_t *player = 0;
7678 int prev_display_surface_type = 0;
7682 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7684 player = MM_PLAYER_CAST(handle);
7686 /* check video sinkbin is created */
7687 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7688 LOGW("Videosink is already created");
7689 return MM_ERROR_NONE;
7692 LOGD("videosink element is not yet ready");
7694 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7695 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7697 return MM_ERROR_INVALID_ARGUMENT;
7700 /* load previous attributes */
7701 if (player->attrs) {
7702 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7703 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7704 if (prev_display_surface_type == surface_type) {
7705 LOGD("incoming display surface type is same as previous one, do nothing..");
7707 return MM_ERROR_NONE;
7710 LOGE("failed to load attributes");
7712 return MM_ERROR_PLAYER_INTERNAL;
7715 /* videobin is not created yet, so we just set attributes related to display surface */
7716 LOGD("store display attribute for given surface type(%d)", surface_type);
7717 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7718 "display_overlay", wl_surface_id, NULL);
7721 return MM_ERROR_NONE;
7724 /* Note : if silent is true, then subtitle would not be displayed. :*/
7726 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7728 mmplayer_t *player = (mmplayer_t *)hplayer;
7732 /* check player handle */
7733 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7735 player->set_mode.subtitle_off = silent;
7737 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7741 return MM_ERROR_NONE;
7745 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7747 mmplayer_gst_element_t *mainbin = NULL;
7748 mmplayer_gst_element_t *textbin = NULL;
7749 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7750 GstState current_state = GST_STATE_VOID_PENDING;
7751 GstState element_state = GST_STATE_VOID_PENDING;
7752 GstState element_pending_state = GST_STATE_VOID_PENDING;
7754 GstEvent *event = NULL;
7755 int result = MM_ERROR_NONE;
7757 GstClock *curr_clock = NULL;
7758 GstClockTime base_time, start_time, curr_time;
7763 /* check player handle */
7764 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7766 player->pipeline->mainbin &&
7767 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7769 mainbin = player->pipeline->mainbin;
7770 textbin = player->pipeline->textbin;
7772 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7774 // sync clock with current pipeline
7775 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7776 curr_time = gst_clock_get_time(curr_clock);
7778 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7779 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7781 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7782 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7784 if (current_state > GST_STATE_READY) {
7785 // sync state with current pipeline
7786 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7787 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7788 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7790 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7791 if (GST_STATE_CHANGE_FAILURE == ret) {
7792 LOGE("fail to state change.");
7793 result = MM_ERROR_PLAYER_INTERNAL;
7797 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7798 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7801 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7802 gst_object_unref(curr_clock);
7805 // seek to current position
7806 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7807 result = MM_ERROR_PLAYER_INVALID_STATE;
7808 LOGE("gst_element_query_position failed, invalid state");
7812 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7813 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);
7815 _mmplayer_gst_send_event_to_sink(player, event);
7817 result = MM_ERROR_PLAYER_INTERNAL;
7818 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7822 /* sync state with current pipeline */
7823 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7824 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7825 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7827 return MM_ERROR_NONE;
7830 /* release text pipeline resource */
7831 player->textsink_linked = 0;
7833 /* release signal */
7834 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7836 /* release textbin with it's childs */
7837 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7838 MMPLAYER_FREEIF(player->pipeline->textbin);
7839 player->pipeline->textbin = NULL;
7841 /* release subtitle elem */
7842 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7843 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7849 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7851 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7852 GstState current_state = GST_STATE_VOID_PENDING;
7854 MMHandleType attrs = 0;
7855 mmplayer_gst_element_t *mainbin = NULL;
7856 mmplayer_gst_element_t *textbin = NULL;
7858 gchar *subtitle_uri = NULL;
7859 int result = MM_ERROR_NONE;
7860 const gchar *charset = NULL;
7864 /* check player handle */
7865 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7867 player->pipeline->mainbin &&
7868 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7869 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7871 mainbin = player->pipeline->mainbin;
7872 textbin = player->pipeline->textbin;
7874 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7875 if (current_state < GST_STATE_READY) {
7876 result = MM_ERROR_PLAYER_INVALID_STATE;
7877 LOGE("Pipeline is not in proper state");
7881 attrs = MMPLAYER_GET_ATTRS(player);
7883 LOGE("cannot get content attribute");
7884 result = MM_ERROR_PLAYER_INTERNAL;
7888 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7889 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7890 LOGE("subtitle uri is not proper filepath");
7891 result = MM_ERROR_PLAYER_INVALID_URI;
7895 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7896 LOGE("failed to get storage info of subtitle path");
7897 result = MM_ERROR_PLAYER_INVALID_URI;
7901 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7902 SECURE_LOGD("new subtitle file path is [%s]", filepath);
7904 if (!strcmp(filepath, subtitle_uri)) {
7905 LOGD("subtitle path is not changed");
7908 if (mm_player_set_attribute((MMHandleType)player, NULL,
7909 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7910 LOGE("failed to set attribute");
7915 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7916 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7917 player->subtitle_language_list = NULL;
7918 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7920 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7921 if (ret != GST_STATE_CHANGE_SUCCESS) {
7922 LOGE("failed to change state of textbin to READY");
7923 result = MM_ERROR_PLAYER_INTERNAL;
7927 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7928 if (ret != GST_STATE_CHANGE_SUCCESS) {
7929 LOGE("failed to change state of subparse to READY");
7930 result = MM_ERROR_PLAYER_INTERNAL;
7934 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7935 if (ret != GST_STATE_CHANGE_SUCCESS) {
7936 LOGE("failed to change state of filesrc to READY");
7937 result = MM_ERROR_PLAYER_INTERNAL;
7941 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7943 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7945 charset = _mmplayer_get_charset(filepath);
7947 LOGD("detected charset is %s", charset);
7948 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7951 result = _mmplayer_sync_subtitle_pipeline(player);
7958 /* API to switch between external subtitles */
7960 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7962 int result = MM_ERROR_NONE;
7963 mmplayer_t *player = (mmplayer_t *)hplayer;
7968 /* check player handle */
7969 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7971 /* filepath can be null in idle state */
7973 /* check file path */
7974 if ((path = strstr(filepath, "file://")))
7975 result = _mmplayer_exist_file_path(path + 7);
7977 result = _mmplayer_exist_file_path(filepath);
7979 if (result != MM_ERROR_NONE) {
7980 LOGE("invalid subtitle path 0x%X", result);
7981 return result; /* file not found or permission denied */
7985 if (!player->pipeline) {
7987 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
7988 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
7989 LOGE("failed to set attribute");
7990 return MM_ERROR_PLAYER_INTERNAL;
7993 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7994 /* check filepath */
7995 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7997 if (!__mmplayer_check_subtitle(player)) {
7998 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
7999 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8000 LOGE("failed to set attribute");
8001 return MM_ERROR_PLAYER_INTERNAL;
8004 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8005 LOGE("fail to create text pipeline");
8006 return MM_ERROR_PLAYER_INTERNAL;
8009 result = _mmplayer_sync_subtitle_pipeline(player);
8011 result = __mmplayer_change_external_subtitle_language(player, filepath);
8014 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8015 player->is_external_subtitle_added_now = TRUE;
8017 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8018 if (!player->subtitle_language_list) {
8019 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8020 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8021 LOGW("subtitle language list is not updated yet");
8023 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8031 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8033 int result = MM_ERROR_NONE;
8034 gchar *change_pad_name = NULL;
8035 GstPad *sinkpad = NULL;
8036 mmplayer_gst_element_t *mainbin = NULL;
8037 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8038 GstCaps *caps = NULL;
8039 gint total_track_num = 0;
8043 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8044 MM_ERROR_PLAYER_NOT_INITIALIZED);
8046 LOGD("Change Track(%d) to %d", type, index);
8048 mainbin = player->pipeline->mainbin;
8050 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8051 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8052 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8053 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8055 /* Changing Video Track is not supported. */
8056 LOGE("Track Type Error");
8060 if (mainbin[elem_idx].gst == NULL) {
8061 result = MM_ERROR_PLAYER_NO_OP;
8062 LOGD("Req track doesn't exist");
8066 total_track_num = player->selector[type].total_track_num;
8067 if (total_track_num <= 0) {
8068 result = MM_ERROR_PLAYER_NO_OP;
8069 LOGD("Language list is not available");
8073 if ((index < 0) || (index >= total_track_num)) {
8074 result = MM_ERROR_INVALID_ARGUMENT;
8075 LOGD("Not a proper index : %d", index);
8079 /*To get the new pad from the selector*/
8080 change_pad_name = g_strdup_printf("sink_%u", index);
8081 if (change_pad_name == NULL) {
8082 result = MM_ERROR_PLAYER_INTERNAL;
8083 LOGD("Pad does not exists");
8087 LOGD("new active pad name: %s", change_pad_name);
8089 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8090 if (sinkpad == NULL) {
8091 LOGD("sinkpad is NULL");
8092 result = MM_ERROR_PLAYER_INTERNAL;
8096 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8097 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8099 caps = gst_pad_get_current_caps(sinkpad);
8100 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8103 gst_object_unref(sinkpad);
8105 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8106 __mmplayer_set_audio_attrs(player, caps);
8109 MMPLAYER_FREEIF(change_pad_name);
8114 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8116 int result = MM_ERROR_NONE;
8117 mmplayer_t *player = NULL;
8118 mmplayer_gst_element_t *mainbin = NULL;
8120 gint current_active_index = 0;
8122 GstState current_state = GST_STATE_VOID_PENDING;
8123 GstEvent *event = NULL;
8128 player = (mmplayer_t *)hplayer;
8129 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8131 if (!player->pipeline) {
8132 LOGE("Track %d pre setting -> %d", type, index);
8134 player->selector[type].active_pad_index = index;
8138 mainbin = player->pipeline->mainbin;
8140 current_active_index = player->selector[type].active_pad_index;
8142 /*If index is same as running index no need to change the pad*/
8143 if (current_active_index == index)
8146 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8147 result = MM_ERROR_PLAYER_INVALID_STATE;
8151 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8152 if (current_state < GST_STATE_PAUSED) {
8153 result = MM_ERROR_PLAYER_INVALID_STATE;
8154 LOGW("Pipeline not in porper state");
8158 result = __mmplayer_change_selector_pad(player, type, index);
8159 if (result != MM_ERROR_NONE) {
8160 LOGE("change selector pad error");
8164 player->selector[type].active_pad_index = index;
8166 if (current_state == GST_STATE_PLAYING) {
8167 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8168 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8169 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8171 _mmplayer_gst_send_event_to_sink(player, event);
8173 result = MM_ERROR_PLAYER_INTERNAL;
8183 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8185 mmplayer_t *player = (mmplayer_t *)hplayer;
8189 /* check player handle */
8190 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8192 *silent = player->set_mode.subtitle_off;
8194 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8198 return MM_ERROR_NONE;
8202 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8204 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8205 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8207 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8208 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8212 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8213 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8214 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8215 mmplayer_dump_t *dump_s;
8216 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8217 if (dump_s == NULL) {
8218 LOGE("malloc fail");
8222 dump_s->dump_element_file = NULL;
8223 dump_s->dump_pad = NULL;
8224 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8226 if (dump_s->dump_pad) {
8227 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8228 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]);
8229 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8230 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);
8231 /* add list for removed buffer probe and close FILE */
8232 player->dump_list = g_list_append(player->dump_list, dump_s);
8233 LOGD("%s sink pad added buffer probe for dump", factory_name);
8236 MMPLAYER_FREEIF(dump_s);
8237 LOGE("failed to get %s sink pad added", factory_name);
8244 static GstPadProbeReturn
8245 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8247 FILE *dump_data = (FILE *)u_data;
8249 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8250 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8252 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8254 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8256 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8258 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8260 gst_buffer_unmap(buffer, &probe_info);
8262 return GST_PAD_PROBE_OK;
8266 __mmplayer_release_dump_list(GList *dump_list)
8268 GList *d_list = dump_list;
8273 for (; d_list; d_list = g_list_next(d_list)) {
8274 mmplayer_dump_t *dump_s = d_list->data;
8275 if (dump_s->dump_pad) {
8276 if (dump_s->probe_handle_id)
8277 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8278 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8280 if (dump_s->dump_element_file) {
8281 fclose(dump_s->dump_element_file);
8282 dump_s->dump_element_file = NULL;
8284 MMPLAYER_FREEIF(dump_s);
8286 g_list_free(dump_list);
8291 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8293 mmplayer_t *player = (mmplayer_t *)hplayer;
8297 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8298 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8300 *exist = (bool)player->has_closed_caption;
8304 return MM_ERROR_NONE;
8308 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8313 LOGD("unref internal gst buffer %p", buffer);
8315 gst_buffer_unref((GstBuffer *)buffer);
8322 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8324 mmplayer_t *player = (mmplayer_t *)hplayer;
8328 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8329 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8331 if (MMPLAYER_IS_STREAMING(player))
8332 *timeout = (int)player->ini.live_state_change_timeout;
8334 *timeout = (int)player->ini.localplayback_state_change_timeout;
8336 LOGD("timeout = %d", *timeout);
8339 return MM_ERROR_NONE;
8343 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8347 MMPLAYER_RETURN_IF_FAIL(player);
8349 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8351 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8352 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8353 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8354 player->storage_info[i].id = -1;
8355 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8357 if (path_type != MMPLAYER_PATH_MAX)
8366 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8368 int ret = MM_ERROR_NONE;
8369 mmplayer_t *player = (mmplayer_t *)hplayer;
8370 MMMessageParamType msg_param = {0, };
8373 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8375 LOGW("state changed storage %d:%d", id, state);
8377 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8378 return MM_ERROR_NONE;
8380 /* FIXME: text path should be handled seperately. */
8381 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8382 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8383 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8384 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8385 LOGW("external storage is removed");
8387 if (player->msg_posted == FALSE) {
8388 memset(&msg_param, 0, sizeof(MMMessageParamType));
8389 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8390 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8391 player->msg_posted = TRUE;
8394 /* unrealize the player */
8395 ret = _mmplayer_unrealize(hplayer);
8396 if (ret != MM_ERROR_NONE)
8397 LOGE("failed to unrealize");
8405 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8407 int ret = MM_ERROR_NONE;
8408 mmplayer_t *player = (mmplayer_t *)hplayer;
8409 int idx = 0, total = 0;
8410 gchar *result = NULL, *tmp = NULL;
8413 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8414 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8416 total = *num = g_list_length(player->adaptive_info.var_list);
8418 LOGW("There is no stream variant info.");
8422 result = g_strdup("");
8423 for (idx = 0 ; idx < total ; idx++) {
8424 stream_variant_t *v_data = NULL;
8425 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8428 gchar data[64] = {0};
8429 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8431 tmp = g_strconcat(result, data, NULL);
8435 LOGW("There is no variant data in %d", idx);
8440 *var_info = (char *)result;
8442 LOGD("variant info %d:%s", *num, *var_info);
8448 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8450 int ret = MM_ERROR_NONE;
8451 mmplayer_t *player = (mmplayer_t *)hplayer;
8454 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8456 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8458 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8459 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8460 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8462 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8463 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8464 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8465 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8467 /* FIXME: seek to current position for applying new variant limitation */
8476 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8478 int ret = MM_ERROR_NONE;
8479 mmplayer_t *player = (mmplayer_t *)hplayer;
8482 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8483 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8485 *bandwidth = player->adaptive_info.limit.bandwidth;
8486 *width = player->adaptive_info.limit.width;
8487 *height = player->adaptive_info.limit.height;
8489 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8496 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8498 int ret = MM_ERROR_NONE;
8499 mmplayer_t *player = (mmplayer_t *)hplayer;
8502 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8503 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8504 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8506 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8508 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8509 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8510 else /* live case */
8511 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8513 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8520 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8522 #define IDX_FIRST_SW_CODEC 0
8523 mmplayer_t *player = (mmplayer_t *)hplayer;
8524 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8527 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8529 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8530 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8531 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8533 switch (stream_type) {
8534 case MM_PLAYER_STREAM_TYPE_AUDIO:
8535 /* to support audio codec selection, codec info have to be added in ini file as below.
8536 audio codec element hw = xxxx
8537 audio codec element sw = avdec */
8538 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8539 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8540 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8541 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8542 LOGE("There is no audio codec info for codec_type %d", codec_type);
8543 return MM_ERROR_PLAYER_NO_OP;
8546 case MM_PLAYER_STREAM_TYPE_VIDEO:
8547 /* to support video codec selection, codec info have to be added in ini file as below.
8548 video codec element hw = omx
8549 video codec element sw = avdec */
8550 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8551 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8552 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8553 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8554 LOGE("There is no video codec info for codec_type %d", codec_type);
8555 return MM_ERROR_PLAYER_NO_OP;
8559 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8560 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8564 LOGD("update %s codec_type to %d", attr_name, codec_type);
8565 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8568 return MM_ERROR_NONE;
8572 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8574 mmplayer_t *player = (mmplayer_t *)hplayer;
8575 GstElement *rg_vol_element = NULL;
8579 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8581 player->sound.rg_enable = enabled;
8583 /* just hold rgvolume enable value if pipeline is not ready */
8584 if (!player->pipeline || !player->pipeline->audiobin) {
8585 LOGD("pipeline is not ready. holding rgvolume enable value");
8586 return MM_ERROR_NONE;
8589 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8591 if (!rg_vol_element) {
8592 LOGD("rgvolume element is not created");
8593 return MM_ERROR_PLAYER_INTERNAL;
8597 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8599 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8603 return MM_ERROR_NONE;
8607 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8609 mmplayer_t *player = (mmplayer_t *)hplayer;
8610 GstElement *rg_vol_element = NULL;
8611 gboolean enable = FALSE;
8615 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8616 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8618 /* just hold enable_rg value if pipeline is not ready */
8619 if (!player->pipeline || !player->pipeline->audiobin) {
8620 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8621 *enabled = player->sound.rg_enable;
8622 return MM_ERROR_NONE;
8625 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8627 if (!rg_vol_element) {
8628 LOGD("rgvolume element is not created");
8629 return MM_ERROR_PLAYER_INTERNAL;
8632 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8633 *enabled = (bool)enable;
8637 return MM_ERROR_NONE;
8641 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8643 mmplayer_t *player = (mmplayer_t *)hplayer;
8644 MMHandleType attrs = 0;
8646 int ret = MM_ERROR_NONE;
8650 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8652 attrs = MMPLAYER_GET_ATTRS(player);
8653 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8655 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8657 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8658 return MM_ERROR_PLAYER_INTERNAL;
8661 player->video_roi.scale_x = scale_x;
8662 player->video_roi.scale_y = scale_y;
8663 player->video_roi.scale_width = scale_width;
8664 player->video_roi.scale_height = scale_height;
8666 /* check video sinkbin is created */
8667 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8668 return MM_ERROR_NONE;
8670 if (!gst_video_overlay_set_video_roi_area(
8671 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8672 scale_x, scale_y, scale_width, scale_height))
8673 ret = MM_ERROR_PLAYER_INTERNAL;
8675 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8676 scale_x, scale_y, scale_width, scale_height);
8684 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8686 mmplayer_t *player = (mmplayer_t *)hplayer;
8687 int ret = MM_ERROR_NONE;
8691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8692 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8694 *scale_x = player->video_roi.scale_x;
8695 *scale_y = player->video_roi.scale_y;
8696 *scale_width = player->video_roi.scale_width;
8697 *scale_height = player->video_roi.scale_height;
8699 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8700 *scale_x, *scale_y, *scale_width, *scale_height);
8706 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8708 mmplayer_t* player = (mmplayer_t*)hplayer;
8712 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8714 player->client_pid = pid;
8716 LOGD("client pid[%d] %p", pid, player);
8720 return MM_ERROR_NONE;
8724 __mmplayer_update_duration_value(mmplayer_t *player)
8726 gboolean ret = FALSE;
8727 gint64 dur_nsec = 0;
8728 LOGD("try to update duration");
8730 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8731 player->duration = dur_nsec;
8732 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8736 if (player->duration < 0) {
8737 LOGW("duration is Non-Initialized !!!");
8738 player->duration = 0;
8741 /* update streaming service type */
8742 player->streaming_type = _mmplayer_get_stream_service_type(player);
8744 /* check duration is OK */
8745 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8746 /* FIXIT : find another way to get duration here. */
8747 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8753 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8755 /* update audio params
8756 NOTE : We need original audio params and it can be only obtained from src pad of audio
8757 decoder. Below code only valid when we are not using 'resampler' just before
8758 'audioconverter'. */
8759 GstCaps *caps_a = NULL;
8761 gint samplerate = 0, channels = 0;
8762 GstStructure *p = NULL;
8763 GstElement *aconv = NULL;
8765 LOGD("try to update audio attrs");
8767 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8769 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8770 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8771 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8772 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8774 LOGE("there is no audio converter");
8778 pad = gst_element_get_static_pad(aconv, "sink");
8781 LOGW("failed to get pad from audio converter");
8785 caps_a = gst_pad_get_current_caps(pad);
8787 LOGW("not ready to get audio caps");
8788 gst_object_unref(pad);
8792 p = gst_caps_get_structure(caps_a, 0);
8794 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8796 gst_structure_get_int(p, "rate", &samplerate);
8797 gst_structure_get_int(p, "channels", &channels);
8799 mm_player_set_attribute((MMHandleType)player, NULL,
8800 "content_audio_samplerate", samplerate,
8801 "content_audio_channels", channels, NULL);
8803 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8805 gst_caps_unref(caps_a);
8806 gst_object_unref(pad);
8812 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8814 LOGD("try to update video attrs");
8816 GstCaps *caps_v = NULL;
8820 GstStructure *p = NULL;
8822 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8823 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8825 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8827 LOGD("no videosink sink pad");
8831 caps_v = gst_pad_get_current_caps(pad);
8832 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8833 if (!caps_v && player->v_stream_caps) {
8834 caps_v = player->v_stream_caps;
8835 gst_caps_ref(caps_v);
8839 LOGD("no negitiated caps from videosink");
8840 gst_object_unref(pad);
8844 p = gst_caps_get_structure(caps_v, 0);
8845 gst_structure_get_int(p, "width", &width);
8846 gst_structure_get_int(p, "height", &height);
8848 mm_player_set_attribute((MMHandleType)player, NULL,
8849 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
8851 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8853 SECURE_LOGD("width : %d height : %d", width, height);
8855 gst_caps_unref(caps_v);
8856 gst_object_unref(pad);
8859 mm_player_set_attribute((MMHandleType)player, NULL,
8860 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
8861 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8868 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8870 gboolean ret = FALSE;
8871 guint64 data_size = 0;
8875 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8876 if (!player->duration)
8879 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8880 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8881 if (stat(path, &sb) == 0)
8882 data_size = (guint64)sb.st_size;
8884 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8885 data_size = player->http_content_size;
8888 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8891 guint64 bitrate = 0;
8892 guint64 msec_dur = 0;
8894 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8896 bitrate = data_size * 8 * 1000 / msec_dur;
8897 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
8898 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8899 mm_player_set_attribute((MMHandleType)player, NULL,
8900 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
8903 LOGD("player duration is less than 0");
8907 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8908 if (player->total_bitrate) {
8909 mm_player_set_attribute((MMHandleType)player, NULL,
8910 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
8919 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8921 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8922 data->uri_type = uri_type;
8926 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8928 int ret = MM_ERROR_PLAYER_INVALID_URI;
8930 char *buffer = NULL;
8931 char *seperator = strchr(path, ',');
8932 char ext[100] = {0,}, size[100] = {0,};
8935 if ((buffer = strstr(path, "ext="))) {
8936 buffer += strlen("ext=");
8938 if (strlen(buffer)) {
8939 strncpy(ext, buffer, 99);
8941 if ((seperator = strchr(ext, ','))
8942 || (seperator = strchr(ext, ' '))
8943 || (seperator = strchr(ext, '\0'))) {
8944 seperator[0] = '\0';
8949 if ((buffer = strstr(path, "size="))) {
8950 buffer += strlen("size=");
8952 if (strlen(buffer) > 0) {
8953 strncpy(size, buffer, 99);
8955 if ((seperator = strchr(size, ','))
8956 || (seperator = strchr(size, ' '))
8957 || (seperator = strchr(size, '\0'))) {
8958 seperator[0] = '\0';
8961 mem_size = atoi(size);
8966 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8968 if (mem_size && param) {
8969 if (data->input_mem.buf)
8970 free(data->input_mem.buf);
8971 data->input_mem.buf = malloc(mem_size);
8973 if (data->input_mem.buf) {
8974 memcpy(data->input_mem.buf, param, mem_size);
8975 data->input_mem.len = mem_size;
8976 ret = MM_ERROR_NONE;
8978 LOGE("failed to alloc mem %d", mem_size);
8979 ret = MM_ERROR_PLAYER_INTERNAL;
8982 data->input_mem.offset = 0;
8983 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8990 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
8992 gchar *location = NULL;
8995 int ret = MM_ERROR_NONE;
8997 if ((path = strstr(uri, "file://"))) {
8998 location = g_filename_from_uri(uri, NULL, &err);
8999 if (!location || (err != NULL)) {
9000 LOGE("Invalid URI '%s' for filesrc: %s", path,
9001 (err != NULL) ? err->message : "unknown error");
9005 MMPLAYER_FREEIF(location);
9007 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9008 return MM_ERROR_PLAYER_INVALID_URI;
9010 LOGD("path from uri: %s", location);
9013 path = (location != NULL) ? (location) : ((char *)uri);
9016 ret = _mmplayer_exist_file_path(path);
9018 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9019 if (ret == MM_ERROR_NONE) {
9020 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9021 if (_mmplayer_is_sdp_file(path)) {
9022 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9023 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9025 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9027 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9028 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9030 LOGE("invalid uri, could not play..");
9031 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9034 MMPLAYER_FREEIF(location);
9039 static mmplayer_video_decoded_data_info_t *
9040 __mmplayer_create_stream_from_pad(GstPad *pad)
9042 GstCaps *caps = NULL;
9043 GstStructure *structure = NULL;
9044 unsigned int fourcc = 0;
9045 const gchar *string_format = NULL;
9046 mmplayer_video_decoded_data_info_t *stream = NULL;
9048 MMPixelFormatType format;
9051 caps = gst_pad_get_current_caps(pad);
9053 LOGE("Caps is NULL.");
9058 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9060 structure = gst_caps_get_structure(caps, 0);
9061 gst_structure_get_int(structure, "width", &width);
9062 gst_structure_get_int(structure, "height", &height);
9063 string_format = gst_structure_get_string(structure, "format");
9066 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9067 format = _mmplayer_get_pixtype(fourcc);
9068 gst_video_info_from_caps(&info, caps);
9069 gst_caps_unref(caps);
9072 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9073 LOGE("Wrong condition!!");
9077 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9079 LOGE("failed to alloc mem for video data");
9083 stream->width = width;
9084 stream->height = height;
9085 stream->format = format;
9086 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9092 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9094 unsigned int pitch = 0;
9095 unsigned int size = 0;
9097 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9100 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9101 bo = gst_tizen_memory_get_bos(mem, index);
9103 stream->bo[index] = tbm_bo_ref(bo);
9105 LOGE("failed to get bo for index %d", index);
9108 for (index = 0; index < stream->plane_num; index++) {
9109 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9110 stream->stride[index] = pitch;
9112 stream->elevation[index] = size / pitch;
9114 stream->elevation[index] = stream->height;
9119 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9121 if (stream->format == MM_PIXEL_FORMAT_I420) {
9122 int ret = TBM_SURFACE_ERROR_NONE;
9123 tbm_surface_h surface;
9124 tbm_surface_info_s info;
9126 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9128 ret = tbm_surface_get_info(surface, &info);
9129 if (ret != TBM_SURFACE_ERROR_NONE) {
9130 tbm_surface_destroy(surface);
9134 tbm_surface_destroy(surface);
9135 stream->stride[0] = info.planes[0].stride;
9136 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9137 stream->stride[1] = info.planes[1].stride;
9138 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9139 stream->stride[2] = info.planes[2].stride;
9140 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9141 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9142 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9143 stream->stride[0] = stream->width * 4;
9144 stream->elevation[0] = stream->height;
9145 stream->bo_size = stream->stride[0] * stream->height;
9147 LOGE("Not support format %d", stream->format);
9155 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9157 tbm_bo_handle thandle;
9159 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9160 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9161 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9165 unsigned char *src = NULL;
9166 unsigned char *dest = NULL;
9167 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9169 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9171 LOGE("fail to gst_memory_map");
9175 if (!mapinfo.data) {
9176 LOGE("data pointer is wrong");
9180 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9181 if (!stream->bo[0]) {
9182 LOGE("Fail to tbm_bo_alloc!!");
9186 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9188 LOGE("thandle pointer is wrong");
9192 if (stream->format == MM_PIXEL_FORMAT_I420) {
9193 src_stride[0] = GST_ROUND_UP_4(stream->width);
9194 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9195 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9196 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9199 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9200 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9202 for (i = 0; i < 3; i++) {
9203 src = mapinfo.data + src_offset[i];
9204 dest = thandle.ptr + dest_offset[i];
9209 for (j = 0; j < stream->height >> k; j++) {
9210 memcpy(dest, src, stream->width>>k);
9211 src += src_stride[i];
9212 dest += stream->stride[i];
9215 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9216 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9218 LOGE("Not support format %d", stream->format);
9222 tbm_bo_unmap(stream->bo[0]);
9223 gst_memory_unmap(mem, &mapinfo);
9229 tbm_bo_unmap(stream->bo[0]);
9232 gst_memory_unmap(mem, &mapinfo);
9238 __mmplayer_set_pause_state(mmplayer_t *player)
9240 if (player->sent_bos)
9243 /* rtsp case, get content attrs by GstMessage */
9244 if (MMPLAYER_IS_RTSP_STREAMING(player))
9247 /* it's first time to update all content attrs. */
9248 _mmplayer_update_content_attrs(player, ATTR_ALL);
9252 __mmplayer_set_playing_state(mmplayer_t *player)
9254 gchar *audio_codec = NULL;
9256 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9257 /* initialize because auto resume is done well. */
9258 player->resumed_by_rewind = FALSE;
9259 player->playback_rate = 1.0;
9262 if (player->sent_bos)
9265 /* try to get content metadata */
9267 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9268 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9269 * legacy mmfw-player api
9271 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9273 if ((player->cmd == MMPLAYER_COMMAND_START)
9274 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9275 __mmplayer_handle_missed_plugin(player);
9278 /* check audio codec field is set or not
9279 * we can get it from typefinder or codec's caps.
9281 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9283 /* The codec format can't be sent for audio only case like amr, mid etc.
9284 * Because, parser don't make related TAG.
9285 * So, if it's not set yet, fill it with found data.
9288 if (g_strrstr(player->type, "audio/midi"))
9289 audio_codec = "MIDI";
9290 else if (g_strrstr(player->type, "audio/x-amr"))
9291 audio_codec = "AMR";
9292 else if (g_strrstr(player->type, "audio/mpeg")
9293 && !g_strrstr(player->type, "mpegversion=(int)1"))
9294 audio_codec = "AAC";
9296 audio_codec = "unknown";
9298 if (mm_player_set_attribute((MMHandleType)player, NULL,
9299 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9300 LOGE("failed to set attribute");
9302 LOGD("set audio codec type with caps");