4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_attrs.h"
47 #include "mm_player_capture.h"
48 #include "mm_player_utils.h"
49 #include "mm_player_tracks.h"
50 #include "mm_player_360.h"
51 #include "mm_player_gst.h"
53 #include <system_info.h>
54 #include <sound_manager.h>
55 #include <gst/allocators/gsttizenmemory.h>
56 #include <tbm_surface_internal.h>
58 /*===========================================================================================
60 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
62 ========================================================================================== */
64 /*---------------------------------------------------------------------------
65 | GLOBAL CONSTANT DEFINITIONS: |
66 ---------------------------------------------------------------------------*/
68 /*---------------------------------------------------------------------------
69 | IMPORTED VARIABLE DECLARATIONS: |
70 ---------------------------------------------------------------------------*/
72 /*---------------------------------------------------------------------------
73 | IMPORTED FUNCTION DECLARATIONS: |
74 ---------------------------------------------------------------------------*/
76 /*---------------------------------------------------------------------------
78 ---------------------------------------------------------------------------*/
79 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
80 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
82 #define MM_VOLUME_FACTOR_DEFAULT 1.0
83 #define MM_VOLUME_FACTOR_MIN 0
84 #define MM_VOLUME_FACTOR_MAX 1.0
86 /* Don't need to sleep for sound fadeout
87 * fadeout related fucntion will be deleted(Deprecated)
89 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
91 #define DEFAULT_PLAYBACK_RATE 1.0
93 #define PLAYER_DISPLAY_MODE_DST_ROI 5
95 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
97 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
98 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
99 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
100 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
102 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
103 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
105 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
107 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
108 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
109 #define DEFAULT_PCM_OUT_CHANNEL 2
111 /*---------------------------------------------------------------------------
112 | LOCAL CONSTANT DEFINITIONS: |
113 ---------------------------------------------------------------------------*/
115 /*---------------------------------------------------------------------------
116 | LOCAL DATA TYPE DEFINITIONS: |
117 ---------------------------------------------------------------------------*/
118 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
119 We are defining our own and will be removed when it actually exposed */
121 GST_AUTOPLUG_SELECT_TRY,
122 GST_AUTOPLUG_SELECT_EXPOSE,
123 GST_AUTOPLUG_SELECT_SKIP
124 } GstAutoplugSelectResult;
126 /*---------------------------------------------------------------------------
127 | GLOBAL VARIABLE DEFINITIONS: |
128 ---------------------------------------------------------------------------*/
130 /*---------------------------------------------------------------------------
131 | LOCAL VARIABLE DEFINITIONS: |
132 ---------------------------------------------------------------------------*/
133 static sound_stream_info_h stream_info;
135 /*---------------------------------------------------------------------------
136 | LOCAL FUNCTION PROTOTYPES: |
137 ---------------------------------------------------------------------------*/
138 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
141 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
142 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
143 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
145 static void __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data);
146 static void __mmplayer_gst_create_sinkbin(GstElement *decodebin, GstPad *pad, gpointer data);
147 static void __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad, GstCaps *caps, gpointer data);
148 static gboolean __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad, GstCaps *caps, gpointer data);
149 static void __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad, gpointer data);
150 static void __mmplayer_gst_decode_drained(GstElement *bin, gpointer data);
151 static void __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data);
152 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
153 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
154 static void __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps);
156 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
157 static void __mmplayer_release_misc(mmplayer_t *player);
158 static void __mmplayer_release_misc_post(mmplayer_t *player);
159 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
160 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
161 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
162 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
163 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
165 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
166 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
167 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
168 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink);
169 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
170 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
171 static gpointer __mmplayer_gapless_play_thread(gpointer data);
172 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
173 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
174 static void __mmplayer_release_dump_list(GList *dump_list);
175 static int __mmplayer_gst_realize(mmplayer_t *player);
176 static int __mmplayer_gst_unrealize(mmplayer_t *player);
177 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
178 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
181 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
182 static void __mmplayer_check_pipeline(mmplayer_t *player);
183 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
184 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
185 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
186 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
187 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
188 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
189 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
190 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
191 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
192 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
193 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
195 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
196 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
197 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
199 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
200 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
201 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
202 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
204 static void __mmplayer_set_pause_state(mmplayer_t *player);
205 static void __mmplayer_set_playing_state(mmplayer_t *player);
206 /*===========================================================================================
208 | FUNCTION DEFINITIONS |
210 ========================================================================================== */
212 /* This function should be called after the pipeline goes PAUSED or higher
215 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
217 static gboolean has_duration = FALSE;
218 static gboolean has_video_attrs = FALSE;
219 static gboolean has_audio_attrs = FALSE;
220 static gboolean has_bitrate = FALSE;
221 gboolean missing_only = FALSE;
222 gboolean all = FALSE;
223 MMHandleType attrs = 0;
227 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
229 /* check player state here */
230 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
231 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
232 /* give warning now only */
233 LOGW("be careful. content attributes may not available in this state ");
236 /* get content attribute first */
237 attrs = MMPLAYER_GET_ATTRS(player);
239 LOGE("cannot get content attribute");
243 /* get update flag */
245 if (flag & ATTR_MISSING_ONLY) {
247 LOGD("updating missed attr only");
250 if (flag & ATTR_ALL) {
252 has_duration = FALSE;
253 has_video_attrs = FALSE;
254 has_audio_attrs = FALSE;
257 LOGD("updating all attrs");
260 if (missing_only && all) {
261 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
262 missing_only = FALSE;
265 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
266 has_duration = __mmplayer_update_duration_value(player);
268 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
269 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
271 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
272 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
274 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
275 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
283 _mmplayer_get_stream_service_type(mmplayer_t *player)
285 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
289 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
291 player->pipeline->mainbin &&
292 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
293 STREAMING_SERVICE_NONE);
295 /* streaming service type if streaming */
296 if (!MMPLAYER_IS_STREAMING(player))
297 return STREAMING_SERVICE_NONE;
299 streaming_type = (player->duration == 0) ?
300 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
302 switch (streaming_type) {
303 case STREAMING_SERVICE_LIVE:
304 LOGD("it's live streaming");
306 case STREAMING_SERVICE_VOD:
307 LOGD("it's vod streaming");
310 LOGE("should not get here");
316 return streaming_type;
319 /* this function sets the player state and also report
320 * it to applicaton by calling callback function
323 _mmplayer_set_state(mmplayer_t *player, int state)
325 MMMessageParamType msg = {0, };
327 MMPLAYER_RETURN_IF_FAIL(player);
329 if (MMPLAYER_CURRENT_STATE(player) == state) {
330 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
331 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
335 /* update player states */
336 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
337 MMPLAYER_CURRENT_STATE(player) = state;
339 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
340 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
343 MMPLAYER_PRINT_STATE(player);
345 switch (MMPLAYER_CURRENT_STATE(player)) {
346 case MM_PLAYER_STATE_NULL:
347 case MM_PLAYER_STATE_READY:
349 case MM_PLAYER_STATE_PAUSED:
350 __mmplayer_set_pause_state(player);
352 case MM_PLAYER_STATE_PLAYING:
353 __mmplayer_set_playing_state(player);
355 case MM_PLAYER_STATE_NONE:
357 LOGW("invalid target state, there is nothing to do.");
362 /* post message to application */
363 if (MMPLAYER_TARGET_STATE(player) == state) {
364 /* fill the message with state of player */
365 msg.union_type = MM_MSG_UNION_STATE;
366 msg.state.previous = MMPLAYER_PREV_STATE(player);
367 msg.state.current = MMPLAYER_CURRENT_STATE(player);
369 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
371 /* state changed by resource callback */
372 if (player->interrupted_by_resource)
373 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
374 else /* state changed by usecase */
375 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
378 LOGD("intermediate state, do nothing.");
379 MMPLAYER_PRINT_STATE(player);
383 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
384 && !player->sent_bos) {
385 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
386 player->sent_bos = TRUE;
393 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
395 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
396 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
398 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
400 LOGD("incomming command : %d ", command);
402 current_state = MMPLAYER_CURRENT_STATE(player);
403 pending_state = MMPLAYER_PENDING_STATE(player);
405 MMPLAYER_PRINT_STATE(player);
408 case MMPLAYER_COMMAND_CREATE:
410 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
412 if (current_state == MM_PLAYER_STATE_NULL ||
413 current_state == MM_PLAYER_STATE_READY ||
414 current_state == MM_PLAYER_STATE_PAUSED ||
415 current_state == MM_PLAYER_STATE_PLAYING)
420 case MMPLAYER_COMMAND_DESTROY:
422 /* destroy can called anytime */
424 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
428 case MMPLAYER_COMMAND_REALIZE:
430 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
432 if (pending_state != MM_PLAYER_STATE_NONE) {
435 /* need ready state to realize */
436 if (current_state == MM_PLAYER_STATE_READY)
439 if (current_state != MM_PLAYER_STATE_NULL)
445 case MMPLAYER_COMMAND_UNREALIZE:
447 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
449 if (current_state == MM_PLAYER_STATE_NULL)
454 case MMPLAYER_COMMAND_START:
456 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
458 if (pending_state == MM_PLAYER_STATE_NONE) {
459 if (current_state == MM_PLAYER_STATE_PLAYING)
461 else if (current_state != MM_PLAYER_STATE_READY &&
462 current_state != MM_PLAYER_STATE_PAUSED)
464 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
466 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
467 LOGD("player is going to paused state, just change the pending state as playing");
474 case MMPLAYER_COMMAND_STOP:
476 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
478 if (current_state == MM_PLAYER_STATE_READY)
481 /* need playing/paused state to stop */
482 if (current_state != MM_PLAYER_STATE_PLAYING &&
483 current_state != MM_PLAYER_STATE_PAUSED)
488 case MMPLAYER_COMMAND_PAUSE:
490 if (MMPLAYER_IS_LIVE_STREAMING(player))
493 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
494 goto NOT_COMPLETED_SEEK;
496 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
498 if (pending_state == MM_PLAYER_STATE_NONE) {
499 if (current_state == MM_PLAYER_STATE_PAUSED)
501 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
503 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
505 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
506 if (current_state == MM_PLAYER_STATE_PAUSED)
507 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
514 case MMPLAYER_COMMAND_RESUME:
516 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
517 goto NOT_COMPLETED_SEEK;
519 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
521 if (pending_state == MM_PLAYER_STATE_NONE) {
522 if (current_state == MM_PLAYER_STATE_PLAYING)
524 else if (current_state != MM_PLAYER_STATE_PAUSED)
526 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
528 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
529 LOGD("player is going to paused state, just change the pending state as playing");
539 player->cmd = command;
541 return MM_ERROR_NONE;
544 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
545 MMPLAYER_STATE_GET_NAME(current_state), command);
546 return MM_ERROR_PLAYER_INVALID_STATE;
549 LOGW("not completed seek");
550 return MM_ERROR_PLAYER_DOING_SEEK;
553 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
554 return MM_ERROR_PLAYER_NO_OP;
557 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
558 return MM_ERROR_PLAYER_NO_OP;
561 static int __mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
563 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
564 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
567 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
568 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
570 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
571 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
573 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
574 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
577 LOGE("invalid mmplayer resource type %d", type);
578 return MM_ERROR_PLAYER_INTERNAL;
581 if (player->hw_resource[type] != NULL) {
582 LOGD("[%d type] resource was already acquired", type);
583 return MM_ERROR_NONE;
586 LOGD("mark for acquire [%d type] resource", type);
587 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
588 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
589 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
590 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
591 return MM_ERROR_PLAYER_INTERNAL;
594 rm_ret = mm_resource_manager_commit(player->resource_manager);
595 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
596 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
597 return MM_ERROR_PLAYER_INTERNAL;
601 return MM_ERROR_NONE;
604 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
606 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
610 if (player->hw_resource[type] == NULL) {
611 LOGD("there is no acquired [%d type] resource", type);
612 return MM_ERROR_NONE;
615 LOGD("mark for release [%d type] resource", type);
616 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
617 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
618 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
619 return MM_ERROR_PLAYER_INTERNAL;
622 player->hw_resource[type] = NULL;
624 rm_ret = mm_resource_manager_commit(player->resource_manager);
625 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
626 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
627 return MM_ERROR_PLAYER_INTERNAL;
631 return MM_ERROR_NONE;
635 __mmplayer_initialize_gapless_play(mmplayer_t *player)
641 player->smooth_streaming = FALSE;
642 player->videodec_linked = 0;
643 player->audiodec_linked = 0;
644 player->textsink_linked = 0;
645 player->is_external_subtitle_present = FALSE;
646 player->is_external_subtitle_added_now = FALSE;
647 player->not_supported_codec = MISSING_PLUGIN_NONE;
648 player->can_support_codec = FOUND_PLUGIN_NONE;
649 player->pending_seek.is_pending = false;
650 player->pending_seek.pos = 0;
651 player->msg_posted = FALSE;
652 player->has_many_types = FALSE;
653 player->no_more_pad = FALSE;
654 player->not_found_demuxer = 0;
655 player->seek_state = MMPLAYER_SEEK_NONE;
656 player->is_subtitle_force_drop = FALSE;
657 player->play_subtitle = FALSE;
658 player->adjust_subtitle_pos = 0;
660 player->total_bitrate = 0;
661 player->total_maximum_bitrate = 0;
663 _mmplayer_track_initialize(player);
664 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
666 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
667 player->bitrate[i] = 0;
668 player->maximum_bitrate[i] = 0;
671 if (player->v_stream_caps) {
672 gst_caps_unref(player->v_stream_caps);
673 player->v_stream_caps = NULL;
676 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
678 /* clean found audio decoders */
679 if (player->audio_decoders) {
680 GList *a_dec = player->audio_decoders;
681 for (; a_dec; a_dec = g_list_next(a_dec)) {
682 gchar *name = a_dec->data;
683 MMPLAYER_FREEIF(name);
685 g_list_free(player->audio_decoders);
686 player->audio_decoders = NULL;
689 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
695 __mmplayer_gapless_play_thread(gpointer data)
697 mmplayer_t *player = (mmplayer_t *)data;
698 mmplayer_gst_element_t *mainbin = NULL;
700 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
702 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
703 while (!player->gapless_play_thread_exit) {
704 LOGD("gapless play thread started. waiting for signal.");
705 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
707 LOGD("reconfigure pipeline for gapless play.");
709 if (player->gapless_play_thread_exit) {
710 if (player->gapless.reconfigure) {
711 player->gapless.reconfigure = false;
712 MMPLAYER_PLAYBACK_UNLOCK(player);
714 LOGD("exiting gapless play thread");
718 mainbin = player->pipeline->mainbin;
720 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
721 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
722 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
723 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
724 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
726 /* Initialize Player values */
727 __mmplayer_initialize_gapless_play(player);
729 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
731 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
737 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
739 GSource *source = NULL;
743 source = g_main_context_find_source_by_id(context, source_id);
744 if (source != NULL) {
745 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
746 g_source_destroy(source);
753 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
755 mmplayer_t *player = (mmplayer_t *)hplayer;
756 GstMessage *msg = NULL;
757 GQueue *queue = NULL;
760 MMPLAYER_RETURN_IF_FAIL(player);
762 /* disconnecting bus watch */
763 if (player->bus_watcher)
764 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
765 player->bus_watcher = 0;
767 /* destroy the gst bus msg thread */
768 if (player->bus_msg_thread) {
769 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
770 player->bus_msg_thread_exit = TRUE;
771 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
772 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
774 LOGD("gst bus msg thread exit.");
775 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
776 player->bus_msg_thread = NULL;
778 g_mutex_clear(&player->bus_msg_thread_mutex);
779 g_cond_clear(&player->bus_msg_thread_cond);
782 g_mutex_lock(&player->bus_msg_q_lock);
783 queue = player->bus_msg_q;
784 while (!g_queue_is_empty(queue)) {
785 msg = (GstMessage *)g_queue_pop_head(queue);
790 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
791 gst_message_unref(msg);
793 g_mutex_unlock(&player->bus_msg_q_lock);
799 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
801 GstElement *parent = NULL;
803 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
804 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
807 MMPLAYER_FSINK_LOCK(player);
809 /* get parent of fakesink */
810 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
812 LOGD("fakesink already removed");
816 gst_element_set_locked_state(fakesink->gst, TRUE);
818 /* setting the state to NULL never returns async
819 * so no need to wait for completion of state transiton
821 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
822 LOGE("fakesink state change failure!");
823 /* FIXIT : should I return here? or try to proceed to next? */
826 /* remove fakesink from it's parent */
827 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
828 LOGE("failed to remove fakesink");
830 gst_object_unref(parent);
835 gst_object_unref(parent);
837 LOGD("state-holder removed");
839 gst_element_set_locked_state(fakesink->gst, FALSE);
841 MMPLAYER_FSINK_UNLOCK(player);
846 gst_element_set_locked_state(fakesink->gst, FALSE);
848 MMPLAYER_FSINK_UNLOCK(player);
852 static GstPadProbeReturn
853 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
855 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
856 return GST_PAD_PROBE_OK;
860 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
862 gint64 stop_running_time = 0;
863 gint64 position_running_time = 0;
867 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
868 if ((player->gapless.update_segment[idx] == TRUE) ||
869 !(player->selector[idx].event_probe_id)) {
871 LOGW("[%d] skip", idx);
876 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
878 gst_segment_to_running_time(&player->gapless.segment[idx],
879 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
880 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
882 gst_segment_to_running_time(&player->gapless.segment[idx],
883 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
885 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
887 gst_segment_to_running_time(&player->gapless.segment[idx],
888 GST_FORMAT_TIME, player->duration);
891 position_running_time =
892 gst_segment_to_running_time(&player->gapless.segment[idx],
893 GST_FORMAT_TIME, player->gapless.segment[idx].position);
895 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
896 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
898 GST_TIME_ARGS(stop_running_time),
899 GST_TIME_ARGS(position_running_time),
900 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
901 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
903 position_running_time = MAX(position_running_time, stop_running_time);
904 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
905 GST_FORMAT_TIME, player->gapless.segment[idx].start);
906 position_running_time = MAX(0, position_running_time);
907 position = MAX(position, position_running_time);
911 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
912 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
913 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
915 player->gapless.start_time[stream_type] += position;
921 static GstPadProbeReturn
922 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
924 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
925 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
926 mmplayer_t *player = (mmplayer_t *)data;
927 GstCaps *caps = NULL;
928 GstStructure *str = NULL;
929 const gchar *name = NULL;
930 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
931 gboolean caps_ret = TRUE;
933 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
934 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
935 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
936 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
937 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
940 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
944 if (strstr(name, "audio")) {
945 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
946 } else if (strstr(name, "video")) {
947 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
949 /* text track is not supportable */
950 LOGE("invalid name %s", name);
954 switch (GST_EVENT_TYPE(event)) {
957 /* in case of gapless, drop eos event not to send it to sink */
958 if (player->gapless.reconfigure && !player->msg_posted) {
959 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
960 ret = GST_PAD_PROBE_DROP;
964 case GST_EVENT_STREAM_START:
966 __mmplayer_gst_selector_update_start_time(player, stream_type);
969 case GST_EVENT_FLUSH_STOP:
971 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
972 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
973 player->gapless.start_time[stream_type] = 0;
976 case GST_EVENT_SEGMENT:
981 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
982 gst_event_copy_segment(event, &segment);
984 if (segment.format != GST_FORMAT_TIME)
987 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
988 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
989 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
990 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
991 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
992 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
994 /* keep the all the segment ev to cover the seeking */
995 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
996 player->gapless.update_segment[stream_type] = TRUE;
998 if (!player->gapless.running)
1001 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1003 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1005 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1006 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1007 gst_event_unref(event);
1008 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1014 gdouble proportion = 0.0;
1015 GstClockTimeDiff diff = 0;
1016 GstClockTime timestamp = 0;
1017 gint64 running_time_diff = -1;
1018 GstQOSType type = 0;
1019 GstEvent *tmpev = NULL;
1021 running_time_diff = player->gapless.segment[stream_type].base;
1023 if (running_time_diff <= 0) /* don't need to adjust */
1026 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1027 gst_event_unref(event);
1029 if (timestamp < running_time_diff) {
1030 LOGW("QOS event from previous group");
1031 ret = GST_PAD_PROBE_DROP;
1036 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1037 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1038 stream_type, GST_TIME_ARGS(timestamp),
1039 GST_TIME_ARGS(running_time_diff),
1040 GST_TIME_ARGS(timestamp - running_time_diff));
1043 timestamp -= running_time_diff;
1045 /* That case is invalid for QoS events */
1046 if (diff < 0 && -diff > timestamp) {
1047 LOGW("QOS event from previous group");
1048 ret = GST_PAD_PROBE_DROP;
1052 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1053 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1063 gst_caps_unref(caps);
1067 /* create fakesink for audio or video path witout audiobin or videobin */
1069 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1071 GstElement *pipeline = NULL;
1072 GstElement *fakesink = NULL;
1073 GstPad *sinkpad = NULL;
1076 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1078 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1081 fakesink = gst_element_factory_make("fakesink", NULL);
1082 if (fakesink == NULL) {
1083 LOGE("failed to create fakesink");
1087 /* store it as it's sink element */
1088 __mmplayer_add_sink(player, fakesink);
1090 gst_bin_add(GST_BIN(pipeline), fakesink);
1093 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1095 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1097 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1098 LOGE("failed to link fakesink");
1099 gst_object_unref(GST_OBJECT(fakesink));
1103 if (strstr(name, "video")) {
1104 if (player->v_stream_caps) {
1105 gst_caps_unref(player->v_stream_caps);
1106 player->v_stream_caps = NULL;
1108 if (player->ini.set_dump_element_flag)
1109 __mmplayer_add_dump_buffer_probe(player, fakesink);
1112 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1113 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1117 gst_object_unref(GST_OBJECT(sinkpad));
1124 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1126 GstElement *pipeline = NULL;
1127 GstElement *selector = NULL;
1128 GstPad *srcpad = NULL;
1131 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1133 selector = gst_element_factory_make("input-selector", NULL);
1135 LOGE("failed to create input-selector");
1138 g_object_set(selector, "sync-streams", TRUE, NULL);
1140 player->pipeline->mainbin[elem_idx].id = elem_idx;
1141 player->pipeline->mainbin[elem_idx].gst = selector;
1143 /* player->selector[stream_type].active_pad_index = DEFAULT_TRACK; */
1145 srcpad = gst_element_get_static_pad(selector, "src");
1147 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1148 player->selector[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1149 __mmplayer_gst_selector_blocked, NULL, NULL);
1150 player->selector[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1151 __mmplayer_gst_selector_event_probe, player, NULL);
1153 gst_element_set_state(selector, GST_STATE_PAUSED);
1155 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1156 gst_bin_add(GST_BIN(pipeline), selector);
1158 gst_object_unref(GST_OBJECT(srcpad));
1165 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1167 mmplayer_t *player = (mmplayer_t *)data;
1168 GstElement *selector = NULL;
1169 GstCaps *caps = NULL;
1170 GstStructure *str = NULL;
1171 const gchar *name = NULL;
1172 GstPad *sinkpad = NULL;
1173 gboolean first_track = FALSE;
1174 gboolean caps_ret = TRUE;
1176 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1177 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1180 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1181 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1183 LOGD("pad-added signal handling");
1185 /* get mimetype from caps */
1186 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1190 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1192 LOGD("detected mimetype : %s", name);
1195 if (strstr(name, "video")) {
1197 gchar *caps_str = NULL;
1199 caps_str = gst_caps_to_string(caps);
1200 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1201 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1202 player->set_mode.video_zc = true;
1204 MMPLAYER_FREEIF(caps_str);
1206 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1207 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1209 LOGD("surface type : %d", stype);
1211 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1212 __mmplayer_gst_create_sinkbin(elem, pad, player);
1216 /* in case of exporting video frame, it requires the 360 video filter.
1217 * it will be handled in _no_more_pads(). */
1218 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1219 __mmplayer_gst_make_fakesink(player, pad, name);
1223 LOGD("video selector is required");
1224 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1225 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1226 } else if (strstr(name, "audio")) {
1227 gint samplerate = 0;
1230 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1231 if (player->build_audio_offload)
1232 player->no_more_pad = TRUE; /* remove state holder */
1233 __mmplayer_gst_create_sinkbin(elem, pad, player);
1237 gst_structure_get_int(str, "rate", &samplerate);
1238 gst_structure_get_int(str, "channels", &channels);
1240 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1241 __mmplayer_gst_make_fakesink(player, pad, name);
1245 LOGD("audio selector is required");
1246 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1247 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1249 } else if (strstr(name, "text")) {
1250 LOGD("text selector is required");
1251 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1252 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1254 LOGE("invalid caps info");
1258 /* check selector and create it */
1259 if (!(selector = player->pipeline->mainbin[elem_idx].gst)) {
1260 selector = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1265 LOGD("input-selector is already created.");
1269 sinkpad = gst_element_get_request_pad(selector, "sink_%u");
1271 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1273 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1274 LOGE("failed to link selector");
1275 gst_object_unref(GST_OBJECT(selector));
1280 LOGD("this track will be activated");
1281 g_object_set(selector, "active-pad", sinkpad, NULL);
1284 _mmplayer_track_update_selector_info(player, stream_type, sinkpad);
1290 gst_caps_unref(caps);
1293 gst_object_unref(GST_OBJECT(sinkpad));
1301 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *selector, mmplayer_track_type_e type)
1303 GstPad *srcpad = NULL;
1306 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1308 LOGD("type %d", type);
1311 LOGD("there is no %d track", type);
1315 srcpad = gst_element_get_static_pad(selector, "src");
1317 LOGE("failed to get srcpad from selector");
1321 LOGD("got pad %s:%s from selector", GST_DEBUG_PAD_NAME(srcpad));
1323 __mmplayer_gst_create_sinkbin(selector, srcpad, player);
1325 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1326 if (player->selector[type].block_id) {
1327 gst_pad_remove_probe(srcpad, player->selector[type].block_id);
1328 player->selector[type].block_id = 0;
1332 gst_object_unref(GST_OBJECT(srcpad));
1341 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1343 gint active_index = 0;
1346 MMPLAYER_RETURN_IF_FAIL(player);
1348 LOGD("type: %d, the num of track: %d", type, player->selector[type].total_track_num);
1350 /* change track to active pad */
1351 active_index = player->selector[type].active_pad_index;
1352 if ((active_index != DEFAULT_TRACK) &&
1353 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1354 LOGW("failed to change %d type track to %d", type, active_index);
1355 player->selector[type].active_pad_index = DEFAULT_TRACK;
1359 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1360 mm_player_set_attribute((MMHandleType)player, NULL,
1361 "content_text_track_num", player->selector[type].total_track_num,
1362 "current_text_track_index", player->selector[type].active_pad_index, NULL);
1369 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1372 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1374 if (!audio_selector) {
1375 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1377 /* in case the source is changed, output can be changed. */
1378 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1379 LOGD("remove previous audiobin if it exist");
1381 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1382 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1384 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1385 MMPLAYER_FREEIF(player->pipeline->audiobin);
1388 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1389 __mmplayer_pipeline_complete(NULL, player);
1394 /* apply the audio track information */
1395 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1397 /* create audio sink path */
1398 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO)) {
1399 LOGE("failed to create audio sink path");
1408 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1411 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1413 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1414 LOGD("text path is not supproted");
1418 /* apply the text track information */
1419 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1421 if (player->selector[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1422 player->has_closed_caption = TRUE;
1424 /* create text decode path */
1425 player->no_more_pad = TRUE;
1427 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT)) {
1428 LOGE("failed to create text sink path");
1437 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1439 gint64 dur_bytes = 0L;
1442 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1443 player->pipeline->mainbin && player->streamer, FALSE);
1445 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1446 LOGE("fail to get duration.");
1448 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1449 * use file information was already set on Q2 when it was created. */
1450 _mm_player_streaming_set_queue2(player->streamer,
1451 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1452 TRUE, /* use_buffering */
1453 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1454 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1461 __mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1463 mmplayer_t *player = NULL;
1464 GstElement *video_selector = NULL;
1465 GstElement *audio_selector = NULL;
1466 GstElement *text_selector = NULL;
1469 player = (mmplayer_t *)data;
1471 LOGD("no-more-pad signal handling");
1473 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1474 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1475 LOGW("player is shutting down");
1479 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1480 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1481 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1482 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1483 LOGE("failed to set queue2 buffering");
1488 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1489 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1490 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1492 if (!video_selector && !audio_selector && !text_selector) {
1493 LOGW("there is no selector");
1494 player->no_more_pad = TRUE;
1498 /* create video path followed by video-select */
1499 if (video_selector && !audio_selector && !text_selector)
1500 player->no_more_pad = TRUE;
1502 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO))
1505 /* create audio path followed by audio-select */
1506 if (audio_selector && !text_selector)
1507 player->no_more_pad = TRUE;
1509 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1512 /* create text path followed by text-select */
1513 __mmplayer_create_text_sink_path(player, text_selector);
1516 if (player->gapless.reconfigure) {
1517 player->gapless.reconfigure = FALSE;
1518 MMPLAYER_PLAYBACK_UNLOCK(player);
1525 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1527 gboolean ret = FALSE;
1528 GstElement *pipeline = NULL;
1529 GstPad *sinkpad = NULL;
1532 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1533 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1535 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1537 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1539 LOGE("failed to get pad from sinkbin");
1545 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1546 LOGE("failed to link sinkbin for reusing");
1547 goto EXIT; /* exit either pass or fail */
1551 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1552 LOGE("failed to set state(READY) to sinkbin");
1557 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1558 LOGE("failed to add sinkbin to pipeline");
1563 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1564 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1569 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1570 LOGE("failed to set state(PAUSED) to sinkbin");
1579 gst_object_unref(GST_OBJECT(sinkpad));
1587 __mmplayer_gst_create_sinkbin(GstElement *elem, GstPad *pad, gpointer data)
1589 mmplayer_t *player = NULL;
1590 GstCaps *caps = NULL;
1591 gchar *caps_str = NULL;
1592 GstStructure *str = NULL;
1593 const gchar *name = NULL;
1594 GstElement *sinkbin = NULL;
1595 gboolean reusing = FALSE;
1596 gboolean caps_ret = TRUE;
1597 gchar *sink_pad_name = "sink";
1600 player = (mmplayer_t *)data;
1603 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1604 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1606 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
1610 caps_str = gst_caps_to_string(caps);
1612 LOGD("detected mimetype : %s", name);
1614 if (strstr(name, "audio")) {
1615 if (player->pipeline->audiobin == NULL) {
1616 const gchar *audio_format = gst_structure_get_string(str, "format");
1618 LOGD("original audio format %s", audio_format);
1619 mm_player_set_attribute((MMHandleType)player, NULL,
1620 "content_audio_format", audio_format, strlen(audio_format), NULL);
1623 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1624 LOGE("failed to create audiobin. continuing without audio");
1628 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1629 LOGD("creating audiobin success");
1632 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1633 LOGD("reusing audiobin");
1634 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1636 } else if (strstr(name, "video")) {
1637 /* 1. zero copy is updated at _decode_pad_added()
1638 * 2. NULL surface type is handled in _decode_pad_added() */
1639 LOGD("zero copy %d", player->set_mode.video_zc);
1640 if (player->pipeline->videobin == NULL) {
1641 int surface_type = 0;
1642 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1643 LOGD("display_surface_type (%d)", surface_type);
1645 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1646 (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1647 LOGE("failed to acquire video overlay resource");
1651 player->interrupted_by_resource = FALSE;
1653 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1654 LOGE("failed to create videobin. continuing without video");
1658 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1659 LOGD("creating videosink bin success");
1662 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1663 LOGD("re-using videobin");
1664 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1666 } else if (strstr(name, "text")) {
1667 if (player->pipeline->textbin == NULL) {
1668 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1669 LOGE("failed to create text sink bin. continuing without text");
1673 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1674 player->textsink_linked = 1;
1675 LOGD("creating textsink bin success");
1677 if (!player->textsink_linked) {
1678 LOGD("re-using textbin");
1680 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1681 player->textsink_linked = 1;
1683 /* linked textbin exist which means that the external subtitle path exist already */
1684 LOGW("ignoring internal subtutle since external subtitle is available");
1687 sink_pad_name = "text_sink";
1689 LOGW("unknown mime type %s, ignoring it", name);
1693 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1696 LOGD("[handle: %p] success to create and link sink bin", player);
1698 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1699 * streaming task. if the task blocked, then buffer will not flow to the next element
1700 *(autoplugging element). so this is special hack for streaming. please try to remove it
1702 /* dec stream count. we can remove fakesink if it's zero */
1703 if (player->num_dynamic_pad)
1704 player->num_dynamic_pad--;
1706 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1708 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1709 __mmplayer_pipeline_complete(NULL, player);
1713 MMPLAYER_FREEIF(caps_str);
1716 gst_caps_unref(caps);
1722 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1724 int required_angle = 0; /* Angle required for straight view */
1725 int rotation_angle = 0;
1727 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1728 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1730 /* Counter clockwise */
1731 switch (orientation) {
1736 required_angle = 270;
1739 required_angle = 180;
1742 required_angle = 90;
1746 rotation_angle = display_angle + required_angle;
1747 if (rotation_angle >= 360)
1748 rotation_angle -= 360;
1750 /* chech if supported or not */
1751 if (rotation_angle % 90) {
1752 LOGD("not supported rotation angle = %d", rotation_angle);
1756 switch (rotation_angle) {
1758 *value = MM_DISPLAY_ROTATION_NONE;
1761 *value = MM_DISPLAY_ROTATION_90;
1764 *value = MM_DISPLAY_ROTATION_180;
1767 *value = MM_DISPLAY_ROTATION_270;
1771 LOGD("setting rotation property value : %d", *value);
1777 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1779 int display_rotation = 0;
1780 gchar *org_orient = NULL;
1781 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1784 LOGE("cannot get content attribute");
1785 return MM_ERROR_PLAYER_INTERNAL;
1788 if (display_angle) {
1789 /* update user roation */
1790 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1792 /* Counter clockwise */
1793 switch (display_rotation) {
1794 case MM_DISPLAY_ROTATION_NONE:
1797 case MM_DISPLAY_ROTATION_90:
1798 *display_angle = 90;
1800 case MM_DISPLAY_ROTATION_180:
1801 *display_angle = 180;
1803 case MM_DISPLAY_ROTATION_270:
1804 *display_angle = 270;
1807 LOGW("wrong angle type : %d", display_rotation);
1810 LOGD("check user angle: %d", *display_angle);
1814 /* Counter clockwise */
1815 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1818 if (!strcmp(org_orient, "rotate-90"))
1820 else if (!strcmp(org_orient, "rotate-180"))
1822 else if (!strcmp(org_orient, "rotate-270"))
1825 LOGD("original rotation is %s", org_orient);
1827 LOGD("content_video_orientation get fail");
1830 LOGD("check orientation: %d", *orientation);
1833 return MM_ERROR_NONE;
1836 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1838 int rotation_value = 0;
1839 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1840 int display_angle = 0;
1843 /* check video sinkbin is created */
1844 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1847 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1849 /* get rotation value to set */
1850 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1851 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1852 LOGD("set video param : rotate %d", rotation_value);
1855 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1857 MMHandleType attrs = 0;
1861 /* check video sinkbin is created */
1862 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1865 attrs = MMPLAYER_GET_ATTRS(player);
1866 MMPLAYER_RETURN_IF_FAIL(attrs);
1868 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1869 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1870 LOGD("set video param : visible %d", visible);
1873 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1875 MMHandleType attrs = 0;
1876 int display_method = 0;
1879 /* check video sinkbin is created */
1880 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1883 attrs = MMPLAYER_GET_ATTRS(player);
1884 MMPLAYER_RETURN_IF_FAIL(attrs);
1886 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1887 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1888 LOGD("set video param : method %d", display_method);
1891 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1893 MMHandleType attrs = 0;
1897 /* check video sinkbin is created */
1898 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1901 attrs = MMPLAYER_GET_ATTRS(player);
1902 MMPLAYER_RETURN_IF_FAIL(attrs);
1904 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1905 MMPLAYER_RETURN_IF_FAIL(handle);
1907 gst_video_overlay_set_video_roi_area(
1908 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1909 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1910 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1911 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1914 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
1916 MMHandleType attrs = 0;
1921 int win_roi_width = 0;
1922 int win_roi_height = 0;
1925 /* check video sinkbin is created */
1926 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1929 attrs = MMPLAYER_GET_ATTRS(player);
1930 MMPLAYER_RETURN_IF_FAIL(attrs);
1932 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1933 MMPLAYER_RETURN_IF_FAIL(handle);
1935 /* It should be set after setting window */
1936 mm_attrs_multiple_get(attrs, NULL,
1937 "display_win_roi_x", &win_roi_x,
1938 "display_win_roi_y", &win_roi_y,
1939 "display_win_roi_width", &win_roi_width,
1940 "display_win_roi_height", &win_roi_height, NULL);
1942 /* After setting window handle, set display roi area */
1943 gst_video_overlay_set_display_roi_area(
1944 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1945 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1946 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
1947 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
1950 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
1952 MMHandleType attrs = 0;
1955 /* check video sinkbin is created */
1956 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1959 attrs = MMPLAYER_GET_ATTRS(player);
1960 MMPLAYER_RETURN_IF_FAIL(attrs);
1962 /* common case if using overlay surface */
1963 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1964 MMPLAYER_RETURN_IF_FAIL(handle);
1966 /* default is using wl_surface_id */
1967 LOGD("set video param : wl_surface_id %d", handle);
1968 gst_video_overlay_set_wl_window_wl_surface_id(
1969 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1974 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
1976 gboolean update_all_param = FALSE;
1980 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
1981 LOGW("videosink is not ready yet");
1982 return MM_ERROR_PLAYER_NOT_INITIALIZED;
1985 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
1986 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
1987 return MM_ERROR_PLAYER_INTERNAL;
1990 LOGD("param_name : %s", param_name);
1991 if (!g_strcmp0(param_name, "update_all_param"))
1992 update_all_param = TRUE;
1994 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
1995 __mmplayer_video_param_set_display_overlay(player);
1996 if (update_all_param || !g_strcmp0(param_name, "display_method"))
1997 __mmplayer_video_param_set_display_method(player);
1998 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
1999 __mmplayer_video_param_set_display_visible(player);
2000 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2001 __mmplayer_video_param_set_display_rotation(player);
2002 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2003 __mmplayer_video_param_set_roi_area(player);
2004 if (update_all_param)
2005 __mmplayer_video_param_set_video_roi_area(player);
2009 return MM_ERROR_NONE;
2013 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2015 gboolean disable_overlay = FALSE;
2016 mmplayer_t *player = (mmplayer_t *)hplayer;
2019 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2020 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2021 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2022 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2024 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2025 LOGW("Display control is not supported");
2026 return MM_ERROR_PLAYER_INTERNAL;
2029 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2031 if (audio_only == (bool)disable_overlay) {
2032 LOGE("It's the same with current setting: (%d)", audio_only);
2033 return MM_ERROR_NONE;
2037 LOGE("disable overlay");
2038 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2040 /* release overlay resource */
2041 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2042 LOGE("failed to release overlay resource");
2046 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2047 LOGE("failed to acquire video overlay resource");
2050 player->interrupted_by_resource = FALSE;
2052 LOGD("enable overlay");
2053 __mmplayer_video_param_set_display_overlay(player);
2054 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2059 return MM_ERROR_NONE;
2063 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2065 mmplayer_t *player = (mmplayer_t *)hplayer;
2066 gboolean disable_overlay = FALSE;
2070 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2071 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2072 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2073 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2074 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2076 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2077 LOGW("Display control is not supported");
2078 return MM_ERROR_PLAYER_INTERNAL;
2081 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2083 *paudio_only = (bool)disable_overlay;
2085 LOGD("audio_only : %d", *paudio_only);
2089 return MM_ERROR_NONE;
2093 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2095 GList *bucket = element_bucket;
2096 mmplayer_gst_element_t *element = NULL;
2097 mmplayer_gst_element_t *prv_element = NULL;
2098 GstElement *tee_element = NULL;
2099 gint successful_link_count = 0;
2103 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2105 prv_element = (mmplayer_gst_element_t *)bucket->data;
2106 bucket = bucket->next;
2108 for (; bucket; bucket = bucket->next) {
2109 element = (mmplayer_gst_element_t *)bucket->data;
2111 if (element && element->gst) {
2112 if (prv_element && prv_element->gst) {
2113 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2115 prv_element->gst = tee_element;
2117 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2118 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2119 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2123 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2124 LOGD("linking [%s] to [%s] success",
2125 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2126 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2127 successful_link_count++;
2128 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2129 LOGD("keep audio-tee element for next audio pipeline branch");
2130 tee_element = prv_element->gst;
2133 LOGD("linking [%s] to [%s] failed",
2134 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2135 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2141 prv_element = element;
2146 return successful_link_count;
2150 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2152 GList *bucket = element_bucket;
2153 mmplayer_gst_element_t *element = NULL;
2154 int successful_add_count = 0;
2158 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2159 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2161 for (; bucket; bucket = bucket->next) {
2162 element = (mmplayer_gst_element_t *)bucket->data;
2164 if (element && element->gst) {
2165 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2166 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2167 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2168 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2171 successful_add_count++;
2177 return successful_add_count;
2181 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2183 mmplayer_t *player = (mmplayer_t *)data;
2184 GstCaps *caps = NULL;
2185 GstStructure *str = NULL;
2187 gboolean caps_ret = TRUE;
2191 MMPLAYER_RETURN_IF_FAIL(pad);
2192 MMPLAYER_RETURN_IF_FAIL(unused);
2193 MMPLAYER_RETURN_IF_FAIL(data);
2195 caps = gst_pad_get_current_caps(pad);
2199 MMPLAYER_GST_GET_CAPS_INFO(pad, caps, str, name, caps_ret);
2203 LOGD("name = %s", name);
2205 if (strstr(name, "audio")) {
2206 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2208 if (player->audio_stream_changed_cb) {
2209 LOGE("call the audio stream changed cb");
2210 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2212 } else if (strstr(name, "video")) {
2213 if ((name = gst_structure_get_string(str, "format")))
2214 player->set_mode.video_zc = name[0] == 'S';
2216 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2217 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2219 LOGW("invalid caps info");
2224 gst_caps_unref(caps);
2232 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2237 MMPLAYER_RETURN_IF_FAIL(player);
2239 if (player->audio_stream_buff_list) {
2240 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2241 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2244 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2245 __mmplayer_audio_stream_send_data(player, tmp);
2247 MMPLAYER_FREEIF(tmp->pcm_data);
2248 MMPLAYER_FREEIF(tmp);
2251 g_list_free(player->audio_stream_buff_list);
2252 player->audio_stream_buff_list = NULL;
2259 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2261 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2264 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2266 audio_stream.bitrate = a_buffer->bitrate;
2267 audio_stream.channel = a_buffer->channel;
2268 audio_stream.depth = a_buffer->depth;
2269 audio_stream.is_little_endian = a_buffer->is_little_endian;
2270 audio_stream.channel_mask = a_buffer->channel_mask;
2271 audio_stream.data_size = a_buffer->data_size;
2272 audio_stream.data = a_buffer->pcm_data;
2273 audio_stream.pcm_format = a_buffer->pcm_format;
2275 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2277 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2283 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2285 mmplayer_t *player = (mmplayer_t *)data;
2286 const gchar *pcm_format = NULL;
2290 gint endianness = 0;
2291 guint64 channel_mask = 0;
2292 void *a_data = NULL;
2294 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2295 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2299 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2301 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2302 a_data = mapinfo.data;
2303 a_size = mapinfo.size;
2305 GstCaps *caps = gst_pad_get_current_caps(pad);
2306 GstStructure *structure = gst_caps_get_structure(caps, 0);
2308 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2310 pcm_format = gst_structure_get_string(structure, "format");
2311 gst_structure_get_int(structure, "rate", &rate);
2312 gst_structure_get_int(structure, "channels", &channel);
2313 gst_structure_get_int(structure, "depth", &depth);
2314 gst_structure_get_int(structure, "endianness", &endianness);
2315 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2316 gst_caps_unref(GST_CAPS(caps));
2318 /* In case of the sync is false, use buffer list. *
2319 * The num of buffer list depends on the num of audio channels */
2320 if (player->audio_stream_buff_list) {
2321 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2322 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2324 if (channel_mask == tmp->channel_mask) {
2326 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2328 if (tmp->data_size + a_size < tmp->buff_size) {
2329 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2330 tmp->data_size += a_size;
2332 /* send data to client */
2333 __mmplayer_audio_stream_send_data(player, tmp);
2335 if (a_size > tmp->buff_size) {
2336 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2337 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2338 if (tmp->pcm_data == NULL) {
2339 LOGE("failed to realloc data.");
2342 tmp->buff_size = a_size;
2344 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2345 memcpy(tmp->pcm_data, a_data, a_size);
2346 tmp->data_size = a_size;
2351 LOGE("data is empty in list.");
2357 /* create new audio stream data for newly found audio channel */
2358 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2359 if (a_buffer == NULL) {
2360 LOGE("failed to alloc data.");
2363 a_buffer->bitrate = rate;
2364 a_buffer->channel = channel;
2365 a_buffer->depth = depth;
2366 a_buffer->is_little_endian = (endianness == 1234 ? true : false);
2367 a_buffer->channel_mask = channel_mask;
2368 a_buffer->data_size = a_size;
2369 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2371 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2372 /* If sync is FALSE, use buffer list to reduce the IPC. */
2373 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2374 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2375 if (a_buffer->pcm_data == NULL) {
2376 LOGE("failed to alloc data.");
2377 MMPLAYER_FREEIF(a_buffer);
2380 memcpy(a_buffer->pcm_data, a_data, a_size);
2382 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2384 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2386 /* If sync is TRUE, send data directly. */
2387 a_buffer->pcm_data = a_data;
2388 __mmplayer_audio_stream_send_data(player, a_buffer);
2389 MMPLAYER_FREEIF(a_buffer);
2393 gst_buffer_unmap(buffer, &mapinfo);
2398 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2400 mmplayer_t *player = (mmplayer_t *)data;
2401 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2402 GstPad *sinkpad = NULL;
2403 GstElement *queue = NULL, *sink = NULL;
2406 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2408 queue = gst_element_factory_make("queue", NULL);
2409 if (queue == NULL) {
2410 LOGD("fail make queue");
2414 sink = gst_element_factory_make("fakesink", NULL);
2416 LOGD("fail make fakesink");
2420 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2422 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2423 LOGW("failed to link queue & sink");
2427 sinkpad = gst_element_get_static_pad(queue, "sink");
2429 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2430 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2434 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2436 gst_object_unref(sinkpad);
2437 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2438 g_object_set(sink, "sync", TRUE, NULL);
2439 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2441 /* keep the first sink reference only */
2442 if (!audiobin[MMPLAYER_A_SINK].gst) {
2443 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2444 audiobin[MMPLAYER_A_SINK].gst = sink;
2448 _mmplayer_add_signal_connection(player,
2450 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2452 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2455 __mmplayer_add_sink(player, sink);
2457 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2458 LOGE("failed to sync state");
2462 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2463 LOGE("failed to sync state");
2471 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2473 gst_object_unref(GST_OBJECT(queue));
2477 gst_object_unref(GST_OBJECT(sink));
2481 gst_object_unref(GST_OBJECT(sinkpad));
2489 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2491 mmplayer_t *player = (mmplayer_t *)data;
2494 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2496 player->no_more_pad = TRUE;
2497 __mmplayer_pipeline_complete(NULL, player);
2504 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2506 #define MAX_PROPS_LEN 128
2507 mmplayer_gst_element_t *audiobin = NULL;
2508 gint latency_mode = 0;
2509 gchar *stream_type = NULL;
2510 gchar *latency = NULL;
2512 gchar stream_props[MAX_PROPS_LEN] = {0,};
2513 GstStructure *props = NULL;
2516 * It should be set after player creation through attribute.
2517 * But, it can not be changed during playing.
2520 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2522 audiobin = player->pipeline->audiobin;
2524 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2525 if (player->sound.mute) {
2526 LOGD("mute enabled");
2527 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2530 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2531 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2534 snprintf(stream_props, sizeof(stream_props) - 1,
2535 "props,application.process.id.origin=%d", player->client_pid);
2537 snprintf(stream_props, sizeof(stream_props) - 1,
2538 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2539 stream_type, stream_id, player->client_pid);
2541 props = gst_structure_from_string(stream_props, NULL);
2542 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2543 LOGI("props result[%s].", stream_props);
2544 gst_structure_free(props);
2546 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2548 switch (latency_mode) {
2549 case AUDIO_LATENCY_MODE_LOW:
2550 latency = g_strndup("low", 3);
2552 case AUDIO_LATENCY_MODE_MID:
2553 latency = g_strndup("mid", 3);
2555 case AUDIO_LATENCY_MODE_HIGH:
2556 latency = g_strndup("high", 4);
2560 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2562 LOGD("audiosink property - latency=%s", latency);
2564 MMPLAYER_FREEIF(latency);
2570 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2572 mmplayer_gst_element_t *audiobin = NULL;
2575 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2577 audiobin = player->pipeline->audiobin;
2579 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2580 sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info);
2581 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2583 if (player->video360_yaw_radians <= M_PI &&
2584 player->video360_yaw_radians >= -M_PI &&
2585 player->video360_pitch_radians <= M_PI_2 &&
2586 player->video360_pitch_radians >= -M_PI_2) {
2587 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2588 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2589 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2590 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2591 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2592 "source-orientation-y", player->video360_metadata.init_view_heading,
2593 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2600 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2602 mmplayer_gst_element_t *audiobin = NULL;
2603 GstPad *sink_pad = NULL;
2604 GstCaps *acaps = NULL;
2606 int pitch_control = 0;
2607 double pitch_value = 1.0;
2610 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2611 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2613 audiobin = player->pipeline->audiobin;
2615 LOGD("make element for normal audio playback");
2617 /* audio bin structure for playback. {} means optional.
2618 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2620 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2621 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2624 /* for pitch control */
2625 mm_attrs_multiple_get(player->attrs, NULL,
2626 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2627 MM_PLAYER_PITCH_VALUE, &pitch_value,
2630 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2631 if (pitch_control && (player->videodec_linked == 0)) {
2632 GstElementFactory *factory;
2634 factory = gst_element_factory_find("pitch");
2636 gst_object_unref(factory);
2639 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2642 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2643 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2645 LOGW("there is no pitch element");
2650 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2652 /* replaygain volume */
2653 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2654 if (player->sound.rg_enable)
2655 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2657 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2660 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2662 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2663 /* currently, only openalsink uses volume element */
2664 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2665 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2667 if (player->sound.mute) {
2668 LOGD("mute enabled");
2669 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2673 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2675 /* audio effect element. if audio effect is enabled */
2676 if ((strcmp(player->ini.audioeffect_element, ""))
2678 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2679 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2681 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2683 if ((!player->bypass_audio_effect)
2684 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2685 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2686 if (!_mmplayer_audio_effect_custom_apply(player))
2687 LOGI("apply audio effect(custom) setting success");
2691 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2692 && (player->set_mode.rich_audio)) {
2693 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2697 /* create audio sink */
2698 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2699 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2700 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2702 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2703 if (player->is_360_feature_enabled &&
2704 player->is_content_spherical &&
2706 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2707 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2708 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2710 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2712 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2714 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2715 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2716 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2717 gst_caps_unref(acaps);
2719 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2721 player->is_openal_plugin_used = TRUE;
2723 if (player->is_360_feature_enabled && player->is_content_spherical)
2724 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2725 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2728 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2729 (player->videodec_linked && player->ini.use_system_clock)) {
2730 LOGD("system clock will be used.");
2731 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2734 if (g_strrstr(player->ini.audiosink_element, "pulsesink"))
2735 __mmplayer_gst_set_pulsesink_property(player);
2736 else if (g_strrstr(player->ini.audiosink_element, "openalsink"))
2737 __mmplayer_gst_set_openalsink_property(player);
2740 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2741 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2743 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2744 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2745 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2746 gst_object_unref(GST_OBJECT(sink_pad));
2748 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2751 return MM_ERROR_NONE;
2753 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2755 return MM_ERROR_PLAYER_INTERNAL;
2759 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2761 mmplayer_gst_element_t *audiobin = NULL;
2762 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2764 gchar *dst_format = NULL;
2766 int dst_samplerate = 0;
2767 int dst_channels = 0;
2768 GstCaps *caps = NULL;
2769 char *caps_str = NULL;
2772 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2773 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2775 audiobin = player->pipeline->audiobin;
2777 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2779 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2781 [case 1] extract interleave audio pcm without playback
2782 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2783 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2785 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2787 [case 2] deinterleave for each channel without playback
2788 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2789 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2791 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2792 - fakesink (sync or not)
2795 [case 3] [case 1(sync only)] + playback
2796 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2798 * src - ... - tee - queue1 - playback path
2799 - queue2 - [case1 pipeline with sync]
2801 [case 4] [case 2(sync only)] + playback
2802 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2804 * src - ... - tee - queue1 - playback path
2805 - queue2 - [case2 pipeline with sync]
2809 /* 1. create tee and playback path
2810 'tee' should be added at first to copy the decoded stream
2812 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2813 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2814 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2816 /* tee - path 1 : for playback path */
2817 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2818 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2820 /* tee - path 2 : for extract path */
2821 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2822 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2825 /* if there is tee, 'tee - path 2' is linked here */
2827 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2830 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2832 /* 2. decide the extract pcm format */
2833 mm_attrs_multiple_get(player->attrs, NULL,
2834 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2835 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2836 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2839 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2840 dst_format, dst_len, dst_samplerate, dst_channels);
2842 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2843 mm_attrs_multiple_get(player->attrs, NULL,
2844 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2845 "content_audio_samplerate", &dst_samplerate,
2846 "content_audio_channels", &dst_channels,
2849 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2850 dst_format, dst_len, dst_samplerate, dst_channels);
2852 /* If there is no enough information, set it to platform default value. */
2853 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2854 LOGD("set platform default format");
2855 dst_format = DEFAULT_PCM_OUT_FORMAT;
2857 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2858 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2861 /* 3. create capsfilter */
2862 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2863 caps = gst_caps_new_simple("audio/x-raw",
2864 "format", G_TYPE_STRING, dst_format,
2865 "rate", G_TYPE_INT, dst_samplerate,
2866 "channels", G_TYPE_INT, dst_channels,
2869 caps_str = gst_caps_to_string(caps);
2870 LOGD("new caps : %s", caps_str);
2872 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2875 gst_caps_unref(caps);
2876 MMPLAYER_FREEIF(caps_str);
2878 /* 4-1. create deinterleave to extract pcm for each channel */
2879 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2880 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2881 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2883 /* audiosink will be added after getting signal for each channel */
2884 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2885 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2886 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2887 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2888 player->no_more_pad = FALSE;
2890 /* 4-2. create fakesink to extract interlevaed pcm */
2891 LOGD("add audio fakesink for interleaved audio");
2892 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2893 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2894 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2895 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2897 _mmplayer_add_signal_connection(player,
2898 G_OBJECT(audiobin[extract_sink_id].gst),
2899 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2901 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2904 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst);
2908 return MM_ERROR_NONE;
2910 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2912 return MM_ERROR_PLAYER_INTERNAL;
2916 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
2918 int ret = MM_ERROR_NONE;
2919 mmplayer_gst_element_t *audiobin = NULL;
2920 GList *element_bucket = NULL;
2923 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2924 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2926 audiobin = player->pipeline->audiobin;
2928 if (player->build_audio_offload) { /* skip all the audio filters */
2929 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
2931 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
2932 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
2933 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
2935 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst);
2939 /* FIXME: need to mention the supportable condition at API reference */
2940 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
2941 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
2943 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
2945 if (ret != MM_ERROR_NONE)
2948 LOGD("success to make audio bin element");
2949 *bucket = element_bucket;
2952 return MM_ERROR_NONE;
2955 LOGE("failed to make audio bin element");
2956 g_list_free(element_bucket);
2960 return MM_ERROR_PLAYER_INTERNAL;
2964 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
2966 mmplayer_gst_element_t *first_element = NULL;
2967 mmplayer_gst_element_t *audiobin = NULL;
2969 GstPad *ghostpad = NULL;
2970 GList *element_bucket = NULL;
2974 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2977 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
2979 LOGE("failed to allocate memory for audiobin");
2980 return MM_ERROR_PLAYER_NO_FREE_SPACE;
2984 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
2985 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
2986 if (!audiobin[MMPLAYER_A_BIN].gst) {
2987 LOGE("failed to create audiobin");
2992 player->pipeline->audiobin = audiobin;
2994 /* create audio filters and audiosink */
2995 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
2998 /* adding created elements to bin */
2999 LOGD("adding created elements to bin");
3000 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3003 /* linking elements in the bucket by added order. */
3004 LOGD("Linking elements in the bucket by added order.");
3005 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3008 /* get first element's sinkpad for creating ghostpad */
3009 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3010 if (!first_element) {
3011 LOGE("failed to get first elem");
3015 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3017 LOGE("failed to get pad from first element of audiobin");
3021 ghostpad = gst_ghost_pad_new("sink", pad);
3023 LOGE("failed to create ghostpad");
3027 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3028 LOGE("failed to add ghostpad to audiobin");
3032 gst_object_unref(pad);
3034 g_list_free(element_bucket);
3037 return MM_ERROR_NONE;
3040 LOGD("ERROR : releasing audiobin");
3043 gst_object_unref(GST_OBJECT(pad));
3046 gst_object_unref(GST_OBJECT(ghostpad));
3049 g_list_free(element_bucket);
3051 /* release element which are not added to bin */
3052 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3053 /* NOTE : skip bin */
3054 if (audiobin[i].gst) {
3055 GstObject *parent = NULL;
3056 parent = gst_element_get_parent(audiobin[i].gst);
3059 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3060 audiobin[i].gst = NULL;
3062 gst_object_unref(GST_OBJECT(parent));
3066 /* release audiobin with it's childs */
3067 if (audiobin[MMPLAYER_A_BIN].gst)
3068 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3070 MMPLAYER_FREEIF(audiobin);
3072 player->pipeline->audiobin = NULL;
3074 return MM_ERROR_PLAYER_INTERNAL;
3078 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3080 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3084 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3086 int ret = MM_ERROR_NONE;
3088 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3089 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3091 MMPLAYER_VIDEO_BO_LOCK(player);
3093 if (player->video_bo_list) {
3094 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3095 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3096 if (tmp && tmp->bo == bo) {
3098 LOGD("release bo %p", bo);
3099 tbm_bo_unref(tmp->bo);
3100 MMPLAYER_VIDEO_BO_UNLOCK(player);
3101 MMPLAYER_VIDEO_BO_SIGNAL(player);
3106 /* hw codec is running or the list was reset for DRC. */
3107 LOGW("there is no bo list.");
3109 MMPLAYER_VIDEO_BO_UNLOCK(player);
3111 LOGW("failed to find bo %p", bo);
3116 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3121 MMPLAYER_RETURN_IF_FAIL(player);
3123 MMPLAYER_VIDEO_BO_LOCK(player);
3124 if (player->video_bo_list) {
3125 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3126 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3127 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3130 tbm_bo_unref(tmp->bo);
3134 g_list_free(player->video_bo_list);
3135 player->video_bo_list = NULL;
3137 player->video_bo_size = 0;
3138 MMPLAYER_VIDEO_BO_UNLOCK(player);
3145 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3148 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3149 gboolean ret = TRUE;
3151 /* check DRC, if it is, destroy the prev bo list to create again */
3152 if (player->video_bo_size != size) {
3153 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3154 __mmplayer_video_stream_destroy_bo_list(player);
3155 player->video_bo_size = size;
3158 MMPLAYER_VIDEO_BO_LOCK(player);
3160 if ((!player->video_bo_list) ||
3161 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3163 /* create bo list */
3165 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3167 if (player->video_bo_list) {
3168 /* if bo list did not created all, try it again. */
3169 idx = g_list_length(player->video_bo_list);
3170 LOGD("bo list exist(len: %d)", idx);
3173 for (; idx < player->ini.num_of_video_bo; idx++) {
3174 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3176 LOGE("Fail to alloc bo_info.");
3179 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3181 LOGE("Fail to tbm_bo_alloc.");
3182 MMPLAYER_FREEIF(bo_info);
3185 bo_info->used = FALSE;
3186 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3189 /* update video num buffers */
3190 LOGD("video_num_buffers : %d", idx);
3191 mm_player_set_attribute((MMHandleType)player, NULL,
3192 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3193 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3197 MMPLAYER_VIDEO_BO_UNLOCK(player);
3203 /* get bo from list*/
3204 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3205 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3206 if (tmp && (tmp->used == FALSE)) {
3207 LOGD("found bo %p to use", tmp->bo);
3209 MMPLAYER_VIDEO_BO_UNLOCK(player);
3210 return tbm_bo_ref(tmp->bo);
3214 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3215 MMPLAYER_VIDEO_BO_UNLOCK(player);
3219 if (player->ini.video_bo_timeout <= 0) {
3220 MMPLAYER_VIDEO_BO_WAIT(player);
3222 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3223 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3230 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3232 mmplayer_t *player = (mmplayer_t *)data;
3234 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3236 /* send prerolled pkt */
3237 player->video_stream_prerolled = false;
3239 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3241 /* not to send prerolled pkt again */
3242 player->video_stream_prerolled = true;
3246 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3248 mmplayer_t *player = (mmplayer_t *)data;
3249 mmplayer_video_decoded_data_info_t *stream = NULL;
3250 GstMemory *mem = NULL;
3253 MMPLAYER_RETURN_IF_FAIL(player);
3254 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3256 if (player->video_stream_prerolled) {
3257 player->video_stream_prerolled = false;
3258 LOGD("skip the prerolled pkt not to send it again");
3262 /* clear stream data structure */
3263 stream = __mmplayer_create_stream_from_pad(pad);
3265 LOGE("failed to alloc stream");
3269 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3271 /* set size and timestamp */
3272 mem = gst_buffer_peek_memory(buffer, 0);
3273 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3274 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3276 /* check zero-copy */
3277 if (player->set_mode.video_zc &&
3278 player->set_mode.video_export &&
3279 gst_is_tizen_memory(mem)) {
3280 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3281 stream->internal_buffer = gst_buffer_ref(buffer);
3282 } else { /* sw codec */
3283 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3286 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3290 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3291 LOGE("failed to send video decoded data.");
3298 LOGE("release video stream resource.");
3299 if (gst_is_tizen_memory(mem)) {
3301 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3303 tbm_bo_unref(stream->bo[i]);
3306 /* unref gst buffer */
3307 if (stream->internal_buffer)
3308 gst_buffer_unref(stream->internal_buffer);
3311 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3313 MMPLAYER_FREEIF(stream);
3318 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3320 mmplayer_gst_element_t *videobin = NULL;
3323 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3325 videobin = player->pipeline->videobin;
3327 /* Set spatial media metadata and/or user settings to the element.
3329 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3330 "projection-type", player->video360_metadata.projection_type, NULL);
3332 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3333 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3335 if (player->video360_metadata.full_pano_width_pixels &&
3336 player->video360_metadata.full_pano_height_pixels &&
3337 player->video360_metadata.cropped_area_image_width &&
3338 player->video360_metadata.cropped_area_image_height) {
3339 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3340 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3341 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3342 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3343 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3344 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3345 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3349 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3350 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3351 "horizontal-fov", player->video360_horizontal_fov,
3352 "vertical-fov", player->video360_vertical_fov, NULL);
3355 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3356 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3357 "zoom", 1.0f / player->video360_zoom, NULL);
3360 if (player->video360_yaw_radians <= M_PI &&
3361 player->video360_yaw_radians >= -M_PI &&
3362 player->video360_pitch_radians <= M_PI_2 &&
3363 player->video360_pitch_radians >= -M_PI_2) {
3364 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3365 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3366 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3367 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3368 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3369 "pose-yaw", player->video360_metadata.init_view_heading,
3370 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3373 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3374 "passthrough", !player->is_video360_enabled, NULL);
3381 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3383 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3384 GList *element_bucket = NULL;
3387 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3389 /* create video360 filter */
3390 if (player->is_360_feature_enabled && player->is_content_spherical) {
3391 LOGD("create video360 element");
3392 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3393 __mmplayer_gst_set_video360_property(player);
3397 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3398 LOGD("skip creating the videoconv and rotator");
3399 return MM_ERROR_NONE;
3402 /* in case of sw codec & overlay surface type, except 360 playback.
3403 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3404 LOGD("create video converter: %s", video_csc);
3405 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3408 *bucket = element_bucket;
3410 return MM_ERROR_NONE;
3412 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3413 g_list_free(element_bucket);
3417 return MM_ERROR_PLAYER_INTERNAL;
3421 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3423 gchar *factory_name = NULL;
3425 switch (surface_type) {
3426 case MM_DISPLAY_SURFACE_OVERLAY:
3427 if (strlen(player->ini.videosink_element_overlay) > 0)
3428 factory_name = player->ini.videosink_element_overlay;
3430 case MM_DISPLAY_SURFACE_REMOTE:
3431 case MM_DISPLAY_SURFACE_NULL:
3432 if (strlen(player->ini.videosink_element_fake) > 0)
3433 factory_name = player->ini.videosink_element_fake;
3436 LOGE("unidentified surface type");
3440 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3441 return factory_name;
3445 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3447 gchar *factory_name = NULL;
3448 mmplayer_gst_element_t *videobin = NULL;
3453 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3455 videobin = player->pipeline->videobin;
3456 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3458 attrs = MMPLAYER_GET_ATTRS(player);
3460 LOGE("cannot get content attribute");
3461 return MM_ERROR_PLAYER_INTERNAL;
3464 LOGD("surface type %d, videosink factory name is %s", surface_type, factory_name);
3465 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3466 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3468 /* support shard memory with S/W codec on HawkP */
3469 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3470 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3471 "use-tbm", use_tbm, NULL);
3475 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3476 return MM_ERROR_PLAYER_INTERNAL;
3478 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3479 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3482 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3484 LOGD("disable last-sample");
3485 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3488 if (player->set_mode.video_export) {
3490 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3491 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3492 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3494 _mmplayer_add_signal_connection(player,
3495 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3496 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3498 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3501 _mmplayer_add_signal_connection(player,
3502 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3503 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3505 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3509 if (videobin[MMPLAYER_V_SINK].gst) {
3510 GstPad *sink_pad = NULL;
3511 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3513 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3514 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3515 gst_object_unref(GST_OBJECT(sink_pad));
3517 LOGE("failed to get sink pad from videosink");
3521 return MM_ERROR_NONE;
3526 * - video overlay surface(arm/x86) : tizenwlsink
3529 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3532 GList *element_bucket = NULL;
3533 mmplayer_gst_element_t *first_element = NULL;
3534 mmplayer_gst_element_t *videobin = NULL;
3535 gchar *videosink_factory_name = NULL;
3538 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3541 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3543 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3545 player->pipeline->videobin = videobin;
3548 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3549 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3550 if (!videobin[MMPLAYER_V_BIN].gst) {
3551 LOGE("failed to create videobin");
3555 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3558 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3559 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3561 /* additional setting for sink plug-in */
3562 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3563 LOGE("failed to set video property");
3567 /* store it as it's sink element */
3568 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst);
3570 /* adding created elements to bin */
3571 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3572 LOGE("failed to add elements");
3576 /* Linking elements in the bucket by added order */
3577 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3578 LOGE("failed to link elements");
3582 /* get first element's sinkpad for creating ghostpad */
3583 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3584 if (!first_element) {
3585 LOGE("failed to get first element from bucket");
3589 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3591 LOGE("failed to get pad from first element");
3595 /* create ghostpad */
3596 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3597 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3598 LOGE("failed to add ghostpad to videobin");
3601 gst_object_unref(pad);
3603 /* done. free allocated variables */
3604 g_list_free(element_bucket);
3608 return MM_ERROR_NONE;
3611 LOGE("ERROR : releasing videobin");
3612 g_list_free(element_bucket);
3615 gst_object_unref(GST_OBJECT(pad));
3617 /* release videobin with it's childs */
3618 if (videobin[MMPLAYER_V_BIN].gst)
3619 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3621 MMPLAYER_FREEIF(videobin);
3622 player->pipeline->videobin = NULL;
3624 return MM_ERROR_PLAYER_INTERNAL;
3628 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3630 GList *element_bucket = NULL;
3631 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3633 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3634 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3635 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3636 "signal-handoffs", FALSE,
3639 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3640 _mmplayer_add_signal_connection(player,
3641 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3642 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3644 G_CALLBACK(__mmplayer_update_subtitle),
3647 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3648 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3650 if (!player->play_subtitle) {
3651 LOGD("add textbin sink as sink element of whole pipeline.");
3652 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst));
3655 /* adding created elements to bin */
3656 LOGD("adding created elements to bin");
3657 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3658 LOGE("failed to add elements");
3662 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3663 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3664 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3666 /* linking elements in the bucket by added order. */
3667 LOGD("Linking elements in the bucket by added order.");
3668 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3669 LOGE("failed to link elements");
3673 /* done. free allocated variables */
3674 g_list_free(element_bucket);
3676 if (textbin[MMPLAYER_T_QUEUE].gst) {
3678 GstPad *ghostpad = NULL;
3680 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3682 LOGE("failed to get sink pad of text queue");
3686 ghostpad = gst_ghost_pad_new("text_sink", pad);
3687 gst_object_unref(pad);
3690 LOGE("failed to create ghostpad of textbin");
3694 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3695 LOGE("failed to add ghostpad to textbin");
3696 gst_object_unref(ghostpad);
3701 return MM_ERROR_NONE;
3704 g_list_free(element_bucket);
3706 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3707 LOGE("remove textbin sink from sink list");
3708 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3711 /* release element at __mmplayer_gst_create_text_sink_bin */
3712 return MM_ERROR_PLAYER_INTERNAL;
3716 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3718 mmplayer_gst_element_t *textbin = NULL;
3719 GList *element_bucket = NULL;
3720 int surface_type = 0;
3725 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3728 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3730 LOGE("failed to allocate memory for textbin");
3731 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3735 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3736 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3737 if (!textbin[MMPLAYER_T_BIN].gst) {
3738 LOGE("failed to create textbin");
3743 player->pipeline->textbin = textbin;
3746 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3747 LOGD("surface type for subtitle : %d", surface_type);
3748 switch (surface_type) {
3749 case MM_DISPLAY_SURFACE_OVERLAY:
3750 case MM_DISPLAY_SURFACE_NULL:
3751 case MM_DISPLAY_SURFACE_REMOTE:
3752 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3753 LOGE("failed to make plain text elements");
3764 return MM_ERROR_NONE;
3768 LOGD("ERROR : releasing textbin");
3770 g_list_free(element_bucket);
3772 /* release signal */
3773 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3775 /* release element which are not added to bin */
3776 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3777 /* NOTE : skip bin */
3778 if (textbin[i].gst) {
3779 GstObject *parent = NULL;
3780 parent = gst_element_get_parent(textbin[i].gst);
3783 gst_object_unref(GST_OBJECT(textbin[i].gst));
3784 textbin[i].gst = NULL;
3786 gst_object_unref(GST_OBJECT(parent));
3791 /* release textbin with it's childs */
3792 if (textbin[MMPLAYER_T_BIN].gst)
3793 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3795 MMPLAYER_FREEIF(player->pipeline->textbin);
3796 player->pipeline->textbin = NULL;
3799 return MM_ERROR_PLAYER_INTERNAL;
3803 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3805 mmplayer_gst_element_t *mainbin = NULL;
3806 mmplayer_gst_element_t *textbin = NULL;
3807 MMHandleType attrs = 0;
3808 GstElement *subsrc = NULL;
3809 GstElement *subparse = NULL;
3810 gchar *subtitle_uri = NULL;
3811 const gchar *charset = NULL;
3817 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3819 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3821 mainbin = player->pipeline->mainbin;
3823 attrs = MMPLAYER_GET_ATTRS(player);
3825 LOGE("cannot get content attribute");
3826 return MM_ERROR_PLAYER_INTERNAL;
3829 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3830 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3831 LOGE("subtitle uri is not proper filepath.");
3832 return MM_ERROR_PLAYER_INVALID_URI;
3835 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3836 LOGE("failed to get storage info of subtitle path");
3837 return MM_ERROR_PLAYER_INVALID_URI;
3840 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3842 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3843 player->subtitle_language_list = NULL;
3844 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3846 /* create the subtitle source */
3847 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3849 LOGE("failed to create filesrc element");
3852 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3854 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3855 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3857 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3858 LOGW("failed to add queue");
3859 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3860 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3861 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3866 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3868 LOGE("failed to create subparse element");
3872 charset = _mmplayer_get_charset(subtitle_uri);
3874 LOGD("detected charset is %s", charset);
3875 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3878 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3879 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3881 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3882 LOGW("failed to add subparse");
3883 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3884 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3885 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3889 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3890 LOGW("failed to link subsrc and subparse");
3894 player->play_subtitle = TRUE;
3895 player->adjust_subtitle_pos = 0;
3897 LOGD("play subtitle using subtitle file");
3899 if (player->pipeline->textbin == NULL) {
3900 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3901 LOGE("failed to create text sink bin. continuing without text");
3905 textbin = player->pipeline->textbin;
3907 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3908 LOGW("failed to add textbin");
3910 /* release signal */
3911 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3913 /* release textbin with it's childs */
3914 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3915 MMPLAYER_FREEIF(player->pipeline->textbin);
3916 player->pipeline->textbin = textbin = NULL;
3920 LOGD("link text input selector and textbin ghost pad");
3922 player->textsink_linked = 1;
3923 player->external_text_idx = 0;
3924 LOGI("textsink is linked");
3926 textbin = player->pipeline->textbin;
3927 LOGD("text bin has been created. reuse it.");
3928 player->external_text_idx = 1;
3931 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
3932 LOGW("failed to link subparse and textbin");
3936 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
3938 LOGE("failed to get sink pad from textsink to probe data");
3942 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
3943 __mmplayer_subtitle_adjust_position_probe, player, NULL);
3945 gst_object_unref(pad);
3948 /* create dot. for debugging */
3949 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
3952 return MM_ERROR_NONE;
3955 /* release text pipeline resource */
3956 player->textsink_linked = 0;
3958 /* release signal */
3959 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3961 if (player->pipeline->textbin) {
3962 LOGE("remove textbin");
3964 /* release textbin with it's childs */
3965 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
3966 MMPLAYER_FREEIF(player->pipeline->textbin);
3967 player->pipeline->textbin = NULL;
3971 /* release subtitle elem */
3972 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
3973 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
3975 return MM_ERROR_PLAYER_INTERNAL;
3979 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3981 mmplayer_t *player = (mmplayer_t *)data;
3982 MMMessageParamType msg = {0, };
3983 GstClockTime duration = 0;
3984 gpointer text = NULL;
3985 guint text_size = 0;
3986 gboolean ret = TRUE;
3987 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
3991 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
3992 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
3994 if (player->is_subtitle_force_drop) {
3995 LOGW("subtitle is dropped forcedly.");
3999 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4000 text = mapinfo.data;
4001 text_size = mapinfo.size;
4003 if (player->set_mode.subtitle_off) {
4004 LOGD("subtitle is OFF.");
4008 if (!text || (text_size == 0)) {
4009 LOGD("There is no subtitle to be displayed.");
4013 msg.data = (void *)text;
4015 duration = GST_BUFFER_DURATION(buffer);
4017 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4018 if (player->duration > GST_BUFFER_PTS(buffer))
4019 duration = player->duration - GST_BUFFER_PTS(buffer);
4022 LOGI("subtitle duration is invalid, subtitle duration change "
4023 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4025 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4027 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4029 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4030 gst_buffer_unmap(buffer, &mapinfo);
4037 static GstPadProbeReturn
4038 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4040 mmplayer_t *player = (mmplayer_t *)u_data;
4041 GstClockTime cur_timestamp = 0;
4042 gint64 adjusted_timestamp = 0;
4043 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4045 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4047 if (player->set_mode.subtitle_off) {
4048 LOGD("subtitle is OFF.");
4052 if (player->adjust_subtitle_pos == 0) {
4053 LOGD("nothing to do");
4057 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4058 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4060 if (adjusted_timestamp < 0) {
4061 LOGD("adjusted_timestamp under zero");
4066 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4067 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4068 GST_TIME_ARGS(cur_timestamp),
4069 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4071 return GST_PAD_PROBE_OK;
4075 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4079 /* check player and subtitlebin are created */
4080 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4081 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4083 if (position == 0) {
4084 LOGD("nothing to do");
4086 return MM_ERROR_NONE;
4089 /* check current postion */
4090 player->adjust_subtitle_pos = position;
4092 LOGD("save adjust_subtitle_pos in player");
4096 return MM_ERROR_NONE;
4100 * This function is to create audio or video pipeline for playing.
4102 * @param player [in] handle of player
4104 * @return This function returns zero on success.
4109 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4111 int ret = MM_ERROR_NONE;
4112 mmplayer_gst_element_t *mainbin = NULL;
4113 MMHandleType attrs = 0;
4116 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4118 /* get profile attribute */
4119 attrs = MMPLAYER_GET_ATTRS(player);
4121 LOGE("failed to get content attribute");
4125 /* create pipeline handles */
4126 if (player->pipeline) {
4127 LOGE("pipeline should be released before create new one");
4131 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4132 if (player->pipeline == NULL)
4135 /* create mainbin */
4136 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4137 if (mainbin == NULL)
4140 /* create pipeline */
4141 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4142 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4143 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4144 LOGE("failed to create pipeline");
4149 player->pipeline->mainbin = mainbin;
4151 /* create the source and decoder elements */
4152 if (MMPLAYER_IS_MS_BUFF_SRC(player))
4153 ret = _mmplayer_gst_build_es_pipeline(player);
4155 ret = _mmplayer_gst_build_pipeline(player);
4157 if (ret != MM_ERROR_NONE) {
4158 LOGE("failed to create some elements");
4162 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4163 if (__mmplayer_check_subtitle(player)
4164 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4165 LOGE("failed to create text pipeline");
4168 ret = _mmplayer_gst_add_bus_watch(player);
4169 if (ret != MM_ERROR_NONE) {
4170 LOGE("failed to add bus watch");
4175 return MM_ERROR_NONE;
4178 __mmplayer_gst_destroy_pipeline(player);
4179 return MM_ERROR_PLAYER_INTERNAL;
4183 __mmplayer_reset_gapless_state(mmplayer_t *player)
4186 MMPLAYER_RETURN_IF_FAIL(player
4188 && player->pipeline->audiobin
4189 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4191 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4198 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4201 int ret = MM_ERROR_NONE;
4205 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4207 /* cleanup stuffs */
4208 MMPLAYER_FREEIF(player->type);
4209 player->no_more_pad = FALSE;
4210 player->num_dynamic_pad = 0;
4211 player->demux_pad_index = 0;
4213 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4214 player->subtitle_language_list = NULL;
4215 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4217 __mmplayer_reset_gapless_state(player);
4219 if (player->streamer) {
4220 _mm_player_streaming_initialize(player->streamer, FALSE);
4221 _mm_player_streaming_destroy(player->streamer);
4222 player->streamer = NULL;
4225 /* cleanup unlinked mime type */
4226 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4227 MMPLAYER_FREEIF(player->unlinked_video_mime);
4228 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4230 /* cleanup running stuffs */
4231 _mmplayer_cancel_eos_timer(player);
4233 /* cleanup gst stuffs */
4234 if (player->pipeline) {
4235 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4236 GstTagList *tag_list = player->pipeline->tag_list;
4238 /* first we need to disconnect all signal hander */
4239 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4242 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4243 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4244 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4245 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4246 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4247 gst_object_unref(bus);
4249 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4250 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4251 if (ret != MM_ERROR_NONE) {
4252 LOGE("fail to change state to NULL");
4253 return MM_ERROR_PLAYER_INTERNAL;
4256 LOGW("succeeded in changing state to NULL");
4258 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4261 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4262 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4264 /* free avsysaudiosink
4265 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4266 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4268 MMPLAYER_FREEIF(audiobin);
4269 MMPLAYER_FREEIF(videobin);
4270 MMPLAYER_FREEIF(textbin);
4271 MMPLAYER_FREEIF(mainbin);
4275 gst_tag_list_unref(tag_list);
4277 MMPLAYER_FREEIF(player->pipeline);
4279 MMPLAYER_FREEIF(player->album_art);
4281 if (player->v_stream_caps) {
4282 gst_caps_unref(player->v_stream_caps);
4283 player->v_stream_caps = NULL;
4286 if (player->a_stream_caps) {
4287 gst_caps_unref(player->a_stream_caps);
4288 player->a_stream_caps = NULL;
4291 if (player->s_stream_caps) {
4292 gst_caps_unref(player->s_stream_caps);
4293 player->s_stream_caps = NULL;
4295 _mmplayer_track_destroy(player);
4297 if (player->sink_elements)
4298 g_list_free(player->sink_elements);
4299 player->sink_elements = NULL;
4301 if (player->bufmgr) {
4302 tbm_bufmgr_deinit(player->bufmgr);
4303 player->bufmgr = NULL;
4306 LOGW("finished destroy pipeline");
4314 __mmplayer_gst_realize(mmplayer_t *player)
4317 int ret = MM_ERROR_NONE;
4321 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4323 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4325 ret = __mmplayer_gst_create_pipeline(player);
4327 LOGE("failed to create pipeline");
4331 /* set pipeline state to READY */
4332 /* NOTE : state change to READY must be performed sync. */
4333 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4334 ret = _mmplayer_gst_set_state(player,
4335 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4337 if (ret != MM_ERROR_NONE) {
4338 /* return error if failed to set state */
4339 LOGE("failed to set READY state");
4343 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4345 /* create dot before error-return. for debugging */
4346 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4354 __mmplayer_gst_unrealize(mmplayer_t *player)
4356 int ret = MM_ERROR_NONE;
4360 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4362 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4363 MMPLAYER_PRINT_STATE(player);
4365 /* release miscellaneous information */
4366 __mmplayer_release_misc(player);
4368 /* destroy pipeline */
4369 ret = __mmplayer_gst_destroy_pipeline(player);
4370 if (ret != MM_ERROR_NONE) {
4371 LOGE("failed to destory pipeline");
4375 /* release miscellaneous information.
4376 these info needs to be released after pipeline is destroyed. */
4377 __mmplayer_release_misc_post(player);
4379 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4387 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4392 LOGW("set_message_callback is called with invalid player handle");
4393 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4396 player->msg_cb = callback;
4397 player->msg_cb_param = user_param;
4399 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4403 return MM_ERROR_NONE;
4407 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4409 int ret = MM_ERROR_NONE;
4414 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4415 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4416 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4418 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4420 if (strstr(uri, "es_buff://")) {
4421 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4422 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4423 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4424 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4426 tmp = g_ascii_strdown(uri, strlen(uri));
4427 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4428 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4430 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4432 } else if (strstr(uri, "mms://")) {
4433 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4434 } else if ((path = strstr(uri, "mem://"))) {
4435 ret = __mmplayer_set_mem_uri(data, path, param);
4437 ret = __mmplayer_set_file_uri(data, uri);
4440 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4441 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4442 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4443 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4445 /* dump parse result */
4446 SECURE_LOGW("incoming uri : %s", uri);
4447 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4448 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4456 __mmplayer_can_do_interrupt(mmplayer_t *player)
4458 if (!player || !player->pipeline || !player->attrs) {
4459 LOGW("not initialized");
4463 if (player->audio_decoded_cb) {
4464 LOGW("not support in pcm extraction mode");
4468 /* check if seeking */
4469 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4470 MMMessageParamType msg_param;
4471 memset(&msg_param, 0, sizeof(MMMessageParamType));
4472 msg_param.code = MM_ERROR_PLAYER_SEEK;
4473 player->seek_state = MMPLAYER_SEEK_NONE;
4474 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4478 /* check other thread */
4479 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4480 LOGW("locked already, cmd state : %d", player->cmd);
4482 /* check application command */
4483 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4484 LOGW("playing.. should wait cmd lock then, will be interrupted");
4486 /* lock will be released at mrp_resource_release_cb() */
4487 MMPLAYER_CMD_LOCK(player);
4490 LOGW("nothing to do");
4493 LOGW("can interrupt immediately");
4497 FAILED: /* with CMD UNLOCKED */
4500 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4505 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4508 mmplayer_t *player = NULL;
4509 MMMessageParamType msg = {0, };
4511 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4516 LOGE("user_data is null");
4519 player = (mmplayer_t *)user_data;
4521 if (!__mmplayer_can_do_interrupt(player)) {
4522 LOGW("no need to interrupt, so leave");
4523 /* FIXME: there is no way to avoid releasing resource. */
4527 player->interrupted_by_resource = TRUE;
4529 /* get last play position */
4530 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4531 msg.union_type = MM_MSG_UNION_TIME;
4532 msg.time.elapsed = pos;
4533 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4535 LOGW("failed to get play position.");
4538 LOGD("video resource conflict so, resource will be freed by unrealizing");
4539 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4540 LOGE("failed to unrealize");
4542 /* lock is called in __mmplayer_can_do_interrupt() */
4543 MMPLAYER_CMD_UNLOCK(player);
4545 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4546 player->hw_resource[res_idx] = NULL;
4550 return TRUE; /* release all the resources */
4554 __mmplayer_initialize_video_roi(mmplayer_t *player)
4556 player->video_roi.scale_x = 0.0;
4557 player->video_roi.scale_y = 0.0;
4558 player->video_roi.scale_width = 1.0;
4559 player->video_roi.scale_height = 1.0;
4563 _mmplayer_create_player(MMHandleType handle)
4565 int ret = MM_ERROR_PLAYER_INTERNAL;
4566 bool enabled = false;
4568 mmplayer_t *player = MM_PLAYER_CAST(handle);
4572 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4574 /* initialize player state */
4575 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4576 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4577 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4578 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4580 /* check current state */
4581 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4583 /* construct attributes */
4584 player->attrs = _mmplayer_construct_attribute(handle);
4586 if (!player->attrs) {
4587 LOGE("Failed to construct attributes");
4591 /* initialize gstreamer with configured parameter */
4592 if (!__mmplayer_init_gstreamer(player)) {
4593 LOGE("Initializing gstreamer failed");
4594 _mmplayer_deconstruct_attribute(handle);
4598 /* create lock. note that g_tread_init() has already called in gst_init() */
4599 g_mutex_init(&player->fsink_lock);
4601 /* create update tag lock */
4602 g_mutex_init(&player->update_tag_lock);
4604 /* create gapless play mutex */
4605 g_mutex_init(&player->gapless_play_thread_mutex);
4607 /* create gapless play cond */
4608 g_cond_init(&player->gapless_play_thread_cond);
4610 /* create gapless play thread */
4611 player->gapless_play_thread =
4612 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4613 if (!player->gapless_play_thread) {
4614 LOGE("failed to create gapless play thread");
4615 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4616 g_mutex_clear(&player->gapless_play_thread_mutex);
4617 g_cond_clear(&player->gapless_play_thread_cond);
4621 player->bus_msg_q = g_queue_new();
4622 if (!player->bus_msg_q) {
4623 LOGE("failed to create queue for bus_msg");
4624 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4628 ret = _mmplayer_initialize_video_capture(player);
4629 if (ret != MM_ERROR_NONE) {
4630 LOGE("failed to initialize video capture");
4634 /* initialize resource manager */
4635 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4636 __resource_release_cb, player, &player->resource_manager)
4637 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4638 LOGE("failed to initialize resource manager");
4639 ret = MM_ERROR_PLAYER_INTERNAL;
4643 /* create video bo lock and cond */
4644 g_mutex_init(&player->video_bo_mutex);
4645 g_cond_init(&player->video_bo_cond);
4647 /* create subtitle info lock and cond */
4648 g_mutex_init(&player->subtitle_info_mutex);
4649 g_cond_init(&player->subtitle_info_cond);
4651 player->streaming_type = STREAMING_SERVICE_NONE;
4653 /* give default value of audio effect setting */
4654 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4655 player->sound.rg_enable = false;
4656 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4658 player->play_subtitle = FALSE;
4659 player->has_closed_caption = FALSE;
4660 player->pending_resume = FALSE;
4661 if (player->ini.dump_element_keyword[0][0] == '\0')
4662 player->ini.set_dump_element_flag = FALSE;
4664 player->ini.set_dump_element_flag = TRUE;
4666 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4667 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4668 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4670 /* Set video360 settings to their defaults for just-created player.
4673 player->is_360_feature_enabled = FALSE;
4674 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4675 LOGI("spherical feature info: %d", enabled);
4677 player->is_360_feature_enabled = TRUE;
4679 LOGE("failed to get spherical feature info");
4682 player->is_content_spherical = FALSE;
4683 player->is_video360_enabled = TRUE;
4684 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4685 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4686 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4687 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4688 player->video360_zoom = 1.0f;
4689 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4690 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4692 __mmplayer_initialize_video_roi(player);
4694 /* set player state to null */
4695 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4696 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4700 return MM_ERROR_NONE;
4704 g_mutex_clear(&player->fsink_lock);
4705 /* free update tag lock */
4706 g_mutex_clear(&player->update_tag_lock);
4707 g_queue_free(player->bus_msg_q);
4708 player->bus_msg_q = NULL;
4709 /* free gapless play thread */
4710 if (player->gapless_play_thread) {
4711 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4712 player->gapless_play_thread_exit = TRUE;
4713 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4714 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4716 g_thread_join(player->gapless_play_thread);
4717 player->gapless_play_thread = NULL;
4719 g_mutex_clear(&player->gapless_play_thread_mutex);
4720 g_cond_clear(&player->gapless_play_thread_cond);
4723 /* release attributes */
4724 _mmplayer_deconstruct_attribute(handle);
4732 __mmplayer_init_gstreamer(mmplayer_t *player)
4734 static gboolean initialized = FALSE;
4735 static const int max_argc = 50;
4737 gchar **argv = NULL;
4738 gchar **argv2 = NULL;
4744 LOGD("gstreamer already initialized.");
4749 argc = malloc(sizeof(int));
4750 argv = malloc(sizeof(gchar *) * max_argc);
4751 argv2 = malloc(sizeof(gchar *) * max_argc);
4753 if (!argc || !argv || !argv2)
4756 memset(argv, 0, sizeof(gchar *) * max_argc);
4757 memset(argv2, 0, sizeof(gchar *) * max_argc);
4761 argv[0] = g_strdup("mmplayer");
4764 for (i = 0; i < 5; i++) {
4765 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4766 if (strlen(player->ini.gst_param[i]) > 0) {
4767 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4772 /* we would not do fork for scanning plugins */
4773 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4776 /* check disable registry scan */
4777 if (player->ini.skip_rescan) {
4778 argv[*argc] = g_strdup("--gst-disable-registry-update");
4782 /* check disable segtrap */
4783 if (player->ini.disable_segtrap) {
4784 argv[*argc] = g_strdup("--gst-disable-segtrap");
4788 LOGD("initializing gstreamer with following parameter");
4789 LOGD("argc : %d", *argc);
4792 for (i = 0; i < arg_count; i++) {
4794 LOGD("argv[%d] : %s", i, argv2[i]);
4797 /* initializing gstreamer */
4798 if (!gst_init_check(argc, &argv, &err)) {
4799 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4806 for (i = 0; i < arg_count; i++) {
4808 LOGD("release - argv[%d] : %s", i, argv2[i]);
4810 MMPLAYER_FREEIF(argv2[i]);
4813 MMPLAYER_FREEIF(argv);
4814 MMPLAYER_FREEIF(argv2);
4815 MMPLAYER_FREEIF(argc);
4825 for (i = 0; i < arg_count; i++) {
4826 LOGD("free[%d] : %s", i, argv2[i]);
4827 MMPLAYER_FREEIF(argv2[i]);
4830 MMPLAYER_FREEIF(argv);
4831 MMPLAYER_FREEIF(argv2);
4832 MMPLAYER_FREEIF(argc);
4838 __mmplayer_check_async_state_transition(mmplayer_t *player)
4840 GstState element_state = GST_STATE_VOID_PENDING;
4841 GstState element_pending_state = GST_STATE_VOID_PENDING;
4842 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4843 GstElement *element = NULL;
4844 gboolean async = FALSE;
4846 /* check player handle */
4847 MMPLAYER_RETURN_IF_FAIL(player &&
4849 player->pipeline->mainbin &&
4850 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4853 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4855 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4856 LOGD("don't need to check the pipeline state");
4860 MMPLAYER_PRINT_STATE(player);
4862 /* wait for state transition */
4863 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4864 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4866 if (ret == GST_STATE_CHANGE_FAILURE) {
4867 LOGE(" [%s] state : %s pending : %s",
4868 GST_ELEMENT_NAME(element),
4869 gst_element_state_get_name(element_state),
4870 gst_element_state_get_name(element_pending_state));
4872 /* dump state of all element */
4873 _mmplayer_dump_pipeline_state(player);
4878 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4883 _mmplayer_destroy(MMHandleType handle)
4885 mmplayer_t *player = MM_PLAYER_CAST(handle);
4889 /* check player handle */
4890 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4892 /* destroy can called at anytime */
4893 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4895 /* check async state transition */
4896 __mmplayer_check_async_state_transition(player);
4898 /* release gapless play thread */
4899 if (player->gapless_play_thread) {
4900 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4901 player->gapless_play_thread_exit = TRUE;
4902 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4903 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4905 LOGD("waitting for gapless play thread exit");
4906 g_thread_join(player->gapless_play_thread);
4907 g_mutex_clear(&player->gapless_play_thread_mutex);
4908 g_cond_clear(&player->gapless_play_thread_cond);
4909 LOGD("gapless play thread released");
4912 _mmplayer_release_video_capture(player);
4914 /* de-initialize resource manager */
4915 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
4916 player->resource_manager))
4917 LOGE("failed to deinitialize resource manager");
4919 /* release pipeline */
4920 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
4921 LOGE("failed to destory pipeline");
4922 return MM_ERROR_PLAYER_INTERNAL;
4925 g_queue_free(player->bus_msg_q);
4927 /* release subtitle info lock and cond */
4928 g_mutex_clear(&player->subtitle_info_mutex);
4929 g_cond_clear(&player->subtitle_info_cond);
4931 __mmplayer_release_dump_list(player->dump_list);
4933 /* release miscellaneous information */
4934 __mmplayer_release_misc(player);
4936 /* release miscellaneous information.
4937 these info needs to be released after pipeline is destroyed. */
4938 __mmplayer_release_misc_post(player);
4940 /* release attributes */
4941 _mmplayer_deconstruct_attribute(handle);
4944 g_mutex_clear(&player->fsink_lock);
4947 g_mutex_clear(&player->update_tag_lock);
4949 /* release video bo lock and cond */
4950 g_mutex_clear(&player->video_bo_mutex);
4951 g_cond_clear(&player->video_bo_cond);
4955 return MM_ERROR_NONE;
4959 _mmplayer_realize(MMHandleType hplayer)
4961 mmplayer_t *player = (mmplayer_t *)hplayer;
4964 MMHandleType attrs = 0;
4965 int ret = MM_ERROR_NONE;
4969 /* check player handle */
4970 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4972 /* check current state */
4973 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
4975 attrs = MMPLAYER_GET_ATTRS(player);
4977 LOGE("fail to get attributes.");
4978 return MM_ERROR_PLAYER_INTERNAL;
4980 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
4981 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
4983 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
4984 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
4986 if (ret != MM_ERROR_NONE) {
4987 LOGE("failed to parse profile");
4992 if (uri && (strstr(uri, "es_buff://"))) {
4993 if (strstr(uri, "es_buff://push_mode"))
4994 player->es_player_push_mode = TRUE;
4996 player->es_player_push_mode = FALSE;
4999 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5000 LOGW("mms protocol is not supported format.");
5001 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5004 if (MMPLAYER_IS_STREAMING(player))
5005 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5007 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5009 player->smooth_streaming = FALSE;
5010 player->videodec_linked = 0;
5011 player->audiodec_linked = 0;
5012 player->textsink_linked = 0;
5013 player->is_external_subtitle_present = FALSE;
5014 player->is_external_subtitle_added_now = FALSE;
5015 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5016 player->video360_metadata.is_spherical = -1;
5017 player->is_openal_plugin_used = FALSE;
5018 player->demux_pad_index = 0;
5019 player->subtitle_language_list = NULL;
5020 player->is_subtitle_force_drop = FALSE;
5022 _mmplayer_track_initialize(player);
5023 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5025 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5026 gint prebuffer_ms = 0, rebuffer_ms = 0;
5028 player->streamer = _mm_player_streaming_create();
5029 _mm_player_streaming_initialize(player->streamer, TRUE);
5031 mm_attrs_multiple_get(player->attrs, NULL,
5032 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5033 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5035 if (prebuffer_ms > 0) {
5036 prebuffer_ms = MAX(prebuffer_ms, 1000);
5037 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5040 if (rebuffer_ms > 0) {
5041 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5042 rebuffer_ms = MAX(rebuffer_ms, 1000);
5043 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5046 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5047 player->streamer->buffering_req.rebuffer_time);
5050 /* realize pipeline */
5051 ret = __mmplayer_gst_realize(player);
5052 if (ret != MM_ERROR_NONE)
5053 LOGE("fail to realize the player.");
5055 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5063 _mmplayer_unrealize(MMHandleType hplayer)
5065 mmplayer_t *player = (mmplayer_t *)hplayer;
5066 int ret = MM_ERROR_NONE;
5070 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5072 MMPLAYER_CMD_UNLOCK(player);
5073 /* destroy the gst bus msg thread which is created during realize.
5074 this funct have to be called before getting cmd lock. */
5075 _mmplayer_bus_msg_thread_destroy(player);
5076 MMPLAYER_CMD_LOCK(player);
5078 /* check current state */
5079 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5081 /* check async state transition */
5082 __mmplayer_check_async_state_transition(player);
5084 /* unrealize pipeline */
5085 ret = __mmplayer_gst_unrealize(player);
5087 if (!player->interrupted_by_resource) {
5088 int rm_ret = MM_ERROR_NONE;
5089 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5091 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5092 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5093 if (rm_ret != MM_ERROR_NONE)
5094 LOGE("failed to release [%d] resources", res_idx);
5103 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5105 mmplayer_t *player = (mmplayer_t *)hplayer;
5107 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5109 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5113 _mmplayer_get_state(MMHandleType hplayer, int *state)
5115 mmplayer_t *player = (mmplayer_t *)hplayer;
5117 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5119 *state = MMPLAYER_CURRENT_STATE(player);
5121 return MM_ERROR_NONE;
5125 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5127 GstElement *vol_element = NULL;
5128 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5131 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5132 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5134 /* check pipeline handle */
5135 if (!player->pipeline || !player->pipeline->audiobin) {
5136 LOGD("'%s' will be applied when audiobin is created", prop_name);
5138 /* NOTE : stored value will be used in create_audiobin
5139 * returning MM_ERROR_NONE here makes application to able to
5140 * set audio volume or mute at anytime.
5142 return MM_ERROR_NONE;
5145 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5146 volume_elem_id = MMPLAYER_A_SINK;
5148 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5150 LOGE("failed to get vol element %d", volume_elem_id);
5151 return MM_ERROR_PLAYER_INTERNAL;
5154 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5156 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5157 LOGE("there is no '%s' property", prop_name);
5158 return MM_ERROR_PLAYER_INTERNAL;
5161 if (!strcmp(prop_name, "volume")) {
5162 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5163 } else if (!strcmp(prop_name, "mute")) {
5164 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5166 LOGE("invalid property %s", prop_name);
5167 return MM_ERROR_PLAYER_INTERNAL;
5170 return MM_ERROR_NONE;
5174 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5176 int ret = MM_ERROR_NONE;
5177 mmplayer_t *player = (mmplayer_t *)hplayer;
5180 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5182 LOGD("volume = %f", volume);
5184 /* invalid factor range or not */
5185 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5186 LOGE("Invalid volume value");
5187 return MM_ERROR_INVALID_ARGUMENT;
5190 player->sound.volume = volume;
5192 ret = __mmplayer_gst_set_volume_property(player, "volume");
5199 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5201 mmplayer_t *player = (mmplayer_t *)hplayer;
5205 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5206 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5208 *volume = player->sound.volume;
5210 LOGD("current vol = %f", *volume);
5213 return MM_ERROR_NONE;
5217 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5219 int ret = MM_ERROR_NONE;
5220 mmplayer_t *player = (mmplayer_t *)hplayer;
5223 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5225 LOGD("mute = %d", mute);
5227 player->sound.mute = mute;
5229 ret = __mmplayer_gst_set_volume_property(player, "mute");
5236 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5238 mmplayer_t *player = (mmplayer_t *)hplayer;
5242 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5243 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5245 *mute = player->sound.mute;
5247 LOGD("current mute = %d", *mute);
5251 return MM_ERROR_NONE;
5255 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5257 mmplayer_t *player = (mmplayer_t *)hplayer;
5261 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5263 player->audio_stream_changed_cb = callback;
5264 player->audio_stream_changed_cb_user_param = user_param;
5265 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5269 return MM_ERROR_NONE;
5273 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5275 mmplayer_t *player = (mmplayer_t *)hplayer;
5279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5281 player->audio_decoded_cb = callback;
5282 player->audio_decoded_cb_user_param = user_param;
5283 player->audio_extract_opt = opt;
5284 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5288 return MM_ERROR_NONE;
5292 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5294 mmplayer_t *player = (mmplayer_t *)hplayer;
5298 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5300 if (callback && !player->bufmgr)
5301 player->bufmgr = tbm_bufmgr_init(-1);
5303 player->set_mode.video_export = (callback) ? true : false;
5304 player->video_decoded_cb = callback;
5305 player->video_decoded_cb_user_param = user_param;
5307 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5311 return MM_ERROR_NONE;
5315 _mmplayer_start(MMHandleType hplayer)
5317 mmplayer_t *player = (mmplayer_t *)hplayer;
5318 gint ret = MM_ERROR_NONE;
5322 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5324 /* check current state */
5325 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5327 /* start pipeline */
5328 ret = _mmplayer_gst_start(player);
5329 if (ret != MM_ERROR_NONE)
5330 LOGE("failed to start player.");
5332 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5333 LOGD("force playing start even during buffering");
5334 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5342 /* NOTE: post "not supported codec message" to application
5343 * when one codec is not found during AUTOPLUGGING in MSL.
5344 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5345 * And, if any codec is not found, don't send message here.
5346 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5349 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5351 MMMessageParamType msg_param;
5352 memset(&msg_param, 0, sizeof(MMMessageParamType));
5353 gboolean post_msg_direct = FALSE;
5357 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5359 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5360 player->not_supported_codec, player->can_support_codec);
5362 if (player->not_found_demuxer) {
5363 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5364 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5366 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5367 MMPLAYER_FREEIF(msg_param.data);
5369 return MM_ERROR_NONE;
5372 if (player->not_supported_codec) {
5373 if (player->can_support_codec) {
5374 // There is one codec to play
5375 post_msg_direct = TRUE;
5377 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5378 post_msg_direct = TRUE;
5381 if (post_msg_direct) {
5382 MMMessageParamType msg_param;
5383 memset(&msg_param, 0, sizeof(MMMessageParamType));
5385 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5386 LOGW("not found AUDIO codec, posting error code to application.");
5388 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5389 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5390 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5391 LOGW("not found VIDEO codec, posting error code to application.");
5393 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5394 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5397 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5399 MMPLAYER_FREEIF(msg_param.data);
5401 return MM_ERROR_NONE;
5403 // no any supported codec case
5404 LOGW("not found any codec, posting error code to application.");
5406 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5407 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5408 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5410 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5411 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5414 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5416 MMPLAYER_FREEIF(msg_param.data);
5422 return MM_ERROR_NONE;
5426 __mmplayer_check_pipeline(mmplayer_t *player)
5428 GstState element_state = GST_STATE_VOID_PENDING;
5429 GstState element_pending_state = GST_STATE_VOID_PENDING;
5431 int ret = MM_ERROR_NONE;
5433 if (!player->gapless.reconfigure)
5436 LOGW("pipeline is under construction.");
5438 MMPLAYER_PLAYBACK_LOCK(player);
5439 MMPLAYER_PLAYBACK_UNLOCK(player);
5441 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5443 /* wait for state transition */
5444 ret = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, &element_state, &element_pending_state, timeout * GST_SECOND);
5445 if (ret == GST_STATE_CHANGE_FAILURE)
5446 LOGE("failed to change pipeline state within %d sec", timeout);
5449 /* NOTE : it should be able to call 'stop' anytime*/
5451 _mmplayer_stop(MMHandleType hplayer)
5453 mmplayer_t *player = (mmplayer_t *)hplayer;
5454 int ret = MM_ERROR_NONE;
5458 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5460 /* check current state */
5461 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5463 /* check pipline building state */
5464 __mmplayer_check_pipeline(player);
5465 __mmplayer_reset_gapless_state(player);
5467 /* NOTE : application should not wait for EOS after calling STOP */
5468 _mmplayer_cancel_eos_timer(player);
5471 player->seek_state = MMPLAYER_SEEK_NONE;
5474 ret = _mmplayer_gst_stop(player);
5476 if (ret != MM_ERROR_NONE)
5477 LOGE("failed to stop player.");
5485 _mmplayer_pause(MMHandleType hplayer)
5487 mmplayer_t *player = (mmplayer_t *)hplayer;
5488 gint64 pos_nsec = 0;
5489 gboolean async = FALSE;
5490 gint ret = MM_ERROR_NONE;
5494 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5496 /* check current state */
5497 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5499 /* check pipline building state */
5500 __mmplayer_check_pipeline(player);
5502 switch (MMPLAYER_CURRENT_STATE(player)) {
5503 case MM_PLAYER_STATE_READY:
5505 /* check prepare async or not.
5506 * In the case of streaming playback, it's recommned to avoid blocking wait.
5508 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5509 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5511 /* Changing back sync of rtspsrc to async */
5512 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5513 LOGD("async prepare working mode for rtsp");
5519 case MM_PLAYER_STATE_PLAYING:
5521 /* NOTE : store current point to overcome some bad operation
5522 *(returning zero when getting current position in paused state) of some
5525 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5526 LOGW("getting current position failed in paused");
5528 player->last_position = pos_nsec;
5530 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5531 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5532 This causes problem is position calculation during normal pause resume scenarios also.
5533 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5534 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5535 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5536 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5542 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5543 LOGD("doing async pause in case of ms buff src");
5547 /* pause pipeline */
5548 ret = _mmplayer_gst_pause(player, async);
5550 if (ret != MM_ERROR_NONE)
5551 LOGE("failed to pause player. ret : 0x%x", ret);
5553 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5554 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5555 LOGE("failed to update display_rotation");
5563 /* in case of streaming, pause could take long time.*/
5565 _mmplayer_abort_pause(MMHandleType hplayer)
5567 mmplayer_t *player = (mmplayer_t *)hplayer;
5568 int ret = MM_ERROR_NONE;
5572 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5574 player->pipeline->mainbin,
5575 MM_ERROR_PLAYER_NOT_INITIALIZED);
5577 LOGD("set the pipeline state to READY");
5579 /* set state to READY */
5580 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5581 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5582 if (ret != MM_ERROR_NONE) {
5583 LOGE("fail to change state to READY");
5584 return MM_ERROR_PLAYER_INTERNAL;
5587 LOGD("succeeded in changing state to READY");
5592 _mmplayer_resume(MMHandleType hplayer)
5594 mmplayer_t *player = (mmplayer_t *)hplayer;
5595 int ret = MM_ERROR_NONE;
5596 gboolean async = FALSE;
5600 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5602 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5603 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5604 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5608 /* Changing back sync mode rtspsrc to async */
5609 LOGD("async resume for rtsp case");
5613 /* check current state */
5614 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5616 ret = _mmplayer_gst_resume(player, async);
5617 if (ret != MM_ERROR_NONE)
5618 LOGE("failed to resume player.");
5620 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5621 LOGD("force resume even during buffering");
5622 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5631 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5633 mmplayer_t *player = (mmplayer_t *)hplayer;
5634 gint64 pos_nsec = 0;
5635 int ret = MM_ERROR_NONE;
5637 signed long long start = 0, stop = 0;
5638 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5641 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5642 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5644 /* The sound of video is not supported under 0.0 and over 2.0. */
5645 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5646 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5649 _mmplayer_set_mute(hplayer, mute);
5651 if (player->playback_rate == rate)
5652 return MM_ERROR_NONE;
5654 /* If the position is reached at start potion during fast backward, EOS is posted.
5655 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5657 player->playback_rate = rate;
5659 current_state = MMPLAYER_CURRENT_STATE(player);
5661 if (current_state != MM_PLAYER_STATE_PAUSED)
5662 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5664 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5666 if ((current_state == MM_PLAYER_STATE_PAUSED)
5667 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5668 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5669 pos_nsec = player->last_position;
5674 stop = GST_CLOCK_TIME_NONE;
5676 start = GST_CLOCK_TIME_NONE;
5680 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5681 player->playback_rate,
5683 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5684 GST_SEEK_TYPE_SET, start,
5685 GST_SEEK_TYPE_SET, stop)) {
5686 LOGE("failed to set speed playback");
5687 return MM_ERROR_PLAYER_SEEK;
5690 LOGD("succeeded to set speed playback as %0.1f", rate);
5694 return MM_ERROR_NONE;;
5698 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5700 mmplayer_t *player = (mmplayer_t *)hplayer;
5701 int ret = MM_ERROR_NONE;
5705 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5707 /* check pipline building state */
5708 __mmplayer_check_pipeline(player);
5710 ret = _mmplayer_gst_set_position(player, position, FALSE);
5718 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5720 mmplayer_t *player = (mmplayer_t *)hplayer;
5721 int ret = MM_ERROR_NONE;
5723 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5724 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5726 if (g_strrstr(player->type, "video/mpegts"))
5727 __mmplayer_update_duration_value(player);
5729 *duration = player->duration;
5734 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5736 mmplayer_t *player = (mmplayer_t *)hplayer;
5737 int ret = MM_ERROR_NONE;
5739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5741 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5747 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5749 mmplayer_t *player = (mmplayer_t *)hplayer;
5750 int ret = MM_ERROR_NONE;
5754 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5756 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5764 __mmplayer_is_midi_type(gchar *str_caps)
5766 if ((g_strrstr(str_caps, "audio/midi")) ||
5767 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5768 (g_strrstr(str_caps, "application/x-smaf")) ||
5769 (g_strrstr(str_caps, "audio/x-imelody")) ||
5770 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5771 (g_strrstr(str_caps, "audio/xmf")) ||
5772 (g_strrstr(str_caps, "audio/mxmf"))) {
5781 __mmplayer_is_only_mp3_type(gchar *str_caps)
5783 if (g_strrstr(str_caps, "application/x-id3") ||
5784 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5790 __mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5792 GstStructure *caps_structure = NULL;
5793 gint samplerate = 0;
5797 MMPLAYER_RETURN_IF_FAIL(player && caps);
5799 caps_structure = gst_caps_get_structure(caps, 0);
5801 /* set stream information */
5802 gst_structure_get_int(caps_structure, "rate", &samplerate);
5803 gst_structure_get_int(caps_structure, "channels", &channels);
5805 mm_player_set_attribute((MMHandleType)player, NULL,
5806 "content_audio_samplerate", samplerate,
5807 "content_audio_channels", channels, NULL);
5809 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5813 __mmplayer_update_content_type_info(mmplayer_t *player)
5816 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5818 if (__mmplayer_is_midi_type(player->type)) {
5819 player->bypass_audio_effect = TRUE;
5823 if (!player->streamer) {
5824 LOGD("no need to check streaming type");
5828 if (g_strrstr(player->type, "application/x-hls")) {
5829 /* If it can't know exact type when it parses uri because of redirection case,
5830 * it will be fixed by typefinder or when doing autoplugging.
5832 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5833 player->streamer->is_adaptive_streaming = TRUE;
5834 } else if (g_strrstr(player->type, "application/dash+xml")) {
5835 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5836 player->streamer->is_adaptive_streaming = TRUE;
5839 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5840 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5841 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5843 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5844 if (player->streamer->is_adaptive_streaming)
5845 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5847 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5851 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5856 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5857 GstCaps *caps, gpointer data)
5859 mmplayer_t *player = (mmplayer_t *)data;
5864 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5866 /* store type string */
5867 MMPLAYER_FREEIF(player->type);
5868 player->type = gst_caps_to_string(caps);
5870 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5871 player, player->type, probability, gst_caps_get_size(caps));
5873 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5874 (g_strrstr(player->type, "audio/x-raw-int"))) {
5875 LOGE("not support media format");
5877 if (player->msg_posted == FALSE) {
5878 MMMessageParamType msg_param;
5879 memset(&msg_param, 0, sizeof(MMMessageParamType));
5881 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5882 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5884 /* don't post more if one was sent already */
5885 player->msg_posted = TRUE;
5890 __mmplayer_update_content_type_info(player);
5892 pad = gst_element_get_static_pad(tf, "src");
5894 LOGE("fail to get typefind src pad.");
5898 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5899 gboolean async = FALSE;
5900 LOGE("failed to autoplug %s", player->type);
5902 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5904 if (async && player->msg_posted == FALSE)
5905 __mmplayer_handle_missed_plugin(player);
5909 gst_object_unref(GST_OBJECT(pad));
5917 _mmplayer_gst_make_decodebin(mmplayer_t *player)
5919 GstElement *decodebin = NULL;
5923 /* create decodebin */
5924 decodebin = gst_element_factory_make("decodebin", NULL);
5927 LOGE("fail to create decodebin");
5931 /* raw pad handling signal */
5932 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
5933 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
5935 /* no-more-pad pad handling signal */
5936 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
5937 G_CALLBACK(__mmplayer_gst_decode_no_more_pads), (gpointer)player);
5939 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
5940 G_CALLBACK(__mmplayer_gst_decode_pad_removed), (gpointer)player);
5942 /* This signal is emitted when a pad for which there is no further possible
5943 decoding is added to the decodebin.*/
5944 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
5945 G_CALLBACK(__mmplayer_gst_decode_unknown_type), (gpointer)player);
5947 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5948 before looking for any elements that can handle that stream.*/
5949 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
5950 G_CALLBACK(__mmplayer_gst_decode_autoplug_continue), (gpointer)player);
5952 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
5953 before looking for any elements that can handle that stream.*/
5954 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
5955 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
5957 /* This signal is emitted once decodebin has finished decoding all the data.*/
5958 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
5959 G_CALLBACK(__mmplayer_gst_decode_drained), (gpointer)player);
5961 /* This signal is emitted when a element is added to the bin.*/
5962 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
5963 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
5970 __mmplayer_gst_make_queue2(mmplayer_t *player)
5972 GstElement *queue2 = NULL;
5973 gint64 dur_bytes = 0L;
5974 mmplayer_gst_element_t *mainbin = NULL;
5975 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
5978 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
5980 mainbin = player->pipeline->mainbin;
5982 queue2 = gst_element_factory_make("queue2", "queue2");
5984 LOGE("failed to create buffering queue element");
5988 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
5989 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
5991 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
5993 /* NOTE : in case of ts streaming, player could not get the correct duration info *
5994 * skip the pull mode(file or ring buffering) setting. */
5995 if (dur_bytes > 0) {
5996 if (!g_strrstr(player->type, "video/mpegts")) {
5997 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
5998 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6004 _mm_player_streaming_set_queue2(player->streamer,
6008 (guint64)dur_bytes); /* no meaning at the moment */
6014 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6016 mmplayer_gst_element_t *mainbin = NULL;
6017 GstElement *decodebin = NULL;
6018 GstElement *queue2 = NULL;
6019 GstPad *sinkpad = NULL;
6020 GstPad *qsrcpad = NULL;
6023 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6025 mainbin = player->pipeline->mainbin;
6027 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6029 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6030 LOGW("need to check: muxed buffer is not null");
6033 queue2 = __mmplayer_gst_make_queue2(player);
6035 LOGE("failed to make queue2");
6039 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6040 LOGE("failed to add buffering queue");
6044 sinkpad = gst_element_get_static_pad(queue2, "sink");
6045 qsrcpad = gst_element_get_static_pad(queue2, "src");
6047 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6048 LOGE("failed to link [%s:%s]-[%s:%s]",
6049 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6053 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6054 LOGE("failed to sync queue2 state with parent");
6058 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6059 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6063 gst_object_unref(GST_OBJECT(sinkpad));
6067 /* create decodebin */
6068 decodebin = _mmplayer_gst_make_decodebin(player);
6070 LOGE("failed to make decodebin");
6074 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6075 LOGE("failed to add decodebin");
6079 /* to force caps on the decodebin element and avoid reparsing stuff by
6080 * typefind. It also avoids a deadlock in the way typefind activates pads in
6081 * the state change */
6082 g_object_set(decodebin, "sink-caps", caps, NULL);
6084 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6086 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6087 LOGE("failed to link [%s:%s]-[%s:%s]",
6088 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6092 gst_object_unref(GST_OBJECT(sinkpad));
6094 gst_object_unref(GST_OBJECT(qsrcpad));
6097 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6098 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6100 /* set decodebin property about buffer in streaming playback. *
6101 * in case of HLS/DASH, it does not need to have big buffer *
6102 * because it is kind of adaptive streaming. */
6103 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6104 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6105 gint high_percent = 0;
6107 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6108 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6110 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6112 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6114 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6115 "high-percent", high_percent,
6116 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6117 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6118 "max-size-buffers", 0, NULL); // disable or automatic
6121 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6122 LOGE("failed to sync decodebin state with parent");
6133 gst_object_unref(GST_OBJECT(sinkpad));
6136 gst_object_unref(GST_OBJECT(qsrcpad));
6139 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6140 * You need to explicitly set elements to the NULL state before
6141 * dropping the final reference, to allow them to clean up.
6143 gst_element_set_state(queue2, GST_STATE_NULL);
6145 /* And, it still has a parent "player".
6146 * You need to let the parent manage the object instead of unreffing the object directly.
6148 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6149 gst_object_unref(queue2);
6154 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6155 * You need to explicitly set elements to the NULL state before
6156 * dropping the final reference, to allow them to clean up.
6158 gst_element_set_state(decodebin, GST_STATE_NULL);
6160 /* And, it still has a parent "player".
6161 * You need to let the parent manage the object instead of unreffing the object directly.
6164 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6165 gst_object_unref(decodebin);
6173 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6177 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6178 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6180 LOGD("class : %s, mime : %s", factory_class, mime);
6182 /* add missing plugin */
6183 /* NOTE : msl should check missing plugin for image mime type.
6184 * Some motion jpeg clips can have playable audio track.
6185 * So, msl have to play audio after displaying popup written video format not supported.
6187 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6188 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6189 LOGD("not found demuxer");
6190 player->not_found_demuxer = TRUE;
6191 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6197 if (!g_strrstr(factory_class, "Demuxer")) {
6198 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6199 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6200 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6202 /* check that clip have multi tracks or not */
6203 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6204 LOGD("video plugin is already linked");
6206 LOGW("add VIDEO to missing plugin");
6207 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6208 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6210 } else if (g_str_has_prefix(mime, "audio")) {
6211 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6212 LOGD("audio plugin is already linked");
6214 LOGW("add AUDIO to missing plugin");
6215 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6216 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6224 return MM_ERROR_NONE;
6228 __mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6230 mmplayer_t *player = (mmplayer_t *)data;
6234 MMPLAYER_RETURN_IF_FAIL(player);
6236 /* remove fakesink. */
6237 if (!_mmplayer_gst_remove_fakesink(player,
6238 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6239 /* NOTE : __mmplayer_pipeline_complete() can be called several time. because
6240 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6241 * source element are not same. To overcome this situation, this function will called
6242 * several places and several times. Therefore, this is not an error case.
6247 LOGD("[handle: %p] pipeline has completely constructed", player);
6249 if ((player->ini.async_start) &&
6250 (player->msg_posted == FALSE) &&
6251 (player->cmd >= MMPLAYER_COMMAND_START))
6252 __mmplayer_handle_missed_plugin(player);
6254 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6258 __mmplayer_check_profile(void)
6261 static int profile_tv = -1;
6263 if (__builtin_expect(profile_tv != -1, 1))
6266 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6267 switch (*profileName) {
6282 __mmplayer_get_next_uri(mmplayer_t *player)
6284 mmplayer_parse_profile_t profile;
6286 guint num_of_list = 0;
6289 num_of_list = g_list_length(player->uri_info.uri_list);
6290 uri_idx = player->uri_info.uri_idx;
6292 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6293 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6294 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6296 LOGW("next uri does not exist");
6300 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6301 LOGE("failed to parse profile");
6305 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6306 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6307 LOGW("uri type is not supported(%d)", profile.uri_type);
6311 LOGD("success to find next uri %d", uri_idx);
6315 if (!uri || uri_idx == num_of_list) {
6316 LOGE("failed to find next uri");
6320 player->uri_info.uri_idx = uri_idx;
6321 if (mm_player_set_attribute((MMHandleType)player, NULL,
6322 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6323 LOGE("failed to set attribute");
6327 SECURE_LOGD("next playback uri: %s", uri);
6332 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6334 #define REPEAT_COUNT_INFINITE -1
6335 #define REPEAT_COUNT_MIN 2
6336 #define ORIGINAL_URI_ONLY 1
6338 MMHandleType attrs = 0;
6342 guint num_of_uri = 0;
6343 int profile_tv = -1;
6347 LOGD("checking for gapless play option");
6349 if (player->build_audio_offload) {
6350 LOGE("offload path is not supportable.");
6354 if (player->pipeline->textbin) {
6355 LOGE("subtitle path is enabled. gapless play is not supported.");
6359 attrs = MMPLAYER_GET_ATTRS(player);
6361 LOGE("fail to get attributes.");
6365 mm_attrs_multiple_get(player->attrs, NULL,
6366 "content_video_found", &video,
6367 "profile_play_count", &count,
6368 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6370 /* gapless playback is not supported in case of video at TV profile. */
6371 profile_tv = __mmplayer_check_profile();
6372 if (profile_tv && video) {
6373 LOGW("not support video gapless playback");
6377 /* check repeat count in case of audio */
6379 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6380 LOGW("gapless is disabled");
6384 num_of_uri = g_list_length(player->uri_info.uri_list);
6386 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6388 if (num_of_uri == ORIGINAL_URI_ONLY) {
6389 /* audio looping path */
6390 if (count >= REPEAT_COUNT_MIN) {
6391 /* decrease play count */
6392 /* we succeeded to rewind. update play count and then wait for next EOS */
6394 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6395 } else if (count != REPEAT_COUNT_INFINITE) {
6396 LOGD("there is no next uri and no repeat");
6399 LOGD("looping cnt %d", count);
6401 /* gapless playback path */
6402 if (!__mmplayer_get_next_uri(player)) {
6403 LOGE("failed to get next uri");
6410 LOGE("unable to play gapless path. EOS will be posted soon");
6415 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6417 mmplayer_selector_t *selector = &player->selector[type];
6418 mmplayer_gst_element_t *sinkbin = NULL;
6419 main_element_id_e selectorId = MMPLAYER_M_NUM;
6420 main_element_id_e sinkId = MMPLAYER_M_NUM;
6421 GstPad *srcpad = NULL;
6422 GstPad *sinkpad = NULL;
6423 gboolean send_notice = FALSE;
6426 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6428 LOGD("type %d", type);
6431 case MM_PLAYER_TRACK_TYPE_AUDIO:
6432 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6433 sinkId = MMPLAYER_A_BIN;
6434 sinkbin = player->pipeline->audiobin;
6436 case MM_PLAYER_TRACK_TYPE_VIDEO:
6437 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6438 sinkId = MMPLAYER_V_BIN;
6439 sinkbin = player->pipeline->videobin;
6442 case MM_PLAYER_TRACK_TYPE_TEXT:
6443 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6444 sinkId = MMPLAYER_T_BIN;
6445 sinkbin = player->pipeline->textbin;
6448 LOGE("requested type is not supportable");
6453 if (player->pipeline->mainbin[selectorId].gst) {
6456 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6458 if (selector->event_probe_id != 0)
6459 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6460 selector->event_probe_id = 0;
6462 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6463 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6465 if (srcpad && sinkpad) {
6466 /* after getting drained signal there is no data flows, so no need to do pad_block */
6467 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6468 gst_pad_unlink(srcpad, sinkpad);
6470 /* send custom event to sink pad to handle it at video sink */
6472 LOGD("send custom event to sinkpad");
6473 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6474 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6475 gst_pad_send_event(sinkpad, event);
6479 gst_object_unref(sinkpad);
6482 gst_object_unref(srcpad);
6485 LOGD("selector release");
6487 /* release and unref requests pad from the selector */
6488 for (n = 0; n < selector->channels->len; n++) {
6489 GstPad *sinkpad = g_ptr_array_index(selector->channels, n);
6490 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6492 g_ptr_array_set_size(selector->channels, 0);
6494 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6495 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6497 player->pipeline->mainbin[selectorId].gst = NULL;
6505 __mmplayer_deactivate_old_path(mmplayer_t *player)
6508 MMPLAYER_RETURN_IF_FAIL(player);
6510 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6511 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6512 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6513 LOGE("deactivate selector error");
6517 _mmplayer_track_destroy(player);
6518 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6520 if (player->streamer) {
6521 _mm_player_streaming_initialize(player->streamer, FALSE);
6522 _mm_player_streaming_destroy(player->streamer);
6523 player->streamer = NULL;
6526 MMPLAYER_PLAYBACK_LOCK(player);
6527 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6534 if (!player->msg_posted) {
6535 MMMessageParamType msg = {0,};
6538 msg.code = MM_ERROR_PLAYER_INTERNAL;
6539 LOGE("gapless_uri_play> deactivate error");
6541 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6542 player->msg_posted = TRUE;
6548 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6550 int result = MM_ERROR_NONE;
6551 mmplayer_t *player = (mmplayer_t *)hplayer;
6554 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6555 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6557 if (mm_player_set_attribute(hplayer, NULL,
6558 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6559 LOGE("failed to set attribute");
6560 result = MM_ERROR_PLAYER_INTERNAL;
6562 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6563 LOGE("failed to add the original uri in the uri list.");
6571 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6573 mmplayer_t *player = (mmplayer_t *)hplayer;
6574 guint num_of_list = 0;
6578 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6579 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6581 if (player->pipeline && player->pipeline->textbin) {
6582 LOGE("subtitle path is enabled.");
6583 return MM_ERROR_PLAYER_INVALID_STATE;
6586 num_of_list = g_list_length(player->uri_info.uri_list);
6588 if (is_first_path) {
6589 if (num_of_list == 0) {
6590 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6591 SECURE_LOGD("add original path : %s", uri);
6593 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6594 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6596 SECURE_LOGD("change original path : %s", uri);
6599 MMHandleType attrs = 0;
6600 attrs = MMPLAYER_GET_ATTRS(player);
6602 if (num_of_list == 0) {
6603 char *original_uri = NULL;
6606 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6608 if (!original_uri) {
6609 LOGE("there is no original uri.");
6610 return MM_ERROR_PLAYER_INVALID_STATE;
6613 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6614 player->uri_info.uri_idx = 0;
6616 SECURE_LOGD("add original path at first : %s", original_uri);
6620 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6621 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6625 return MM_ERROR_NONE;
6629 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6631 mmplayer_t *player = (mmplayer_t *)hplayer;
6632 char *next_uri = NULL;
6633 guint num_of_list = 0;
6636 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6638 num_of_list = g_list_length(player->uri_info.uri_list);
6640 if (num_of_list > 0) {
6641 gint uri_idx = player->uri_info.uri_idx;
6643 if (uri_idx < num_of_list-1)
6648 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6649 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6651 *uri = g_strdup(next_uri);
6655 return MM_ERROR_NONE;
6659 __mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6660 GstCaps *caps, gpointer data)
6662 mmplayer_t *player = (mmplayer_t *)data;
6663 const gchar *klass = NULL;
6664 const gchar *mime = NULL;
6665 gchar *caps_str = NULL;
6667 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6668 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6669 caps_str = gst_caps_to_string(caps);
6671 LOGW("unknown type of caps : %s from %s",
6672 caps_str, GST_ELEMENT_NAME(elem));
6674 MMPLAYER_FREEIF(caps_str);
6676 /* There is no available codec. */
6677 __mmplayer_check_not_supported_codec(player, klass, mime);
6681 __mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6682 GstCaps *caps, gpointer data)
6684 mmplayer_t *player = (mmplayer_t *)data;
6685 const char *mime = NULL;
6686 gboolean ret = TRUE;
6688 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6689 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6691 if (g_str_has_prefix(mime, "audio")) {
6692 GstStructure *caps_structure = NULL;
6693 gint samplerate = 0;
6695 gchar *caps_str = NULL;
6697 caps_structure = gst_caps_get_structure(caps, 0);
6698 gst_structure_get_int(caps_structure, "rate", &samplerate);
6699 gst_structure_get_int(caps_structure, "channels", &channels);
6701 if ((channels > 0 && samplerate == 0)) {
6702 LOGD("exclude audio...");
6706 caps_str = gst_caps_to_string(caps);
6707 /* set it directly because not sent by TAG */
6708 if (g_strrstr(caps_str, "mobile-xmf"))
6709 mm_player_set_attribute((MMHandleType)player, NULL,
6710 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6712 MMPLAYER_FREEIF(caps_str);
6713 } else if (g_str_has_prefix(mime, "video") && !player->ini.video_playback_supported) {
6714 MMMessageParamType msg_param;
6715 memset(&msg_param, 0, sizeof(MMMessageParamType));
6716 msg_param.code = MM_ERROR_NOT_SUPPORT_API;
6717 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6718 LOGD("video file is not supported on this device");
6720 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6721 LOGD("already video linked");
6724 LOGD("found new stream");
6731 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6733 gboolean ret = TRUE;
6734 GDBusConnection *conn = NULL;
6736 GVariant *result = NULL;
6737 const gchar *dbus_device_type = NULL;
6738 const gchar *dbus_ret = NULL;
6741 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6743 LOGE("failed g_bus_get_sync() (%s)", err ? err->message : NULL);
6749 result = g_dbus_connection_call_sync(conn,
6750 "org.pulseaudio.Server",
6751 "/org/pulseaudio/StreamManager",
6752 "org.pulseaudio.StreamManager",
6753 "GetCurrentMediaRoutingPath",
6754 g_variant_new("(s)", "out"),
6755 G_VARIANT_TYPE("(ss)"),
6756 G_DBUS_CALL_FLAGS_NONE,
6760 if (!result || err) {
6761 LOGE("failed g_dbus_connection_call_sync() (%s)", err ? err->message : NULL);
6767 /* device type is listed in stream-map.json at mmfw-sysconf */
6768 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6770 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6771 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret))) {
6776 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6777 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6778 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6779 LOGD("audio offload is supportable");
6785 LOGD("audio offload is not supportable");
6789 g_variant_unref(result);
6790 g_object_unref(conn);
6795 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6797 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6798 gint64 position = 0;
6800 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6801 player->pipeline && player->pipeline->mainbin);
6803 MMPLAYER_CMD_LOCK(player);
6804 current_state = MMPLAYER_CURRENT_STATE(player);
6806 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6807 LOGW("getting current position failed in paused");
6809 _mmplayer_unrealize((MMHandleType)player);
6810 _mmplayer_realize((MMHandleType)player);
6812 _mmplayer_set_position((MMHandleType)player, position);
6814 /* async not to be blocked in streaming case */
6815 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6817 _mmplayer_pause((MMHandleType)player);
6819 if (current_state == MM_PLAYER_STATE_PLAYING)
6820 _mmplayer_start((MMHandleType)player);
6821 MMPLAYER_CMD_UNLOCK(player);
6823 LOGD("rebuilding audio pipeline is completed.");
6826 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
6828 mmplayer_t *player = (mmplayer_t *)user_data;
6829 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
6830 gboolean is_supportable = FALSE;
6832 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
6833 LOGW("failed to get device type");
6835 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
6837 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
6838 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
6839 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
6840 LOGD("ignore this dev connected info");
6844 is_supportable = __mmplayer_is_audio_offload_device_type(player);
6845 if (player->build_audio_offload == is_supportable) {
6846 LOGD("keep current pipeline without re-building");
6850 /* rebuild pipeline */
6851 LOGD("re-build pipeline - offload: %d", is_supportable);
6852 player->build_audio_offload = FALSE;
6853 __mmplayer_rebuild_audio_pipeline(player);
6859 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
6861 unsigned int id = 0;
6863 if (player->audio_device_cb_id != 0) {
6864 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
6868 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
6869 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
6870 LOGD("added device connected cb (%u)", id);
6871 player->audio_device_cb_id = id;
6873 LOGW("failed to add device connected cb");
6881 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
6883 gboolean ret = FALSE;
6884 GstElementFactory *factory = NULL;
6887 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
6889 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
6890 if (!__mmplayer_is_only_mp3_type(player->type))
6893 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
6894 LOGD("there is no audio offload sink");
6898 if (player->ini.audio_offload_device_type[0][0] == '\0') {
6899 LOGW("there is no audio device type to support offload");
6903 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
6905 LOGW("there is no installed audio offload sink element");
6908 gst_object_unref(factory);
6910 if (__mmplayer_acquire_hw_resource(player,
6911 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
6912 LOGE("failed to acquire audio offload decoder resource");
6916 if (!__mmplayer_add_audio_device_connected_cb(player))
6919 if (!__mmplayer_is_audio_offload_device_type(player))
6922 LOGD("audio offload can be built");
6927 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
6933 static GstAutoplugSelectResult
6934 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
6936 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
6938 int codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
6939 int audio_offload = 0;
6941 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
6942 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
6944 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
6945 LOGD("expose audio path to build offload output path");
6946 player->build_audio_offload = TRUE;
6947 /* update codec info */
6948 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6949 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6950 player->audiodec_linked = 1;
6952 ret = GST_AUTOPLUG_SELECT_EXPOSE;
6956 mm_attrs_get_int_by_name(player->attrs, "audio_codec_type", &codec_type);
6958 LOGD("audio codec type: %d", codec_type);
6959 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6960 /* sw codec will be skipped */
6961 for (idx = 0; player->ini.audiocodec_element_sw[idx][0] != '\0'; idx++) {
6962 if (strstr(factory_name, player->ini.audiocodec_element_sw[idx])) {
6963 LOGW("skipping sw acodec:[%s] by codec type", factory_name);
6964 ret = GST_AUTOPLUG_SELECT_SKIP;
6968 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
6969 /* hw codec will be skipped */
6970 if (strcmp(player->ini.audiocodec_element_hw, "") &&
6971 g_strrstr(factory_name, player->ini.audiocodec_element_hw)) {
6972 LOGW("skipping hw acodec:[%s] by codec type", factory_name);
6973 ret = GST_AUTOPLUG_SELECT_SKIP;
6978 /* set stream information */
6979 if (!player->audiodec_linked)
6980 __mmplayer_set_audio_attrs(player, caps);
6982 /* update codec info */
6983 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
6984 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
6985 player->audiodec_linked = 1;
6987 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
6989 mm_attrs_get_int_by_name(player->attrs, "video_codec_type", &codec_type);
6991 LOGD("video codec type: %d", codec_type);
6992 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
6993 /* sw codec is skipped */
6994 for (idx = 0; player->ini.videocodec_element_sw[idx][0] != '\0'; idx++) {
6995 if (strstr(factory_name, player->ini.videocodec_element_sw[idx])) {
6996 LOGW("skipping sw vcodec:[%s] by codec type", factory_name);
6997 ret = GST_AUTOPLUG_SELECT_SKIP;
7001 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7002 /* hw codec is skipped */
7003 if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7004 LOGW("skipping hw vcodec:[%s] by codec type", factory_name);
7005 ret = GST_AUTOPLUG_SELECT_SKIP;
7010 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7011 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7013 /* mark video decoder for acquire */
7014 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7015 LOGW("video decoder resource is already acquired, skip it.");
7016 ret = GST_AUTOPLUG_SELECT_SKIP;
7020 if (__mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7021 LOGE("failed to acquire video decoder resource");
7022 ret = GST_AUTOPLUG_SELECT_SKIP;
7025 player->interrupted_by_resource = FALSE;
7028 /* update codec info */
7029 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7030 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7031 player->videodec_linked = 1;
7039 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7040 GstCaps *caps, GstElementFactory *factory, gpointer data)
7042 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7043 mmplayer_t *player = (mmplayer_t *)data;
7045 gchar *factory_name = NULL;
7046 gchar *caps_str = NULL;
7047 const gchar *klass = NULL;
7050 factory_name = GST_OBJECT_NAME(factory);
7051 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7052 caps_str = gst_caps_to_string(caps);
7054 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7056 /* store type string */
7057 if (player->type == NULL) {
7058 player->type = gst_caps_to_string(caps);
7059 __mmplayer_update_content_type_info(player);
7062 /* filtering exclude keyword */
7063 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7064 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7065 LOGW("skipping [%s] by exculde keyword [%s]",
7066 factory_name, player->ini.exclude_element_keyword[idx]);
7068 result = GST_AUTOPLUG_SELECT_SKIP;
7073 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7074 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7075 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7076 factory_name, player->ini.unsupported_codec_keyword[idx]);
7077 result = GST_AUTOPLUG_SELECT_SKIP;
7082 /* exclude webm format */
7083 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7084 * because webm format is not supportable.
7085 * If webm is disabled in "autoplug-continue", there is no state change
7086 * failure or error because the decodebin will expose the pad directly.
7087 * It make MSL invoke _prepare_async_callback.
7088 * So, we need to disable webm format in "autoplug-select" */
7089 if (caps_str && strstr(caps_str, "webm")) {
7090 LOGW("webm is not supported");
7091 result = GST_AUTOPLUG_SELECT_SKIP;
7095 /* check factory class for filtering */
7096 /* NOTE : msl don't need to use image plugins.
7097 * So, those plugins should be skipped for error handling.
7099 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7100 LOGD("skipping [%s] by not required", factory_name);
7101 result = GST_AUTOPLUG_SELECT_SKIP;
7105 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7106 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7107 // TO CHECK : subtitle if needed, add subparse exception.
7108 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7109 result = GST_AUTOPLUG_SELECT_SKIP;
7113 if (g_strrstr(factory_name, "mpegpsdemux")) {
7114 LOGD("skipping PS container - not support");
7115 result = GST_AUTOPLUG_SELECT_SKIP;
7119 if (g_strrstr(factory_name, "mssdemux"))
7120 player->smooth_streaming = TRUE;
7122 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7123 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7126 GstStructure *str = NULL;
7127 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7129 /* don't make video because of not required */
7130 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7131 (!player->set_mode.video_export)) {
7132 LOGD("no need video decoding, expose pad");
7133 result = GST_AUTOPLUG_SELECT_EXPOSE;
7137 /* get w/h for omx state-tune */
7138 /* FIXME: deprecated? */
7139 str = gst_caps_get_structure(caps, 0);
7140 gst_structure_get_int(str, "width", &width);
7143 if (player->v_stream_caps) {
7144 gst_caps_unref(player->v_stream_caps);
7145 player->v_stream_caps = NULL;
7148 player->v_stream_caps = gst_caps_copy(caps);
7149 LOGD("take caps for video state tune");
7150 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7154 if (g_strrstr(klass, "Codec/Decoder")) {
7155 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7156 if (result != GST_AUTOPLUG_SELECT_TRY) {
7157 LOGW("skip add decoder");
7163 MMPLAYER_FREEIF(caps_str);
7169 __mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7172 //mmplayer_t *player = (mmplayer_t *)data;
7173 GstCaps *caps = NULL;
7175 LOGD("[Decodebin2] pad-removed signal");
7177 caps = gst_pad_query_caps(new_pad, NULL);
7179 LOGW("query caps is NULL");
7183 gchar *caps_str = NULL;
7184 caps_str = gst_caps_to_string(caps);
7186 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7188 MMPLAYER_FREEIF(caps_str);
7189 gst_caps_unref(caps);
7193 __mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7195 mmplayer_t *player = (mmplayer_t *)data;
7196 GstIterator *iter = NULL;
7197 GValue item = { 0, };
7199 gboolean done = FALSE;
7200 gboolean is_all_drained = TRUE;
7203 MMPLAYER_RETURN_IF_FAIL(player);
7205 LOGD("__mmplayer_gst_decode_drained");
7207 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7208 LOGW("Fail to get cmd lock");
7212 if (!player->gapless.reconfigure && /* If it is already checked, skip verify. */
7213 !__mmplayer_verify_gapless_play_path(player)) {
7214 LOGD("decoding is finished.");
7215 __mmplayer_reset_gapless_state(player);
7216 MMPLAYER_CMD_UNLOCK(player);
7220 player->gapless.reconfigure = TRUE;
7222 /* check decodebin src pads whether they received EOS or not */
7223 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7226 switch (gst_iterator_next(iter, &item)) {
7227 case GST_ITERATOR_OK:
7228 pad = g_value_get_object(&item);
7229 if (pad && !GST_PAD_IS_EOS(pad)) {
7230 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7231 is_all_drained = FALSE;
7234 g_value_reset(&item);
7236 case GST_ITERATOR_RESYNC:
7237 gst_iterator_resync(iter);
7239 case GST_ITERATOR_ERROR:
7240 case GST_ITERATOR_DONE:
7245 g_value_unset(&item);
7246 gst_iterator_free(iter);
7248 if (!is_all_drained) {
7249 LOGD("Wait util the all pads get EOS.");
7250 MMPLAYER_CMD_UNLOCK(player);
7255 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7256 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7258 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7259 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7260 __mmplayer_deactivate_old_path(player);
7261 MMPLAYER_CMD_UNLOCK(player);
7267 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7269 mmplayer_t *player = (mmplayer_t *)data;
7270 const gchar *klass = NULL;
7271 gchar *factory_name = NULL;
7273 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7274 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7276 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7278 if (__mmplayer_add_dump_buffer_probe(player, element))
7279 LOGD("add buffer probe");
7281 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7282 gchar *selected = NULL;
7283 selected = g_strdup(GST_ELEMENT_NAME(element));
7284 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7287 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7288 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7289 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7291 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7292 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7294 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7295 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7296 "max-video-width", player->adaptive_info.limit.width,
7297 "max-video-height", player->adaptive_info.limit.height, NULL);
7299 } else if (g_strrstr(klass, "Demuxer")) {
7301 LOGD("plugged element is demuxer. take it");
7303 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7304 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7307 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7308 int surface_type = 0;
7310 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7313 // to support trust-zone only
7314 if (g_strrstr(factory_name, "asfdemux")) {
7315 LOGD("set file-location %s", player->profile.uri);
7316 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7317 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7318 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7319 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7320 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7321 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7322 (__mmplayer_is_only_mp3_type(player->type))) {
7323 LOGD("[mpegaudioparse] set streaming pull mode.");
7324 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7326 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7327 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7330 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7331 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7332 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7334 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7335 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7337 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7338 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7339 (MMPLAYER_IS_DASH_STREAMING(player))) {
7340 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7341 _mm_player_streaming_set_multiqueue(player->streamer, element);
7342 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7351 __mmplayer_release_misc(mmplayer_t *player)
7354 bool cur_mode = player->set_mode.rich_audio;
7357 MMPLAYER_RETURN_IF_FAIL(player);
7359 player->video_decoded_cb = NULL;
7360 player->video_decoded_cb_user_param = NULL;
7361 player->video_stream_prerolled = false;
7363 player->audio_decoded_cb = NULL;
7364 player->audio_decoded_cb_user_param = NULL;
7365 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7367 player->audio_stream_changed_cb = NULL;
7368 player->audio_stream_changed_cb_user_param = NULL;
7370 player->sent_bos = FALSE;
7371 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7373 player->seek_state = MMPLAYER_SEEK_NONE;
7375 player->total_bitrate = 0;
7376 player->total_maximum_bitrate = 0;
7378 player->not_found_demuxer = 0;
7380 player->last_position = 0;
7381 player->duration = 0;
7382 player->http_content_size = 0;
7383 player->not_supported_codec = MISSING_PLUGIN_NONE;
7384 player->can_support_codec = FOUND_PLUGIN_NONE;
7385 player->pending_seek.is_pending = false;
7386 player->pending_seek.pos = 0;
7387 player->msg_posted = FALSE;
7388 player->has_many_types = FALSE;
7389 player->is_subtitle_force_drop = FALSE;
7390 player->play_subtitle = FALSE;
7391 player->adjust_subtitle_pos = 0;
7392 player->has_closed_caption = FALSE;
7393 player->set_mode.video_export = false;
7394 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7395 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7397 player->set_mode.rich_audio = cur_mode;
7399 if (player->audio_device_cb_id > 0 &&
7400 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7401 LOGW("failed to remove audio device_connected_callback");
7402 player->audio_device_cb_id = 0;
7404 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7405 player->bitrate[i] = 0;
7406 player->maximum_bitrate[i] = 0;
7409 /* free memory related to audio effect */
7410 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7412 if (player->adaptive_info.var_list) {
7413 g_list_free_full(player->adaptive_info.var_list, g_free);
7414 player->adaptive_info.var_list = NULL;
7417 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7418 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7419 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7421 /* Reset video360 settings to their defaults in case if the pipeline is to be
7424 player->video360_metadata.is_spherical = -1;
7425 player->is_openal_plugin_used = FALSE;
7427 player->is_content_spherical = FALSE;
7428 player->is_video360_enabled = TRUE;
7429 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7430 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7431 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7432 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7433 player->video360_zoom = 1.0f;
7434 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7435 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7437 player->sound.rg_enable = false;
7439 __mmplayer_initialize_video_roi(player);
7444 __mmplayer_release_misc_post(mmplayer_t *player)
7446 char *original_uri = NULL;
7449 /* player->pipeline is already released before. */
7451 MMPLAYER_RETURN_IF_FAIL(player);
7453 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7455 /* clean found audio decoders */
7456 if (player->audio_decoders) {
7457 GList *a_dec = player->audio_decoders;
7458 for (; a_dec; a_dec = g_list_next(a_dec)) {
7459 gchar *name = a_dec->data;
7460 MMPLAYER_FREEIF(name);
7462 g_list_free(player->audio_decoders);
7463 player->audio_decoders = NULL;
7466 /* clean the uri list except original uri */
7467 if (player->uri_info.uri_list) {
7468 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7471 LOGW("failed to get original uri info");
7473 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7474 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7476 GList *uri_list = player->uri_info.uri_list;
7477 for (; uri_list; uri_list = g_list_next(uri_list)) {
7478 gchar *uri = uri_list->data;
7479 MMPLAYER_FREEIF(uri);
7481 g_list_free(player->uri_info.uri_list);
7482 player->uri_info.uri_list = NULL;
7485 /* clear the audio stream buffer list */
7486 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7488 /* clear the video stream bo list */
7489 __mmplayer_video_stream_destroy_bo_list(player);
7490 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7492 if (player->profile.input_mem.buf) {
7493 free(player->profile.input_mem.buf);
7494 player->profile.input_mem.buf = NULL;
7496 player->profile.input_mem.len = 0;
7497 player->profile.input_mem.offset = 0;
7499 player->uri_info.uri_idx = 0;
7504 __mmplayer_check_subtitle(mmplayer_t *player)
7506 MMHandleType attrs = 0;
7507 char *subtitle_uri = NULL;
7511 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7513 /* get subtitle attribute */
7514 attrs = MMPLAYER_GET_ATTRS(player);
7518 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7519 if (!subtitle_uri || !strlen(subtitle_uri))
7522 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7523 player->is_external_subtitle_present = TRUE;
7531 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7533 MMPLAYER_RETURN_IF_FAIL(player);
7535 if (player->eos_timer) {
7536 LOGD("cancel eos timer");
7537 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7538 player->eos_timer = 0;
7545 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink)
7549 MMPLAYER_RETURN_IF_FAIL(player);
7550 MMPLAYER_RETURN_IF_FAIL(sink);
7552 player->sink_elements = g_list_append(player->sink_elements, sink);
7558 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7562 MMPLAYER_RETURN_IF_FAIL(player);
7563 MMPLAYER_RETURN_IF_FAIL(sink);
7565 player->sink_elements = g_list_remove(player->sink_elements, sink);
7571 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7572 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7574 mmplayer_signal_item_t *item = NULL;
7577 MMPLAYER_RETURN_IF_FAIL(player);
7579 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7580 LOGE("invalid signal type [%d]", type);
7584 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7586 LOGE("cannot connect signal [%s]", signal);
7591 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7592 player->signals[type] = g_list_append(player->signals[type], item);
7598 /* NOTE : be careful with calling this api. please refer to below glib comment
7599 * glib comment : Note that there is a bug in GObject that makes this function much
7600 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7601 * will no longer be called, but, the signal handler is not currently disconnected.
7602 * If the instance is itself being freed at the same time than this doesn't matter,
7603 * since the signal will automatically be removed, but if instance persists,
7604 * then the signal handler will leak. You should not remove the signal yourself
7605 * because in a future versions of GObject, the handler will automatically be
7608 * It's possible to work around this problem in a way that will continue to work
7609 * with future versions of GObject by checking that the signal handler is still
7610 * connected before disconnected it:
7612 * if (g_signal_handler_is_connected(instance, id))
7613 * g_signal_handler_disconnect(instance, id);
7616 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7618 GList *sig_list = NULL;
7619 mmplayer_signal_item_t *item = NULL;
7623 MMPLAYER_RETURN_IF_FAIL(player);
7625 LOGD("release signals type : %d", type);
7627 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7628 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7629 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7630 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7631 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7632 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7636 sig_list = player->signals[type];
7638 for (; sig_list; sig_list = sig_list->next) {
7639 item = sig_list->data;
7641 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7642 if (g_signal_handler_is_connected(item->obj, item->sig))
7643 g_signal_handler_disconnect(item->obj, item->sig);
7646 MMPLAYER_FREEIF(item);
7649 g_list_free(player->signals[type]);
7650 player->signals[type] = NULL;
7658 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, unsigned int wl_surface_id)
7660 mmplayer_t *player = 0;
7661 int prev_display_surface_type = 0;
7665 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7667 player = MM_PLAYER_CAST(handle);
7669 /* check video sinkbin is created */
7670 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7671 LOGW("Videosink is already created");
7672 return MM_ERROR_NONE;
7675 LOGD("videosink element is not yet ready");
7677 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7678 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
7680 return MM_ERROR_INVALID_ARGUMENT;
7683 /* load previous attributes */
7684 if (player->attrs) {
7685 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
7686 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
7687 if (prev_display_surface_type == surface_type) {
7688 LOGD("incoming display surface type is same as previous one, do nothing..");
7690 return MM_ERROR_NONE;
7693 LOGE("failed to load attributes");
7695 return MM_ERROR_PLAYER_INTERNAL;
7698 /* videobin is not created yet, so we just set attributes related to display surface */
7699 LOGD("store display attribute for given surface type(%d)", surface_type);
7700 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
7701 "display_overlay", (int)wl_surface_id, NULL);
7704 return MM_ERROR_NONE;
7707 /* Note : if silent is true, then subtitle would not be displayed. :*/
7709 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
7711 mmplayer_t *player = (mmplayer_t *)hplayer;
7715 /* check player handle */
7716 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7718 player->set_mode.subtitle_off = silent;
7720 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
7724 return MM_ERROR_NONE;
7728 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
7730 mmplayer_gst_element_t *mainbin = NULL;
7731 mmplayer_gst_element_t *textbin = NULL;
7732 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7733 GstState current_state = GST_STATE_VOID_PENDING;
7734 GstState element_state = GST_STATE_VOID_PENDING;
7735 GstState element_pending_state = GST_STATE_VOID_PENDING;
7737 GstEvent *event = NULL;
7738 int result = MM_ERROR_NONE;
7740 GstClock *curr_clock = NULL;
7741 GstClockTime base_time, start_time, curr_time;
7746 /* check player handle */
7747 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7749 player->pipeline->mainbin &&
7750 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7752 mainbin = player->pipeline->mainbin;
7753 textbin = player->pipeline->textbin;
7755 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7757 // sync clock with current pipeline
7758 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
7759 curr_time = gst_clock_get_time(curr_clock);
7761 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7762 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
7764 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
7765 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
7767 if (current_state > GST_STATE_READY) {
7768 // sync state with current pipeline
7769 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
7770 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
7771 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
7773 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
7774 if (GST_STATE_CHANGE_FAILURE == ret) {
7775 LOGE("fail to state change.");
7776 result = MM_ERROR_PLAYER_INTERNAL;
7780 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
7781 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
7784 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
7785 gst_object_unref(curr_clock);
7788 // seek to current position
7789 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
7790 result = MM_ERROR_PLAYER_INVALID_STATE;
7791 LOGE("gst_element_query_position failed, invalid state");
7795 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
7796 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);
7798 _mmplayer_gst_send_event_to_sink(player, event);
7800 result = MM_ERROR_PLAYER_INTERNAL;
7801 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
7805 /* sync state with current pipeline */
7806 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
7807 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
7808 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
7810 return MM_ERROR_NONE;
7813 /* release text pipeline resource */
7814 player->textsink_linked = 0;
7816 /* release signal */
7817 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7819 /* release textbin with it's childs */
7820 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
7821 MMPLAYER_FREEIF(player->pipeline->textbin);
7822 player->pipeline->textbin = NULL;
7824 /* release subtitle elem */
7825 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
7826 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
7832 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
7834 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
7835 GstState current_state = GST_STATE_VOID_PENDING;
7837 MMHandleType attrs = 0;
7838 mmplayer_gst_element_t *mainbin = NULL;
7839 mmplayer_gst_element_t *textbin = NULL;
7841 gchar *subtitle_uri = NULL;
7842 int result = MM_ERROR_NONE;
7843 const gchar *charset = NULL;
7847 /* check player handle */
7848 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
7850 player->pipeline->mainbin &&
7851 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
7852 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7854 mainbin = player->pipeline->mainbin;
7855 textbin = player->pipeline->textbin;
7857 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
7858 if (current_state < GST_STATE_READY) {
7859 result = MM_ERROR_PLAYER_INVALID_STATE;
7860 LOGE("Pipeline is not in proper state");
7864 attrs = MMPLAYER_GET_ATTRS(player);
7866 LOGE("cannot get content attribute");
7867 result = MM_ERROR_PLAYER_INTERNAL;
7871 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7872 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
7873 LOGE("subtitle uri is not proper filepath");
7874 result = MM_ERROR_PLAYER_INVALID_URI;
7878 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
7879 LOGE("failed to get storage info of subtitle path");
7880 result = MM_ERROR_PLAYER_INVALID_URI;
7884 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
7885 SECURE_LOGD("new subtitle file path is [%s]", filepath);
7887 if (!strcmp(filepath, subtitle_uri)) {
7888 LOGD("subtitle path is not changed");
7891 if (mm_player_set_attribute((MMHandleType)player, NULL,
7892 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7893 LOGE("failed to set attribute");
7898 //gst_pad_set_blocked_async(src-srcpad, TRUE)
7899 MMPLAYER_SUBTITLE_INFO_LOCK(player);
7900 player->subtitle_language_list = NULL;
7901 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
7903 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
7904 if (ret != GST_STATE_CHANGE_SUCCESS) {
7905 LOGE("failed to change state of textbin to READY");
7906 result = MM_ERROR_PLAYER_INTERNAL;
7910 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
7911 if (ret != GST_STATE_CHANGE_SUCCESS) {
7912 LOGE("failed to change state of subparse to READY");
7913 result = MM_ERROR_PLAYER_INTERNAL;
7917 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
7918 if (ret != GST_STATE_CHANGE_SUCCESS) {
7919 LOGE("failed to change state of filesrc to READY");
7920 result = MM_ERROR_PLAYER_INTERNAL;
7924 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
7926 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
7928 charset = _mmplayer_get_charset(filepath);
7930 LOGD("detected charset is %s", charset);
7931 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
7934 result = _mmplayer_sync_subtitle_pipeline(player);
7941 /* API to switch between external subtitles */
7943 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
7945 int result = MM_ERROR_NONE;
7946 mmplayer_t *player = (mmplayer_t *)hplayer;
7951 /* check player handle */
7952 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7954 /* filepath can be null in idle state */
7956 /* check file path */
7957 if ((path = strstr(filepath, "file://")))
7958 result = _mmplayer_exist_file_path(path + 7);
7960 result = _mmplayer_exist_file_path(filepath);
7962 if (result != MM_ERROR_NONE) {
7963 LOGE("invalid subtitle path 0x%X", result);
7964 return result; /* file not found or permission denied */
7968 if (!player->pipeline) {
7970 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
7971 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
7972 LOGE("failed to set attribute");
7973 return MM_ERROR_PLAYER_INTERNAL;
7976 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
7977 /* check filepath */
7978 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
7980 if (!__mmplayer_check_subtitle(player)) {
7981 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
7982 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
7983 LOGE("failed to set attribute");
7984 return MM_ERROR_PLAYER_INTERNAL;
7987 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
7988 LOGE("fail to create text pipeline");
7989 return MM_ERROR_PLAYER_INTERNAL;
7992 result = _mmplayer_sync_subtitle_pipeline(player);
7994 result = __mmplayer_change_external_subtitle_language(player, filepath);
7997 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
7998 player->is_external_subtitle_added_now = TRUE;
8000 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8001 if (!player->subtitle_language_list) {
8002 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8003 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8004 LOGW("subtitle language list is not updated yet");
8006 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8014 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8016 int result = MM_ERROR_NONE;
8017 gchar *change_pad_name = NULL;
8018 GstPad *sinkpad = NULL;
8019 mmplayer_gst_element_t *mainbin = NULL;
8020 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8021 GstCaps *caps = NULL;
8022 gint total_track_num = 0;
8026 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8027 MM_ERROR_PLAYER_NOT_INITIALIZED);
8029 LOGD("Change Track(%d) to %d", type, index);
8031 mainbin = player->pipeline->mainbin;
8033 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8034 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8035 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8036 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8038 /* Changing Video Track is not supported. */
8039 LOGE("Track Type Error");
8043 if (mainbin[elem_idx].gst == NULL) {
8044 result = MM_ERROR_PLAYER_NO_OP;
8045 LOGD("Req track doesn't exist");
8049 total_track_num = player->selector[type].total_track_num;
8050 if (total_track_num <= 0) {
8051 result = MM_ERROR_PLAYER_NO_OP;
8052 LOGD("Language list is not available");
8056 if ((index < 0) || (index >= total_track_num)) {
8057 result = MM_ERROR_INVALID_ARGUMENT;
8058 LOGD("Not a proper index : %d", index);
8062 /*To get the new pad from the selector*/
8063 change_pad_name = g_strdup_printf("sink_%u", index);
8064 if (change_pad_name == NULL) {
8065 result = MM_ERROR_PLAYER_INTERNAL;
8066 LOGD("Pad does not exists");
8070 LOGD("new active pad name: %s", change_pad_name);
8072 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8073 if (sinkpad == NULL) {
8074 LOGD("sinkpad is NULL");
8075 result = MM_ERROR_PLAYER_INTERNAL;
8079 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8080 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8082 caps = gst_pad_get_current_caps(sinkpad);
8083 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8086 gst_object_unref(sinkpad);
8088 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8089 __mmplayer_set_audio_attrs(player, caps);
8092 MMPLAYER_FREEIF(change_pad_name);
8097 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8099 int result = MM_ERROR_NONE;
8100 mmplayer_t *player = NULL;
8101 mmplayer_gst_element_t *mainbin = NULL;
8103 gint current_active_index = 0;
8105 GstState current_state = GST_STATE_VOID_PENDING;
8106 GstEvent *event = NULL;
8111 player = (mmplayer_t *)hplayer;
8112 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8114 if (!player->pipeline) {
8115 LOGE("Track %d pre setting -> %d", type, index);
8117 player->selector[type].active_pad_index = index;
8121 mainbin = player->pipeline->mainbin;
8123 current_active_index = player->selector[type].active_pad_index;
8125 /*If index is same as running index no need to change the pad*/
8126 if (current_active_index == index)
8129 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8130 result = MM_ERROR_PLAYER_INVALID_STATE;
8134 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8135 if (current_state < GST_STATE_PAUSED) {
8136 result = MM_ERROR_PLAYER_INVALID_STATE;
8137 LOGW("Pipeline not in porper state");
8141 result = __mmplayer_change_selector_pad(player, type, index);
8142 if (result != MM_ERROR_NONE) {
8143 LOGE("change selector pad error");
8147 player->selector[type].active_pad_index = index;
8149 if (current_state == GST_STATE_PLAYING) {
8150 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8151 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8152 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8154 _mmplayer_gst_send_event_to_sink(player, event);
8156 result = MM_ERROR_PLAYER_INTERNAL;
8166 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8168 mmplayer_t *player = (mmplayer_t *)hplayer;
8172 /* check player handle */
8173 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8175 *silent = player->set_mode.subtitle_off;
8177 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8181 return MM_ERROR_NONE;
8185 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8187 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8188 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8190 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8191 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8195 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8196 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8197 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8198 mmplayer_dump_t *dump_s;
8199 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8200 if (dump_s == NULL) {
8201 LOGE("malloc fail");
8205 dump_s->dump_element_file = NULL;
8206 dump_s->dump_pad = NULL;
8207 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8209 if (dump_s->dump_pad) {
8210 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8211 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]);
8212 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8213 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);
8214 /* add list for removed buffer probe and close FILE */
8215 player->dump_list = g_list_append(player->dump_list, dump_s);
8216 LOGD("%s sink pad added buffer probe for dump", factory_name);
8219 MMPLAYER_FREEIF(dump_s);
8220 LOGE("failed to get %s sink pad added", factory_name);
8227 static GstPadProbeReturn
8228 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8230 FILE *dump_data = (FILE *)u_data;
8232 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8233 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8235 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8237 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8239 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8241 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8243 gst_buffer_unmap(buffer, &probe_info);
8245 return GST_PAD_PROBE_OK;
8249 __mmplayer_release_dump_list(GList *dump_list)
8251 GList *d_list = dump_list;
8256 for (; d_list; d_list = g_list_next(d_list)) {
8257 mmplayer_dump_t *dump_s = d_list->data;
8258 if (dump_s->dump_pad) {
8259 if (dump_s->probe_handle_id)
8260 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8261 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8263 if (dump_s->dump_element_file) {
8264 fclose(dump_s->dump_element_file);
8265 dump_s->dump_element_file = NULL;
8267 MMPLAYER_FREEIF(dump_s);
8269 g_list_free(dump_list);
8274 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8276 mmplayer_t *player = (mmplayer_t *)hplayer;
8280 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8281 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8283 *exist = (bool)player->has_closed_caption;
8287 return MM_ERROR_NONE;
8291 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8296 LOGD("unref internal gst buffer %p", buffer);
8298 gst_buffer_unref((GstBuffer *)buffer);
8305 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8307 mmplayer_t *player = (mmplayer_t *)hplayer;
8311 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8312 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8314 if (MMPLAYER_IS_STREAMING(player))
8315 *timeout = (int)player->ini.live_state_change_timeout;
8317 *timeout = (int)player->ini.localplayback_state_change_timeout;
8319 LOGD("timeout = %d", *timeout);
8322 return MM_ERROR_NONE;
8326 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8330 MMPLAYER_RETURN_IF_FAIL(player);
8332 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8334 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8335 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8336 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8337 player->storage_info[i].id = -1;
8338 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8340 if (path_type != MMPLAYER_PATH_MAX)
8349 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8351 int ret = MM_ERROR_NONE;
8352 mmplayer_t *player = (mmplayer_t *)hplayer;
8353 MMMessageParamType msg_param = {0, };
8356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8358 LOGW("state changed storage %d:%d", id, state);
8360 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8361 return MM_ERROR_NONE;
8363 /* FIXME: text path should be handled seperately. */
8364 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8365 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8366 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8367 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8368 LOGW("external storage is removed");
8370 if (player->msg_posted == FALSE) {
8371 memset(&msg_param, 0, sizeof(MMMessageParamType));
8372 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8373 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8374 player->msg_posted = TRUE;
8377 /* unrealize the player */
8378 ret = _mmplayer_unrealize(hplayer);
8379 if (ret != MM_ERROR_NONE)
8380 LOGE("failed to unrealize");
8388 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8390 int ret = MM_ERROR_NONE;
8391 mmplayer_t *player = (mmplayer_t *)hplayer;
8392 int idx = 0, total = 0;
8393 gchar *result = NULL, *tmp = NULL;
8396 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8397 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8399 total = *num = g_list_length(player->adaptive_info.var_list);
8401 LOGW("There is no stream variant info.");
8405 result = g_strdup("");
8406 for (idx = 0 ; idx < total ; idx++) {
8407 stream_variant_t *v_data = NULL;
8408 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8411 gchar data[64] = {0};
8412 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8414 tmp = g_strconcat(result, data, NULL);
8418 LOGW("There is no variant data in %d", idx);
8423 *var_info = (char *)result;
8425 LOGD("variant info %d:%s", *num, *var_info);
8431 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8433 int ret = MM_ERROR_NONE;
8434 mmplayer_t *player = (mmplayer_t *)hplayer;
8437 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8439 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8441 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8442 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8443 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8445 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8446 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8447 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8448 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8450 /* FIXME: seek to current position for applying new variant limitation */
8459 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8461 int ret = MM_ERROR_NONE;
8462 mmplayer_t *player = (mmplayer_t *)hplayer;
8465 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8466 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8468 *bandwidth = player->adaptive_info.limit.bandwidth;
8469 *width = player->adaptive_info.limit.width;
8470 *height = player->adaptive_info.limit.height;
8472 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8479 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8481 int ret = MM_ERROR_NONE;
8482 mmplayer_t *player = (mmplayer_t *)hplayer;
8485 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8486 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8487 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8489 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8491 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8492 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8493 else /* live case */
8494 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8496 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8503 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_video_codec_type_e codec_type)
8505 #define IDX_FIRST_SW_CODEC 0
8506 mmplayer_t *player = (mmplayer_t *)hplayer;
8507 const char *attr_name = (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO) ? (MM_PLAYER_AUDIO_CODEC_TYPE) : (MM_PLAYER_VIDEO_CODEC_TYPE);
8510 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8512 LOGD("ini setting : [a][h:%s][s:%s] / [v][h:%s][s:%s]",
8513 player->ini.audiocodec_element_hw, player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC],
8514 player->ini.videocodec_element_hw, player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC]);
8516 switch (stream_type) {
8517 case MM_PLAYER_STREAM_TYPE_AUDIO:
8518 /* to support audio codec selection, codec info have to be added in ini file as below.
8519 audio codec element hw = xxxx
8520 audio codec element sw = avdec */
8521 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8522 (!strcmp(player->ini.audiocodec_element_hw, ""))) ||
8523 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8524 (!strcmp(player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8525 LOGE("There is no audio codec info for codec_type %d", codec_type);
8526 return MM_ERROR_PLAYER_NO_OP;
8529 case MM_PLAYER_STREAM_TYPE_VIDEO:
8530 /* to support video codec selection, codec info have to be added in ini file as below.
8531 video codec element hw = omx
8532 video codec element sw = avdec */
8533 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) &&
8534 (!strcmp(player->ini.videocodec_element_hw, ""))) ||
8535 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) &&
8536 (!strcmp(player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC], "")))) {
8537 LOGE("There is no video codec info for codec_type %d", codec_type);
8538 return MM_ERROR_PLAYER_NO_OP;
8542 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8543 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8547 LOGD("update %s codec_type to %d", attr_name, codec_type);
8548 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8551 return MM_ERROR_NONE;
8555 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8557 mmplayer_t *player = (mmplayer_t *)hplayer;
8558 GstElement *rg_vol_element = NULL;
8562 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8564 player->sound.rg_enable = enabled;
8566 /* just hold rgvolume enable value if pipeline is not ready */
8567 if (!player->pipeline || !player->pipeline->audiobin) {
8568 LOGD("pipeline is not ready. holding rgvolume enable value");
8569 return MM_ERROR_NONE;
8572 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8574 if (!rg_vol_element) {
8575 LOGD("rgvolume element is not created");
8576 return MM_ERROR_PLAYER_INTERNAL;
8580 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8582 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8586 return MM_ERROR_NONE;
8590 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8592 mmplayer_t *player = (mmplayer_t *)hplayer;
8593 GstElement *rg_vol_element = NULL;
8594 gboolean enable = FALSE;
8598 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8599 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8601 /* just hold enable_rg value if pipeline is not ready */
8602 if (!player->pipeline || !player->pipeline->audiobin) {
8603 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8604 *enabled = player->sound.rg_enable;
8605 return MM_ERROR_NONE;
8608 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8610 if (!rg_vol_element) {
8611 LOGD("rgvolume element is not created");
8612 return MM_ERROR_PLAYER_INTERNAL;
8615 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
8616 *enabled = (bool)enable;
8620 return MM_ERROR_NONE;
8624 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
8626 mmplayer_t *player = (mmplayer_t *)hplayer;
8627 MMHandleType attrs = 0;
8629 int ret = MM_ERROR_NONE;
8633 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8635 attrs = MMPLAYER_GET_ATTRS(player);
8636 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
8638 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
8640 LOGE("Display handle is NULL, after setting window handle, set video roi area");
8641 return MM_ERROR_PLAYER_INTERNAL;
8644 player->video_roi.scale_x = scale_x;
8645 player->video_roi.scale_y = scale_y;
8646 player->video_roi.scale_width = scale_width;
8647 player->video_roi.scale_height = scale_height;
8649 /* check video sinkbin is created */
8650 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
8651 return MM_ERROR_NONE;
8653 if (!gst_video_overlay_set_video_roi_area(
8654 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
8655 scale_x, scale_y, scale_width, scale_height))
8656 ret = MM_ERROR_PLAYER_INTERNAL;
8658 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8659 scale_x, scale_y, scale_width, scale_height);
8667 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
8669 mmplayer_t *player = (mmplayer_t *)hplayer;
8670 int ret = MM_ERROR_NONE;
8674 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8675 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
8677 *scale_x = player->video_roi.scale_x;
8678 *scale_y = player->video_roi.scale_y;
8679 *scale_width = player->video_roi.scale_width;
8680 *scale_height = player->video_roi.scale_height;
8682 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
8683 *scale_x, *scale_y, *scale_width, *scale_height);
8689 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
8691 mmplayer_t* player = (mmplayer_t*)hplayer;
8695 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8697 player->client_pid = pid;
8699 LOGD("client pid[%d] %p", pid, player);
8703 return MM_ERROR_NONE;
8707 __mmplayer_update_duration_value(mmplayer_t *player)
8709 gboolean ret = FALSE;
8710 gint64 dur_nsec = 0;
8711 LOGD("try to update duration");
8713 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
8714 player->duration = dur_nsec;
8715 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
8719 if (player->duration < 0) {
8720 LOGW("duration is Non-Initialized !!!");
8721 player->duration = 0;
8724 /* update streaming service type */
8725 player->streaming_type = _mmplayer_get_stream_service_type(player);
8727 /* check duration is OK */
8728 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
8729 /* FIXIT : find another way to get duration here. */
8730 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
8736 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
8738 /* update audio params
8739 NOTE : We need original audio params and it can be only obtained from src pad of audio
8740 decoder. Below code only valid when we are not using 'resampler' just before
8741 'audioconverter'. */
8742 GstCaps *caps_a = NULL;
8744 gint samplerate = 0, channels = 0;
8745 GstStructure *p = NULL;
8746 GstElement *aconv = NULL;
8748 LOGD("try to update audio attrs");
8750 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
8752 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
8753 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
8754 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
8755 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
8757 LOGE("there is no audio converter");
8761 pad = gst_element_get_static_pad(aconv, "sink");
8764 LOGW("failed to get pad from audio converter");
8768 caps_a = gst_pad_get_current_caps(pad);
8770 LOGW("not ready to get audio caps");
8771 gst_object_unref(pad);
8775 p = gst_caps_get_structure(caps_a, 0);
8777 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
8779 gst_structure_get_int(p, "rate", &samplerate);
8780 gst_structure_get_int(p, "channels", &channels);
8782 mm_player_set_attribute((MMHandleType)player, NULL,
8783 "content_audio_samplerate", samplerate,
8784 "content_audio_channels", channels, NULL);
8786 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
8788 gst_caps_unref(caps_a);
8789 gst_object_unref(pad);
8795 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
8797 LOGD("try to update video attrs");
8799 GstCaps *caps_v = NULL;
8803 GstStructure *p = NULL;
8805 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
8806 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
8808 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
8810 LOGD("no videosink sink pad");
8814 caps_v = gst_pad_get_current_caps(pad);
8815 /* Use v_stream_caps, if fail to get video_sink sink pad*/
8816 if (!caps_v && player->v_stream_caps) {
8817 caps_v = player->v_stream_caps;
8818 gst_caps_ref(caps_v);
8822 LOGD("no negitiated caps from videosink");
8823 gst_object_unref(pad);
8827 p = gst_caps_get_structure(caps_v, 0);
8828 gst_structure_get_int(p, "width", &width);
8829 gst_structure_get_int(p, "height", &height);
8831 mm_player_set_attribute((MMHandleType)player, NULL,
8832 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
8834 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
8836 SECURE_LOGD("width : %d height : %d", width, height);
8838 gst_caps_unref(caps_v);
8839 gst_object_unref(pad);
8842 mm_player_set_attribute((MMHandleType)player, NULL,
8843 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
8844 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
8851 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
8853 gboolean ret = FALSE;
8854 guint64 data_size = 0;
8858 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
8859 if (!player->duration)
8862 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
8863 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
8864 if (stat(path, &sb) == 0)
8865 data_size = (guint64)sb.st_size;
8867 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
8868 data_size = player->http_content_size;
8871 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
8874 guint64 bitrate = 0;
8875 guint64 msec_dur = 0;
8877 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
8879 bitrate = data_size * 8 * 1000 / msec_dur;
8880 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
8881 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
8882 mm_player_set_attribute((MMHandleType)player, NULL,
8883 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
8886 LOGD("player duration is less than 0");
8890 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
8891 if (player->total_bitrate) {
8892 mm_player_set_attribute((MMHandleType)player, NULL,
8893 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
8902 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
8904 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
8905 data->uri_type = uri_type;
8909 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
8911 int ret = MM_ERROR_PLAYER_INVALID_URI;
8913 char *buffer = NULL;
8914 char *seperator = strchr(path, ',');
8915 char ext[100] = {0,}, size[100] = {0,};
8918 if ((buffer = strstr(path, "ext="))) {
8919 buffer += strlen("ext=");
8921 if (strlen(buffer)) {
8922 strncpy(ext, buffer, 99);
8924 if ((seperator = strchr(ext, ','))
8925 || (seperator = strchr(ext, ' '))
8926 || (seperator = strchr(ext, '\0'))) {
8927 seperator[0] = '\0';
8932 if ((buffer = strstr(path, "size="))) {
8933 buffer += strlen("size=");
8935 if (strlen(buffer) > 0) {
8936 strncpy(size, buffer, 99);
8938 if ((seperator = strchr(size, ','))
8939 || (seperator = strchr(size, ' '))
8940 || (seperator = strchr(size, '\0'))) {
8941 seperator[0] = '\0';
8944 mem_size = atoi(size);
8949 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
8951 if (mem_size && param) {
8952 if (data->input_mem.buf)
8953 free(data->input_mem.buf);
8954 data->input_mem.buf = malloc(mem_size);
8956 if (data->input_mem.buf) {
8957 memcpy(data->input_mem.buf, param, mem_size);
8958 data->input_mem.len = mem_size;
8959 ret = MM_ERROR_NONE;
8961 LOGE("failed to alloc mem %d", mem_size);
8962 ret = MM_ERROR_PLAYER_INTERNAL;
8965 data->input_mem.offset = 0;
8966 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
8973 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
8975 gchar *location = NULL;
8978 int ret = MM_ERROR_NONE;
8980 if ((path = strstr(uri, "file://"))) {
8981 location = g_filename_from_uri(uri, NULL, &err);
8982 if (!location || (err != NULL)) {
8983 LOGE("Invalid URI '%s' for filesrc: %s", path,
8984 (err != NULL) ? err->message : "unknown error");
8988 MMPLAYER_FREEIF(location);
8990 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
8991 return MM_ERROR_PLAYER_INVALID_URI;
8993 LOGD("path from uri: %s", location);
8996 path = (location != NULL) ? (location) : ((char *)uri);
8999 ret = _mmplayer_exist_file_path(path);
9001 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9002 if (ret == MM_ERROR_NONE) {
9003 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9004 if (_mmplayer_is_sdp_file(path)) {
9005 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9006 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9008 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9010 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9011 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9013 LOGE("invalid uri, could not play..");
9014 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9017 MMPLAYER_FREEIF(location);
9022 static mmplayer_video_decoded_data_info_t *
9023 __mmplayer_create_stream_from_pad(GstPad *pad)
9025 GstCaps *caps = NULL;
9026 GstStructure *structure = NULL;
9027 unsigned int fourcc = 0;
9028 const gchar *string_format = NULL;
9029 mmplayer_video_decoded_data_info_t *stream = NULL;
9031 MMPixelFormatType format;
9034 caps = gst_pad_get_current_caps(pad);
9036 LOGE("Caps is NULL.");
9041 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9043 structure = gst_caps_get_structure(caps, 0);
9044 gst_structure_get_int(structure, "width", &width);
9045 gst_structure_get_int(structure, "height", &height);
9046 string_format = gst_structure_get_string(structure, "format");
9049 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9050 format = _mmplayer_get_pixtype(fourcc);
9051 gst_video_info_from_caps(&info, caps);
9052 gst_caps_unref(caps);
9055 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9056 LOGE("Wrong condition!!");
9060 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9062 LOGE("failed to alloc mem for video data");
9066 stream->width = width;
9067 stream->height = height;
9068 stream->format = format;
9069 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9075 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9077 unsigned int pitch = 0;
9078 unsigned int size = 0;
9080 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9083 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9084 bo = gst_tizen_memory_get_bos(mem, index);
9086 stream->bo[index] = tbm_bo_ref(bo);
9088 LOGE("failed to get bo for index %d", index);
9091 for (index = 0; index < stream->plane_num; index++) {
9092 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9093 stream->stride[index] = pitch;
9095 stream->elevation[index] = size / pitch;
9097 stream->elevation[index] = stream->height;
9102 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9104 if (stream->format == MM_PIXEL_FORMAT_I420) {
9105 int ret = TBM_SURFACE_ERROR_NONE;
9106 tbm_surface_h surface;
9107 tbm_surface_info_s info;
9109 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9111 ret = tbm_surface_get_info(surface, &info);
9112 if (ret != TBM_SURFACE_ERROR_NONE) {
9113 tbm_surface_destroy(surface);
9117 tbm_surface_destroy(surface);
9118 stream->stride[0] = info.planes[0].stride;
9119 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9120 stream->stride[1] = info.planes[1].stride;
9121 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9122 stream->stride[2] = info.planes[2].stride;
9123 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9124 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9125 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9126 stream->stride[0] = stream->width * 4;
9127 stream->elevation[0] = stream->height;
9128 stream->bo_size = stream->stride[0] * stream->height;
9130 LOGE("Not support format %d", stream->format);
9138 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9140 tbm_bo_handle thandle;
9142 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9143 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9144 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9148 unsigned char *src = NULL;
9149 unsigned char *dest = NULL;
9150 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9152 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9154 LOGE("fail to gst_memory_map");
9158 if (!mapinfo.data) {
9159 LOGE("data pointer is wrong");
9163 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9164 if (!stream->bo[0]) {
9165 LOGE("Fail to tbm_bo_alloc!!");
9169 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9171 LOGE("thandle pointer is wrong");
9175 if (stream->format == MM_PIXEL_FORMAT_I420) {
9176 src_stride[0] = GST_ROUND_UP_4(stream->width);
9177 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9178 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9179 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9182 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9183 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9185 for (i = 0; i < 3; i++) {
9186 src = mapinfo.data + src_offset[i];
9187 dest = thandle.ptr + dest_offset[i];
9192 for (j = 0; j < stream->height >> k; j++) {
9193 memcpy(dest, src, stream->width>>k);
9194 src += src_stride[i];
9195 dest += stream->stride[i];
9198 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9199 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9201 LOGE("Not support format %d", stream->format);
9205 tbm_bo_unmap(stream->bo[0]);
9206 gst_memory_unmap(mem, &mapinfo);
9212 tbm_bo_unmap(stream->bo[0]);
9215 gst_memory_unmap(mem, &mapinfo);
9221 __mmplayer_set_pause_state(mmplayer_t *player)
9223 if (player->sent_bos)
9226 /* rtsp case, get content attrs by GstMessage */
9227 if (MMPLAYER_IS_RTSP_STREAMING(player))
9230 /* it's first time to update all content attrs. */
9231 _mmplayer_update_content_attrs(player, ATTR_ALL);
9235 __mmplayer_set_playing_state(mmplayer_t *player)
9237 gchar *audio_codec = NULL;
9239 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9240 /* initialize because auto resume is done well. */
9241 player->resumed_by_rewind = FALSE;
9242 player->playback_rate = 1.0;
9245 if (player->sent_bos)
9248 /* try to get content metadata */
9250 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9251 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9252 * legacy mmfw-player api
9254 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9256 if ((player->cmd == MMPLAYER_COMMAND_START)
9257 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9258 __mmplayer_handle_missed_plugin(player);
9261 /* check audio codec field is set or not
9262 * we can get it from typefinder or codec's caps.
9264 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9266 /* The codec format can't be sent for audio only case like amr, mid etc.
9267 * Because, parser don't make related TAG.
9268 * So, if it's not set yet, fill it with found data.
9271 if (g_strrstr(player->type, "audio/midi"))
9272 audio_codec = "MIDI";
9273 else if (g_strrstr(player->type, "audio/x-amr"))
9274 audio_codec = "AMR";
9275 else if (g_strrstr(player->type, "audio/mpeg")
9276 && !g_strrstr(player->type, "mpegversion=(int)1"))
9277 audio_codec = "AAC";
9279 audio_codec = "unknown";
9281 if (mm_player_set_attribute((MMHandleType)player, NULL,
9282 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9283 LOGE("failed to set attribute");
9285 LOGD("set audio codec type with caps");