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_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related function will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
143 static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
144 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void __mmplayer_release_misc(mmplayer_t *player);
150 static void __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
160 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
161 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
162 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
163 static gpointer __mmplayer_gapless_play_thread(gpointer data);
164 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
165 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_release_dump_list(GList *dump_list);
167 static int __mmplayer_gst_realize(mmplayer_t *player);
168 static int __mmplayer_gst_unrealize(mmplayer_t *player);
169 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
170 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
173 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
174 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
175 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
176 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
177 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
178 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
179 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
180 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
181 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
182 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
183 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
184 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
188 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
189 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
190 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
192 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
193 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
194 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
195 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
197 static void __mmplayer_set_pause_state(mmplayer_t *player);
198 static void __mmplayer_set_playing_state(mmplayer_t *player);
199 static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
200 /*===========================================================================================
202 | FUNCTION DEFINITIONS |
204 ========================================================================================== */
206 /* This function should be called after the pipeline goes PAUSED or higher
209 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
211 static gboolean has_duration = FALSE;
212 static gboolean has_video_attrs = FALSE;
213 static gboolean has_audio_attrs = FALSE;
214 static gboolean has_bitrate = FALSE;
215 gboolean missing_only = FALSE;
216 gboolean all = FALSE;
217 MMHandleType attrs = 0;
221 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
223 /* check player state here */
224 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
225 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
226 /* give warning now only */
227 LOGW("be careful. content attributes may not available in this state ");
230 /* get content attribute first */
231 attrs = MMPLAYER_GET_ATTRS(player);
233 LOGE("cannot get content attribute");
237 /* get update flag */
239 if (flag & ATTR_MISSING_ONLY) {
241 LOGD("updating missed attr only");
244 if (flag & ATTR_ALL) {
246 has_duration = FALSE;
247 has_video_attrs = FALSE;
248 has_audio_attrs = FALSE;
251 LOGD("updating all attrs");
254 if (missing_only && all) {
255 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
256 missing_only = FALSE;
259 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
260 has_duration = __mmplayer_update_duration_value(player);
262 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
263 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
265 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
266 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
268 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
269 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
277 _mmplayer_get_stream_service_type(mmplayer_t *player)
279 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
283 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
285 player->pipeline->mainbin &&
286 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
287 STREAMING_SERVICE_NONE);
289 /* streaming service type if streaming */
290 if (!MMPLAYER_IS_STREAMING(player))
291 return STREAMING_SERVICE_NONE;
293 streaming_type = (player->duration == 0) ?
294 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
296 switch (streaming_type) {
297 case STREAMING_SERVICE_LIVE:
298 LOGD("it's live streaming");
300 case STREAMING_SERVICE_VOD:
301 LOGD("it's vod streaming");
304 LOGE("should not get here");
310 return streaming_type;
313 /* this function sets the player state and also report
314 * it to application by calling callback function
317 _mmplayer_set_state(mmplayer_t *player, int state)
319 MMMessageParamType msg = {0, };
321 MMPLAYER_RETURN_IF_FAIL(player);
323 if (MMPLAYER_CURRENT_STATE(player) == state) {
324 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
325 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
329 /* update player states */
330 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
331 MMPLAYER_CURRENT_STATE(player) = state;
333 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
334 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
337 MMPLAYER_PRINT_STATE(player);
339 switch (MMPLAYER_CURRENT_STATE(player)) {
340 case MM_PLAYER_STATE_NULL:
341 case MM_PLAYER_STATE_READY:
343 case MM_PLAYER_STATE_PAUSED:
344 __mmplayer_set_pause_state(player);
346 case MM_PLAYER_STATE_PLAYING:
347 __mmplayer_set_playing_state(player);
349 case MM_PLAYER_STATE_NONE:
351 LOGW("invalid target state, there is nothing to do.");
356 /* post message to application */
357 if (MMPLAYER_TARGET_STATE(player) == state) {
358 /* fill the message with state of player */
359 msg.union_type = MM_MSG_UNION_STATE;
360 msg.state.previous = MMPLAYER_PREV_STATE(player);
361 msg.state.current = MMPLAYER_CURRENT_STATE(player);
363 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
365 /* state changed by resource callback */
366 if (player->interrupted_by_resource)
367 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
368 else /* state changed by usecase */
369 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
372 LOGD("intermediate state, do nothing.");
373 MMPLAYER_PRINT_STATE(player);
377 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
378 && !player->sent_bos) {
379 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
380 player->sent_bos = TRUE;
387 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
389 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
390 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
394 LOGD("incoming command : %d ", command);
396 current_state = MMPLAYER_CURRENT_STATE(player);
397 pending_state = MMPLAYER_PENDING_STATE(player);
399 MMPLAYER_PRINT_STATE(player);
402 case MMPLAYER_COMMAND_CREATE:
404 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
406 if (current_state == MM_PLAYER_STATE_NULL ||
407 current_state == MM_PLAYER_STATE_READY ||
408 current_state == MM_PLAYER_STATE_PAUSED ||
409 current_state == MM_PLAYER_STATE_PLAYING)
414 case MMPLAYER_COMMAND_DESTROY:
416 /* destroy can called anytime */
418 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
422 case MMPLAYER_COMMAND_REALIZE:
424 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
426 if (pending_state != MM_PLAYER_STATE_NONE) {
429 /* need ready state to realize */
430 if (current_state == MM_PLAYER_STATE_READY)
433 if (current_state != MM_PLAYER_STATE_NULL)
439 case MMPLAYER_COMMAND_UNREALIZE:
441 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
443 if (current_state == MM_PLAYER_STATE_NULL)
448 case MMPLAYER_COMMAND_START:
450 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
452 if (pending_state == MM_PLAYER_STATE_NONE) {
453 if (current_state == MM_PLAYER_STATE_PLAYING)
455 else if (current_state != MM_PLAYER_STATE_READY &&
456 current_state != MM_PLAYER_STATE_PAUSED)
458 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
460 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
461 LOGD("player is going to paused state, just change the pending state as playing");
468 case MMPLAYER_COMMAND_STOP:
470 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
472 if (current_state == MM_PLAYER_STATE_READY)
475 /* need playing/paused state to stop */
476 if (current_state != MM_PLAYER_STATE_PLAYING &&
477 current_state != MM_PLAYER_STATE_PAUSED)
482 case MMPLAYER_COMMAND_PAUSE:
484 if (MMPLAYER_IS_LIVE_STREAMING(player))
487 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
488 goto NOT_COMPLETED_SEEK;
490 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
492 if (pending_state == MM_PLAYER_STATE_NONE) {
493 if (current_state == MM_PLAYER_STATE_PAUSED)
495 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
497 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
499 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
500 if (current_state == MM_PLAYER_STATE_PAUSED)
501 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
508 case MMPLAYER_COMMAND_RESUME:
510 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
511 goto NOT_COMPLETED_SEEK;
513 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
515 if (pending_state == MM_PLAYER_STATE_NONE) {
516 if (current_state == MM_PLAYER_STATE_PLAYING)
518 else if (current_state != MM_PLAYER_STATE_PAUSED)
520 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
522 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
523 LOGD("player is going to paused state, just change the pending state as playing");
533 player->cmd = command;
535 return MM_ERROR_NONE;
538 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
539 MMPLAYER_STATE_GET_NAME(current_state), command);
540 return MM_ERROR_PLAYER_INVALID_STATE;
543 LOGW("not completed seek");
544 return MM_ERROR_PLAYER_DOING_SEEK;
547 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
548 return MM_ERROR_PLAYER_NO_OP;
551 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
552 return MM_ERROR_PLAYER_NO_OP;
555 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
557 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
558 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
561 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
562 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
564 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
565 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
567 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
568 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
571 LOGE("invalid mmplayer resource type %d", type);
572 return MM_ERROR_PLAYER_INTERNAL;
575 if (player->hw_resource[type] != NULL) {
576 LOGD("[%d type] resource was already acquired", type);
577 return MM_ERROR_NONE;
580 LOGD("mark for acquire [%d type] resource", type);
581 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
582 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
583 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
584 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
585 return MM_ERROR_PLAYER_INTERNAL;
588 LOGD("commit [%d type] resource", type);
589 rm_ret = mm_resource_manager_commit(player->resource_manager);
590 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
591 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
592 return MM_ERROR_PLAYER_INTERNAL;
596 return MM_ERROR_NONE;
599 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
601 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
603 MMPLAYER_RETURN_IF_FAIL(player);
604 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
606 rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
607 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
608 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
612 rm_ret = mm_resource_manager_commit(player->resource_manager);
613 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
614 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
617 /* de-initialize resource manager */
618 rm_ret = mm_resource_manager_destroy(player->resource_manager);
619 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
620 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
624 player->resource_manager = NULL;
626 LOGD("resource manager is destroyed");
629 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
631 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
635 if (player->hw_resource[type] == NULL) {
636 LOGD("there is no acquired [%d type] resource", type);
637 return MM_ERROR_NONE;
640 LOGD("mark for release [%d type] resource", type);
641 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
642 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
643 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
644 return MM_ERROR_PLAYER_INTERNAL;
647 player->hw_resource[type] = NULL;
649 LOGD("commit [%d type] resource", type);
650 rm_ret = mm_resource_manager_commit(player->resource_manager);
651 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
652 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
653 return MM_ERROR_PLAYER_INTERNAL;
657 return MM_ERROR_NONE;
661 __mmplayer_initialize_gapless_play(mmplayer_t *player)
667 player->smooth_streaming = FALSE;
668 player->videodec_linked = 0;
669 player->audiodec_linked = 0;
670 player->textsink_linked = 0;
671 player->is_external_subtitle_present = FALSE;
672 player->is_external_subtitle_added_now = FALSE;
673 player->not_supported_codec = MISSING_PLUGIN_NONE;
674 player->can_support_codec = FOUND_PLUGIN_NONE;
675 player->pending_seek.is_pending = false;
676 player->pending_seek.pos = 0;
677 player->msg_posted = FALSE;
678 player->has_many_types = FALSE;
679 player->no_more_pad = FALSE;
680 player->not_found_demuxer = 0;
681 player->seek_state = MMPLAYER_SEEK_NONE;
682 player->is_subtitle_force_drop = FALSE;
683 player->play_subtitle = FALSE;
684 player->adjust_subtitle_pos = 0;
686 player->total_bitrate = 0;
687 player->total_maximum_bitrate = 0;
689 _mmplayer_track_initialize(player);
690 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
692 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
693 player->bitrate[i] = 0;
694 player->maximum_bitrate[i] = 0;
697 if (player->v_stream_caps) {
698 gst_caps_unref(player->v_stream_caps);
699 player->v_stream_caps = NULL;
702 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
704 /* clean found audio decoders */
705 if (player->audio_decoders) {
706 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
707 player->audio_decoders = NULL;
710 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
715 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
717 LOGI("set pipeline reconfigure state %d", state);
718 MMPLAYER_RECONFIGURE_LOCK(player);
719 player->gapless.reconfigure = state;
720 if (!state) /* wake up the waiting job */
721 MMPLAYER_RECONFIGURE_SIGNAL(player);
722 MMPLAYER_RECONFIGURE_UNLOCK(player);
726 __mmplayer_gapless_play_thread(gpointer data)
728 mmplayer_t *player = (mmplayer_t *)data;
729 mmplayer_gst_element_t *mainbin = NULL;
731 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
733 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
734 while (!player->gapless_play_thread_exit) {
735 LOGD("gapless play thread started. waiting for signal.");
736 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
738 LOGD("reconfigure pipeline for gapless play.");
740 if (player->gapless_play_thread_exit) {
741 _mmplayer_set_reconfigure_state(player, FALSE);
742 LOGD("exiting gapless play thread");
746 mainbin = player->pipeline->mainbin;
748 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
749 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
752 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
754 /* Initialize Player values */
755 __mmplayer_initialize_gapless_play(player);
757 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
759 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
765 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
767 GSource *source = NULL;
771 source = g_main_context_find_source_by_id(context, source_id);
772 if (source != NULL) {
773 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
774 g_source_destroy(source);
781 _mmplayer_watcher_removed_notify(gpointer data)
783 mmplayer_t *player = (mmplayer_t *)data;
784 MMPLAYER_RETURN_IF_FAIL(player);
786 MMPLAYER_BUS_WATCHER_LOCK(player);
787 player->bus_watcher = 0;
788 MMPLAYER_BUS_WATCHER_SIGNAL(player);
789 MMPLAYER_BUS_WATCHER_UNLOCK(player);
793 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
795 mmplayer_t *player = (mmplayer_t *)hplayer;
798 MMPLAYER_RETURN_IF_FAIL(player);
800 /* disconnecting bus watch */
801 if (player->bus_watcher > 0) {
802 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
803 MMPLAYER_BUS_WATCHER_LOCK(player);
804 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
805 while (player->bus_watcher > 0) {
806 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
807 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
808 player->bus_watcher);
812 MMPLAYER_BUS_WATCHER_UNLOCK(player);
813 g_mutex_clear(&player->bus_watcher_mutex);
814 g_cond_clear(&player->bus_watcher_cond);
821 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
823 mmplayer_t *player = (mmplayer_t *)hplayer;
824 GstMessage *msg = NULL;
825 GQueue *queue = NULL;
828 MMPLAYER_RETURN_IF_FAIL(player);
830 /* destroy the gst bus msg thread */
831 if (player->bus_msg_thread) {
832 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
833 player->bus_msg_thread_exit = TRUE;
834 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
835 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
837 LOGD("gst bus msg thread exit.");
838 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
839 player->bus_msg_thread = NULL;
841 g_mutex_clear(&player->bus_msg_thread_mutex);
842 g_cond_clear(&player->bus_msg_thread_cond);
845 g_mutex_lock(&player->bus_msg_q_lock);
846 queue = player->bus_msg_q;
847 while (!g_queue_is_empty(queue)) {
848 msg = (GstMessage *)g_queue_pop_head(queue);
853 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
854 gst_message_unref(msg);
856 g_mutex_unlock(&player->bus_msg_q_lock);
862 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
864 GstElement *parent = NULL;
866 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
867 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
870 MMPLAYER_FSINK_LOCK(player);
872 /* get parent of fakesink */
873 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
875 LOGD("fakesink already removed");
879 gst_element_set_locked_state(fakesink->gst, TRUE);
881 /* setting the state to NULL never returns async
882 * so no need to wait for completion of state transition
884 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
885 LOGE("fakesink state change failure!");
886 /* FIXIT : should I return here? or try to proceed to next? */
889 /* remove fakesink from it's parent */
890 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
891 LOGE("failed to remove fakesink");
893 gst_object_unref(parent);
898 gst_object_unref(parent);
900 LOGD("state-holder removed");
902 gst_element_set_locked_state(fakesink->gst, FALSE);
904 MMPLAYER_FSINK_UNLOCK(player);
909 gst_element_set_locked_state(fakesink->gst, FALSE);
911 MMPLAYER_FSINK_UNLOCK(player);
915 static GstPadProbeReturn
916 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
918 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
919 return GST_PAD_PROBE_OK;
923 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
925 gint64 stop_running_time = 0;
926 gint64 position_running_time = 0;
930 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
931 if ((player->gapless.update_segment[idx] == TRUE) ||
932 !(player->track[idx].event_probe_id)) {
934 LOGW("[%d] skip", idx);
939 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
941 gst_segment_to_running_time(&player->gapless.segment[idx],
942 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
943 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
945 gst_segment_to_running_time(&player->gapless.segment[idx],
946 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
948 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
950 gst_segment_to_running_time(&player->gapless.segment[idx],
951 GST_FORMAT_TIME, player->duration);
954 position_running_time =
955 gst_segment_to_running_time(&player->gapless.segment[idx],
956 GST_FORMAT_TIME, player->gapless.segment[idx].position);
958 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
959 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
961 GST_TIME_ARGS(stop_running_time),
962 GST_TIME_ARGS(position_running_time),
963 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
964 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
966 position_running_time = MAX(position_running_time, stop_running_time);
967 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
968 GST_FORMAT_TIME, player->gapless.segment[idx].start);
969 position_running_time = MAX(0, position_running_time);
970 position = MAX(position, position_running_time);
974 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
975 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
976 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
978 player->gapless.start_time[stream_type] += position;
984 static GstPadProbeReturn
985 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
987 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
988 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
989 mmplayer_t *player = (mmplayer_t *)data;
990 GstCaps *caps = NULL;
991 GstStructure *str = NULL;
992 const gchar *name = NULL;
993 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
994 gboolean caps_ret = TRUE;
996 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
997 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
998 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
999 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1000 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1003 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1007 if (strstr(name, "audio")) {
1008 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1009 } else if (strstr(name, "video")) {
1010 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1012 /* text track is not supportable */
1013 LOGE("invalid name %s", name);
1017 switch (GST_EVENT_TYPE(event)) {
1020 /* in case of gapless, drop eos event not to send it to sink */
1021 if (player->gapless.reconfigure && !player->msg_posted) {
1022 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1023 ret = GST_PAD_PROBE_DROP;
1027 case GST_EVENT_STREAM_START:
1029 __mmplayer_gst_selector_update_start_time(player, stream_type);
1032 case GST_EVENT_FLUSH_STOP:
1034 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1035 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1036 player->gapless.start_time[stream_type] = 0;
1039 case GST_EVENT_SEGMENT:
1044 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1045 gst_event_copy_segment(event, &segment);
1047 if (segment.format != GST_FORMAT_TIME)
1050 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1051 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1052 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1053 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1054 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1055 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1057 /* keep the all the segment ev to cover the seeking */
1058 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1059 player->gapless.update_segment[stream_type] = TRUE;
1061 if (!player->gapless.running)
1064 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1066 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1068 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1069 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1070 gst_event_unref(event);
1071 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1077 gdouble proportion = 0.0;
1078 GstClockTimeDiff diff = 0;
1079 GstClockTime timestamp = 0;
1080 gint64 running_time_diff = -1;
1081 GstQOSType type = 0;
1082 GstEvent *tmpev = NULL;
1084 running_time_diff = player->gapless.segment[stream_type].base;
1086 if (running_time_diff <= 0) /* don't need to adjust */
1089 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1090 gst_event_unref(event);
1092 if (timestamp < running_time_diff) {
1093 LOGW("QOS event from previous group");
1094 ret = GST_PAD_PROBE_DROP;
1099 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1100 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1101 stream_type, GST_TIME_ARGS(timestamp),
1102 GST_TIME_ARGS(running_time_diff),
1103 GST_TIME_ARGS(timestamp - running_time_diff));
1106 timestamp -= running_time_diff;
1108 /* That case is invalid for QoS events */
1109 if (diff < 0 && -diff > timestamp) {
1110 LOGW("QOS event from previous group");
1111 ret = GST_PAD_PROBE_DROP;
1115 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1116 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1126 gst_caps_unref(caps);
1130 /* create fakesink for audio or video path without audiobin or videobin */
1132 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1134 GstElement *pipeline = NULL;
1135 GstElement *fakesink = NULL;
1136 GstPad *sinkpad = NULL;
1139 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1141 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1144 fakesink = gst_element_factory_make("fakesink", NULL);
1145 if (fakesink == NULL) {
1146 LOGE("failed to create fakesink");
1150 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1151 LOGE("failed to add fakesink to pipeline");
1156 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1158 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1160 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1161 LOGE("failed to link fakesink");
1165 if (strstr(name, "video")) {
1166 if (player->v_stream_caps) {
1167 gst_caps_unref(player->v_stream_caps);
1168 player->v_stream_caps = NULL;
1170 if (player->ini.set_dump_element_flag)
1171 __mmplayer_add_dump_buffer_probe(player, fakesink);
1174 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1175 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1177 /* store it as it's sink element */
1178 __mmplayer_add_sink(player, fakesink, FALSE);
1181 gst_object_unref(GST_OBJECT(sinkpad));
1189 gst_object_unref(GST_OBJECT(sinkpad));
1192 gst_element_set_state(fakesink, GST_STATE_NULL);
1194 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1195 gst_object_unref(GST_OBJECT(fakesink));
1202 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1204 GstElement *pipeline = NULL;
1205 GstElement *concat = NULL;
1208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1210 concat = gst_element_factory_make("concat", NULL);
1212 LOGE("failed to create concat");
1216 gst_element_set_state(concat, GST_STATE_PAUSED);
1218 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1219 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1220 LOGE("failed to add concat to pipeline");
1221 gst_element_set_state(concat, GST_STATE_NULL);
1222 gst_object_unref(GST_OBJECT(concat));
1226 LOGD("Create concat [%d] element", elem_idx);
1228 player->pipeline->mainbin[elem_idx].id = elem_idx;
1229 player->pipeline->mainbin[elem_idx].gst = concat;
1236 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1238 GstElement *pipeline = NULL;
1239 GstElement *selector = NULL;
1240 GstPad *srcpad = NULL;
1243 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1245 selector = gst_element_factory_make("input-selector", NULL);
1247 LOGE("failed to create input-selector");
1250 g_object_set(selector, "sync-streams", TRUE, NULL);
1252 srcpad = gst_element_get_static_pad(selector, "src");
1254 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1255 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1256 __mmplayer_gst_selector_blocked, NULL, NULL);
1257 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1258 __mmplayer_gst_selector_event_probe, player, NULL);
1260 gst_element_set_state(selector, GST_STATE_PAUSED);
1262 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1263 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1264 LOGE("failed to add selector to pipeline");
1266 if (player->track[stream_type].block_id != 0)
1267 gst_pad_remove_probe (srcpad, player->track[stream_type].block_id);
1268 player->track[stream_type].block_id = 0;
1270 if (player->track[stream_type].event_probe_id != 0)
1271 gst_pad_remove_probe (srcpad, player->track[stream_type].event_probe_id);
1272 player->track[stream_type].event_probe_id = 0;
1274 gst_object_unref(GST_OBJECT(srcpad));
1276 gst_element_set_state(selector, GST_STATE_NULL);
1277 gst_object_unref(GST_OBJECT(selector));
1281 gst_object_unref(GST_OBJECT(srcpad));
1283 player->pipeline->mainbin[elem_idx].id = elem_idx;
1284 player->pipeline->mainbin[elem_idx].gst = selector;
1291 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1293 mmplayer_t *player = (mmplayer_t *)data;
1294 GstElement *combiner = NULL;
1295 GstCaps *caps = NULL;
1296 GstStructure *str = NULL;
1297 const gchar *name = NULL;
1298 GstPad *sinkpad = NULL;
1299 gboolean first_track = FALSE;
1300 gboolean caps_ret = TRUE;
1302 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1303 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1306 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1307 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1309 LOGD("pad-added signal handling");
1311 /* get mimetype from caps */
1312 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1316 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1318 LOGD("detected mimetype : %s", name);
1321 if (strstr(name, "video")) {
1323 gchar *caps_str = NULL;
1325 caps_str = gst_caps_to_string(caps);
1326 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1327 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1328 player->set_mode.video_zc = true;
1330 MMPLAYER_FREEIF(caps_str);
1332 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1333 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1335 LOGD("surface type : %d", stype);
1337 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1338 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1342 /* in case of exporting video frame, it requires the 360 video filter.
1343 * it will be handled in _no_more_pads(). */
1344 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1345 __mmplayer_gst_make_fakesink(player, pad, name);
1349 if (MMPLAYER_USE_DECODEBIN(player)) {
1350 LOGD("video selector is required");
1351 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1353 LOGD("video concat is required");
1354 elem_idx = MMPLAYER_M_V_CONCAT;
1356 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1357 } else if (strstr(name, "audio")) {
1358 gint samplerate = 0;
1361 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1362 if (player->build_audio_offload)
1363 player->no_more_pad = TRUE; /* remove state holder */
1364 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1368 gst_structure_get_int(str, "rate", &samplerate);
1369 gst_structure_get_int(str, "channels", &channels);
1371 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1372 __mmplayer_gst_make_fakesink(player, pad, name);
1375 if (MMPLAYER_USE_DECODEBIN(player)) {
1376 LOGD("audio selector is required");
1377 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1379 LOGD("audio concat is required");
1380 elem_idx = MMPLAYER_M_A_CONCAT;
1382 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1384 } else if (strstr(name, "text")) {
1385 if (MMPLAYER_USE_DECODEBIN(player)) {
1386 LOGD("text selector is required");
1387 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1389 LOGD("text concat is required");
1390 elem_idx = MMPLAYER_M_T_CONCAT;
1392 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1394 LOGE("invalid caps info");
1398 /* check selector and create it */
1399 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1400 if (MMPLAYER_USE_DECODEBIN(player))
1401 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1403 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1409 LOGD("Combiner element is already created.");
1413 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1415 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1417 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1418 LOGE("failed to link combiner");
1419 gst_object_unref(GST_OBJECT(combiner));
1424 if (MMPLAYER_USE_DECODEBIN(player)) {
1425 LOGD("this track will be activated");
1426 g_object_set(combiner, "active-pad", sinkpad, NULL);
1430 if (MMPLAYER_USE_DECODEBIN(player)) {
1431 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1433 /* apply the text track information */
1434 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1435 mm_player_set_attribute((MMHandleType)player, NULL,
1436 "content_text_track_num", player->track[stream_type].total_track_num,
1437 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1438 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1445 gst_caps_unref(caps);
1448 gst_object_unref(GST_OBJECT(sinkpad));
1456 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1458 GstPad *srcpad = NULL;
1461 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1463 LOGD("type %d", type);
1466 LOGD("there is no %d track", type);
1470 srcpad = gst_element_get_static_pad(combiner, "src");
1472 LOGE("failed to get srcpad from combiner");
1476 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1478 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1480 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1481 if (player->track[type].block_id) {
1482 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1483 player->track[type].block_id = 0;
1487 gst_object_unref(GST_OBJECT(srcpad));
1496 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1498 gint active_index = 0;
1501 MMPLAYER_RETURN_IF_FAIL(player);
1503 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1505 /* change track to active pad */
1506 active_index = player->track[type].active_track_index;
1507 if ((active_index != DEFAULT_TRACK_INDEX) &&
1508 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1509 LOGW("failed to change %d type track to %d", type, active_index);
1510 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1514 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1515 mm_player_set_attribute((MMHandleType)player, NULL,
1516 "content_text_track_num", player->track[type].total_track_num,
1517 "current_text_track_index", player->track[type].active_track_index, NULL);
1524 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1527 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1529 if (!audio_selector) {
1530 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1532 /* in case the source is changed, output can be changed. */
1533 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1534 LOGD("remove previous audiobin if it exist");
1536 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1537 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1539 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1540 MMPLAYER_FREEIF(player->pipeline->audiobin);
1543 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1544 _mmplayer_pipeline_complete(NULL, player);
1549 /* apply the audio track information */
1550 if (MMPLAYER_USE_DECODEBIN(player))
1551 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1553 /* create audio sink path */
1554 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1555 LOGE("failed to create audio sink path");
1564 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1567 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1569 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1570 LOGD("text path is not supported");
1574 /* apply the text track information */
1575 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1577 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1578 player->has_closed_caption = TRUE;
1580 /* create text decode path */
1581 player->no_more_pad = TRUE;
1583 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1584 LOGE("failed to create text sink path");
1593 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1595 gint64 dur_bytes = 0L;
1598 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1599 player->pipeline->mainbin && player->streamer, FALSE);
1601 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1602 LOGE("fail to get duration.");
1604 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1605 * use file information was already set on Q2 when it was created. */
1606 _mm_player_streaming_set_queue2(player->streamer,
1607 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1608 TRUE, /* use_buffering */
1609 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1610 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1617 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1619 mmplayer_t *player = NULL;
1620 GstElement *video_selector = NULL;
1621 GstElement *audio_selector = NULL;
1622 GstElement *text_selector = NULL;
1625 player = (mmplayer_t *)data;
1627 LOGD("no-more-pad signal handling");
1629 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1630 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1631 LOGW("player is shutting down");
1635 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1636 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1637 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1638 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1639 LOGE("failed to set queue2 buffering");
1644 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1645 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1646 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1648 if (!video_selector && !audio_selector && !text_selector) {
1649 LOGW("there is no selector");
1650 player->no_more_pad = TRUE;
1654 /* create video path followed by video-select */
1655 if (video_selector && !audio_selector && !text_selector)
1656 player->no_more_pad = TRUE;
1658 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1661 /* create audio path followed by audio-select */
1662 if (audio_selector && !text_selector)
1663 player->no_more_pad = TRUE;
1665 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1668 /* create text path followed by text-select */
1669 __mmplayer_create_text_sink_path(player, text_selector);
1672 _mmplayer_set_reconfigure_state(player, FALSE);
1677 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1679 gboolean ret = FALSE;
1680 GstElement *pipeline = NULL;
1681 GstPad *sinkpad = NULL;
1684 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1685 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1687 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1689 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1691 LOGE("failed to get pad from sinkbin");
1697 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1698 LOGE("failed to link sinkbin for reusing");
1699 goto EXIT; /* exit either pass or fail */
1703 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1704 LOGE("failed to set state(READY) to sinkbin");
1709 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1710 LOGE("failed to add sinkbin to pipeline");
1715 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1716 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1721 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1722 LOGE("failed to set state(PAUSED) to sinkbin");
1731 gst_object_unref(GST_OBJECT(sinkpad));
1739 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1741 mmplayer_t *player = NULL;
1742 GstCaps *caps = NULL;
1743 gchar *caps_str = NULL;
1744 GstStructure *str = NULL;
1745 const gchar *name = NULL;
1746 GstElement *sinkbin = NULL;
1747 gboolean reusing = FALSE;
1748 gboolean caps_ret = TRUE;
1749 gchar *sink_pad_name = "sink";
1752 player = (mmplayer_t *)data;
1755 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1756 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1757 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1759 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1763 gst_caps_unref(caps);
1764 caps = gst_caps_ref(ref_caps);
1767 caps_str = gst_caps_to_string(caps);
1769 LOGD("detected mimetype : %s", name);
1771 if (strstr(name, "audio")) {
1772 if (player->pipeline->audiobin == NULL) {
1773 const gchar *audio_format = gst_structure_get_string(str, "format");
1775 LOGD("original audio format %s", audio_format);
1776 mm_player_set_attribute((MMHandleType)player, NULL,
1777 "content_audio_format", audio_format, strlen(audio_format), NULL);
1780 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1781 LOGE("failed to create audiobin. continuing without audio");
1785 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1786 LOGD("creating audiobin success");
1789 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1790 LOGD("reusing audiobin");
1791 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1793 } else if (strstr(name, "video")) {
1794 /* 1. zero copy is updated at _decode_pad_added()
1795 * 2. NULL surface type is handled in _decode_pad_added() */
1796 LOGD("zero copy %d", player->set_mode.video_zc);
1797 if (player->pipeline->videobin == NULL) {
1798 int surface_type = 0;
1799 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1800 LOGD("display_surface_type (%d)", surface_type);
1802 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1803 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1804 LOGE("failed to acquire video overlay resource");
1808 player->interrupted_by_resource = FALSE;
1810 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1811 LOGE("failed to create videobin. continuing without video");
1815 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1816 LOGD("creating videosink bin success");
1819 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1820 LOGD("re-using videobin");
1821 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1823 } else if (strstr(name, "text")) {
1824 if (player->pipeline->textbin == NULL) {
1825 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1826 LOGE("failed to create text sink bin. continuing without text");
1830 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1831 player->textsink_linked = 1;
1832 LOGD("creating textsink bin success");
1834 if (!player->textsink_linked) {
1835 LOGD("re-using textbin");
1837 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1838 player->textsink_linked = 1;
1840 /* linked textbin exist which means that the external subtitle path exist already */
1841 LOGW("ignoring internal subtitle since external subtitle is available");
1844 sink_pad_name = "text_sink";
1846 LOGW("unknown mime type %s, ignoring it", name);
1850 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1853 LOGD("[handle: %p] success to create and link sink bin", player);
1855 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1856 * streaming task. if the task blocked, then buffer will not flow to the next element
1857 *(autoplugging element). so this is special hack for streaming. please try to remove it
1859 /* dec stream count. we can remove fakesink if it's zero */
1860 if (player->num_dynamic_pad)
1861 player->num_dynamic_pad--;
1863 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1865 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1866 _mmplayer_pipeline_complete(NULL, player);
1870 MMPLAYER_FREEIF(caps_str);
1873 gst_caps_unref(caps);
1879 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1881 int required_angle = 0; /* Angle required for straight view */
1882 int rotation_angle = 0;
1884 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1885 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1887 /* Counter clockwise */
1888 switch (orientation) {
1893 required_angle = 270;
1896 required_angle = 180;
1899 required_angle = 90;
1903 rotation_angle = display_angle + required_angle;
1904 if (rotation_angle >= 360)
1905 rotation_angle -= 360;
1907 /* check if supported or not */
1908 if (rotation_angle % 90) {
1909 LOGD("not supported rotation angle = %d", rotation_angle);
1913 switch (rotation_angle) {
1915 *value = MM_DISPLAY_ROTATION_NONE;
1918 *value = MM_DISPLAY_ROTATION_90;
1921 *value = MM_DISPLAY_ROTATION_180;
1924 *value = MM_DISPLAY_ROTATION_270;
1928 LOGD("setting rotation property value : %d", *value);
1934 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1936 int display_rotation = 0;
1937 gchar *org_orient = NULL;
1938 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1941 LOGE("cannot get content attribute");
1942 return MM_ERROR_PLAYER_INTERNAL;
1945 if (display_angle) {
1946 /* update user rotation */
1947 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1949 /* Counter clockwise */
1950 switch (display_rotation) {
1951 case MM_DISPLAY_ROTATION_NONE:
1954 case MM_DISPLAY_ROTATION_90:
1955 *display_angle = 90;
1957 case MM_DISPLAY_ROTATION_180:
1958 *display_angle = 180;
1960 case MM_DISPLAY_ROTATION_270:
1961 *display_angle = 270;
1964 LOGW("wrong angle type : %d", display_rotation);
1967 LOGD("check user angle: %d", *display_angle);
1971 /* Counter clockwise */
1972 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1975 if (!strcmp(org_orient, "rotate-90"))
1977 else if (!strcmp(org_orient, "rotate-180"))
1979 else if (!strcmp(org_orient, "rotate-270"))
1982 LOGD("original rotation is %s", org_orient);
1984 LOGD("content_video_orientation get fail");
1987 LOGD("check orientation: %d", *orientation);
1990 return MM_ERROR_NONE;
1993 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1995 int rotation_value = 0;
1996 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1997 int display_angle = 0;
2000 /* check video sinkbin is created */
2001 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2004 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2006 /* get rotation value to set */
2007 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2008 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2009 LOGD("set video param : rotate %d", rotation_value);
2012 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2014 MMHandleType attrs = 0;
2018 /* check video sinkbin is created */
2019 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2020 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2023 attrs = MMPLAYER_GET_ATTRS(player);
2024 MMPLAYER_RETURN_IF_FAIL(attrs);
2026 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2027 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2028 LOGD("set video param : visible %d", visible);
2031 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2033 MMHandleType attrs = 0;
2034 int display_method = 0;
2037 /* check video sinkbin is created */
2038 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2041 attrs = MMPLAYER_GET_ATTRS(player);
2042 MMPLAYER_RETURN_IF_FAIL(attrs);
2044 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2045 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2046 LOGD("set video param : method %d", display_method);
2049 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2051 MMHandleType attrs = 0;
2055 /* check video sinkbin is created */
2056 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2059 attrs = MMPLAYER_GET_ATTRS(player);
2060 MMPLAYER_RETURN_IF_FAIL(attrs);
2062 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2063 MMPLAYER_RETURN_IF_FAIL(handle);
2065 gst_video_overlay_set_video_roi_area(
2066 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2067 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2068 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2069 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2072 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2074 MMHandleType attrs = 0;
2079 int win_roi_width = 0;
2080 int win_roi_height = 0;
2083 /* check video sinkbin is created */
2084 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2087 attrs = MMPLAYER_GET_ATTRS(player);
2088 MMPLAYER_RETURN_IF_FAIL(attrs);
2090 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2091 MMPLAYER_RETURN_IF_FAIL(handle);
2093 /* It should be set after setting window */
2094 mm_attrs_multiple_get(attrs, NULL,
2095 "display_win_roi_x", &win_roi_x,
2096 "display_win_roi_y", &win_roi_y,
2097 "display_win_roi_width", &win_roi_width,
2098 "display_win_roi_height", &win_roi_height, NULL);
2100 /* After setting window handle, set display roi area */
2101 gst_video_overlay_set_display_roi_area(
2102 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2103 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2104 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2105 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2108 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2110 MMHandleType attrs = 0;
2111 gchar *handle = NULL;
2113 /* check video sinkbin is created */
2114 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2117 attrs = MMPLAYER_GET_ATTRS(player);
2118 MMPLAYER_RETURN_IF_FAIL(attrs);
2120 /* common case if using overlay surface */
2121 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2122 MMPLAYER_RETURN_IF_FAIL(handle);
2124 gst_video_overlay_set_wl_window_exported_shell_handle(
2125 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2127 LOGD("set video param: exported_shell_handle (%s)", handle);
2130 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2132 MMHandleType attrs = 0;
2135 /* check video sinkbin is created */
2136 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2139 attrs = MMPLAYER_GET_ATTRS(player);
2140 MMPLAYER_RETURN_IF_FAIL(attrs);
2142 /* common case if using overlay surface */
2143 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2144 MMPLAYER_RETURN_IF_FAIL(handle);
2146 /* default is using wl_surface_id */
2147 LOGD("set video param : wl_surface_id %d", handle);
2148 gst_video_overlay_set_wl_window_wl_surface_id(
2149 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2154 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2156 gboolean update_all_param = FALSE;
2157 int curr_type = MM_DISPLAY_SURFACE_NUM;
2161 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2162 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2163 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2164 LOGW("videosink is not ready yet");
2165 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2168 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2170 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2171 LOGE("current type(%d) is wrong", curr_type);
2172 return MM_ERROR_PLAYER_INTERNAL;
2175 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2176 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2177 return MM_ERROR_PLAYER_INTERNAL;
2180 LOGD("param_name : %s", param_name);
2181 if (!g_strcmp0(param_name, "update_all_param"))
2182 update_all_param = TRUE;
2184 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2185 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2187 return MM_ERROR_NONE;
2189 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2190 __mmplayer_video_param_set_display_overlay(player);
2191 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2192 __mmplayer_video_param_set_display_method(player);
2193 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2194 __mmplayer_video_param_set_display_visible(player);
2195 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2196 __mmplayer_video_param_set_display_rotation(player);
2197 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2198 __mmplayer_video_param_set_roi_area(player);
2199 if (update_all_param)
2200 __mmplayer_video_param_set_video_roi_area(player);
2203 return MM_ERROR_NONE;
2206 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2208 gboolean disable_overlay = FALSE;
2211 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2212 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2213 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2215 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2216 LOGW("Display control is not supported");
2217 return MM_ERROR_PLAYER_INTERNAL;
2220 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2222 if (disable == (bool)disable_overlay) {
2223 LOGE("It's the same with current setting: (%d)", disable);
2224 return MM_ERROR_NONE;
2228 LOGE("disable overlay");
2229 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2231 /* release overlay resource */
2232 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2233 LOGE("failed to release overlay resource");
2234 return MM_ERROR_PLAYER_INTERNAL;
2237 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2238 LOGE("failed to acquire video overlay resource");
2239 return MM_ERROR_PLAYER_INTERNAL;
2241 player->interrupted_by_resource = FALSE;
2243 LOGD("enable overlay");
2244 __mmplayer_video_param_set_display_overlay(player);
2245 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2246 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2250 return MM_ERROR_NONE;
2254 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2256 int ret = MM_ERROR_NONE;
2257 mmplayer_t *player = (mmplayer_t *)hplayer;
2260 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2262 if (MMPLAYER_USE_DECODEBIN(player)) {
2263 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2268 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2269 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2270 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2272 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2274 /* release decoder resource */
2275 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2276 LOGE("failed to release video decoder resources");
2277 return MM_ERROR_PLAYER_INTERNAL;
2279 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2281 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2285 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2292 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2294 GList *bucket = element_bucket;
2295 mmplayer_gst_element_t *element = NULL;
2296 mmplayer_gst_element_t *prv_element = NULL;
2297 GstElement *tee_element = NULL;
2298 gint successful_link_count = 0;
2302 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2304 prv_element = (mmplayer_gst_element_t *)bucket->data;
2305 bucket = bucket->next;
2307 for (; bucket; bucket = bucket->next) {
2308 element = (mmplayer_gst_element_t *)bucket->data;
2310 if (element && element->gst) {
2311 if (prv_element && prv_element->gst) {
2312 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2314 prv_element->gst = tee_element;
2316 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2317 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2318 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2322 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2323 LOGD("linking [%s] to [%s] success",
2324 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2325 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2326 successful_link_count++;
2327 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2328 LOGD("keep audio-tee element for next audio pipeline branch");
2329 tee_element = prv_element->gst;
2332 LOGD("linking [%s] to [%s] failed",
2333 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2334 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2340 prv_element = element;
2345 return successful_link_count;
2349 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2351 GList *bucket = element_bucket;
2352 mmplayer_gst_element_t *element = NULL;
2353 int successful_add_count = 0;
2357 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2358 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2360 for (; bucket; bucket = bucket->next) {
2361 element = (mmplayer_gst_element_t *)bucket->data;
2363 if (element && element->gst) {
2364 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2365 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2366 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2367 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2370 successful_add_count++;
2376 return successful_add_count;
2380 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2382 mmplayer_t *player = (mmplayer_t *)data;
2383 GstCaps *caps = NULL;
2384 GstStructure *str = NULL;
2386 gboolean caps_ret = TRUE;
2390 MMPLAYER_RETURN_IF_FAIL(pad);
2391 MMPLAYER_RETURN_IF_FAIL(unused);
2392 MMPLAYER_RETURN_IF_FAIL(data);
2394 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2398 LOGD("name = %s", name);
2400 if (strstr(name, "audio")) {
2401 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2403 if (player->audio_stream_changed_cb) {
2404 LOGE("call the audio stream changed cb");
2405 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2407 } else if (strstr(name, "video")) {
2408 if ((name = gst_structure_get_string(str, "format")))
2409 player->set_mode.video_zc = name[0] == 'S';
2411 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2412 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2414 LOGW("invalid caps info");
2419 gst_caps_unref(caps);
2427 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2432 MMPLAYER_RETURN_IF_FAIL(player);
2434 if (player->audio_stream_buff_list) {
2435 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2436 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2439 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2440 __mmplayer_audio_stream_send_data(player, tmp);
2442 MMPLAYER_FREEIF(tmp->pcm_data);
2443 MMPLAYER_FREEIF(tmp);
2446 g_list_free(player->audio_stream_buff_list);
2447 player->audio_stream_buff_list = NULL;
2454 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2456 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2459 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2461 audio_stream.bitrate = a_buffer->bitrate;
2462 audio_stream.channel = a_buffer->channel;
2463 audio_stream.channel_mask = a_buffer->channel_mask;
2464 audio_stream.data_size = a_buffer->data_size;
2465 audio_stream.data = a_buffer->pcm_data;
2466 audio_stream.pcm_format = a_buffer->pcm_format;
2468 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2470 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2476 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2478 mmplayer_t *player = (mmplayer_t *)data;
2479 const gchar *pcm_format = NULL;
2482 guint64 channel_mask = 0;
2483 void *a_data = NULL;
2485 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2486 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2490 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2492 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2493 a_data = mapinfo.data;
2494 a_size = mapinfo.size;
2496 GstCaps *caps = gst_pad_get_current_caps(pad);
2497 GstStructure *structure = gst_caps_get_structure(caps, 0);
2499 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2501 pcm_format = gst_structure_get_string(structure, "format");
2502 gst_structure_get_int(structure, "rate", &rate);
2503 gst_structure_get_int(structure, "channels", &channel);
2504 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2505 gst_caps_unref(GST_CAPS(caps));
2507 /* In case of the sync is false, use buffer list. *
2508 * The num of buffer list depends on the num of audio channels */
2509 if (player->audio_stream_buff_list) {
2510 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2511 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2513 if (channel_mask == tmp->channel_mask) {
2515 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2517 if (tmp->data_size + a_size < tmp->buff_size) {
2518 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2519 tmp->data_size += a_size;
2521 /* send data to client */
2522 __mmplayer_audio_stream_send_data(player, tmp);
2524 if (a_size > tmp->buff_size) {
2525 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2526 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2527 if (tmp->pcm_data == NULL) {
2528 LOGE("failed to realloc data.");
2531 tmp->buff_size = a_size;
2533 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2534 memcpy(tmp->pcm_data, a_data, a_size);
2535 tmp->data_size = a_size;
2540 LOGE("data is empty in list.");
2546 /* create new audio stream data for newly found audio channel */
2547 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2548 if (a_buffer == NULL) {
2549 LOGE("failed to alloc data.");
2552 a_buffer->bitrate = rate;
2553 a_buffer->channel = channel;
2554 a_buffer->channel_mask = channel_mask;
2555 a_buffer->data_size = a_size;
2556 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2558 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2559 /* If sync is FALSE, use buffer list to reduce the IPC. */
2560 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2561 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2562 if (a_buffer->pcm_data == NULL) {
2563 LOGE("failed to alloc data.");
2564 MMPLAYER_FREEIF(a_buffer);
2567 memcpy(a_buffer->pcm_data, a_data, a_size);
2569 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2571 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2573 /* If sync is TRUE, send data directly. */
2574 a_buffer->pcm_data = a_data;
2575 __mmplayer_audio_stream_send_data(player, a_buffer);
2576 MMPLAYER_FREEIF(a_buffer);
2580 gst_buffer_unmap(buffer, &mapinfo);
2585 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2587 mmplayer_t *player = (mmplayer_t *)data;
2588 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2589 GstPad *sinkpad = NULL;
2590 GstElement *queue = NULL, *sink = NULL;
2593 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2595 queue = gst_element_factory_make("queue", NULL);
2596 if (queue == NULL) {
2597 LOGD("fail make queue");
2601 sink = gst_element_factory_make("fakesink", NULL);
2603 LOGD("fail make fakesink");
2607 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2609 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2610 LOGW("failed to link queue & sink");
2614 sinkpad = gst_element_get_static_pad(queue, "sink");
2616 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2617 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2621 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2623 gst_object_unref(sinkpad);
2624 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2625 g_object_set(sink, "sync", TRUE, NULL);
2626 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2628 /* keep the first sink reference only */
2629 if (!audiobin[MMPLAYER_A_SINK].gst) {
2630 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2631 audiobin[MMPLAYER_A_SINK].gst = sink;
2635 _mmplayer_add_signal_connection(player,
2637 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2639 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2642 __mmplayer_add_sink(player, sink, FALSE);
2644 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2645 LOGE("failed to sync state");
2649 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2650 LOGE("failed to sync state");
2658 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2660 gst_object_unref(GST_OBJECT(queue));
2664 gst_object_unref(GST_OBJECT(sink));
2668 gst_object_unref(GST_OBJECT(sinkpad));
2676 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2678 mmplayer_t *player = (mmplayer_t *)data;
2681 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2683 player->no_more_pad = TRUE;
2684 _mmplayer_pipeline_complete(NULL, player);
2691 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2693 #define MAX_PROPS_LEN 128
2694 mmplayer_gst_element_t *audiobin = NULL;
2695 gint latency_mode = 0;
2696 gchar *stream_type = NULL;
2697 gchar *latency = NULL;
2699 gchar stream_props[MAX_PROPS_LEN] = {0,};
2700 GstStructure *props = NULL;
2703 * It should be set after player creation through attribute.
2704 * But, it can not be changed during playing.
2707 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2709 audiobin = player->pipeline->audiobin;
2711 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2712 if (player->sound.mute) {
2713 LOGD("mute enabled");
2714 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2717 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2718 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2721 snprintf(stream_props, sizeof(stream_props) - 1,
2722 "props,application.process.id.origin=%d", player->client_pid);
2724 snprintf(stream_props, sizeof(stream_props) - 1,
2725 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2726 stream_type, stream_id, player->client_pid);
2728 props = gst_structure_from_string(stream_props, NULL);
2729 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2730 LOGI("props result[%s].", stream_props);
2731 gst_structure_free(props);
2733 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2735 switch (latency_mode) {
2736 case AUDIO_LATENCY_MODE_LOW:
2737 latency = g_strdup("low");
2739 case AUDIO_LATENCY_MODE_MID:
2740 latency = g_strdup("mid");
2742 case AUDIO_LATENCY_MODE_HIGH:
2743 latency = g_strdup("high");
2746 latency = g_strdup("mid");
2750 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2752 LOGD("audiosink property - latency=%s", latency);
2754 MMPLAYER_FREEIF(latency);
2760 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2762 mmplayer_gst_element_t *audiobin = NULL;
2765 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2766 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2768 audiobin = player->pipeline->audiobin;
2770 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2771 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2772 LOGE("failed to create media stream info");
2773 return MM_ERROR_PLAYER_INTERNAL;
2776 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2778 if (player->video360_yaw_radians <= M_PI &&
2779 player->video360_yaw_radians >= -M_PI &&
2780 player->video360_pitch_radians <= M_PI_2 &&
2781 player->video360_pitch_radians >= -M_PI_2) {
2782 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2783 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2784 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2785 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2786 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2787 "source-orientation-y", player->video360_metadata.init_view_heading,
2788 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2792 return MM_ERROR_NONE;
2796 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2798 mmplayer_gst_element_t *audiobin = NULL;
2799 GstPad *sink_pad = NULL;
2800 GstCaps *acaps = NULL;
2802 int pitch_control = 0;
2803 double pitch_value = 1.0;
2806 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2807 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2809 audiobin = player->pipeline->audiobin;
2811 LOGD("make element for normal audio playback");
2813 /* audio bin structure for playback. {} means optional.
2814 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2816 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2817 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2820 /* for pitch control */
2821 mm_attrs_multiple_get(player->attrs, NULL,
2822 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2823 MM_PLAYER_PITCH_VALUE, &pitch_value,
2826 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2827 if (pitch_control && (player->videodec_linked == 0)) {
2828 GstElementFactory *factory;
2830 factory = gst_element_factory_find("pitch");
2832 gst_object_unref(factory);
2835 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2838 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2839 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2841 LOGW("there is no pitch element");
2846 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2848 /* replaygain volume */
2849 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2850 if (player->sound.rg_enable)
2851 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2853 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2856 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2858 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2859 /* currently, only openalsink uses volume element */
2860 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2861 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2863 if (player->sound.mute) {
2864 LOGD("mute enabled");
2865 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2869 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2871 /* audio effect element. if audio effect is enabled */
2872 if ((strcmp(player->ini.audioeffect_element, ""))
2874 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2875 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2877 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2879 if ((!player->bypass_audio_effect)
2880 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2881 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2882 if (!_mmplayer_audio_effect_custom_apply(player))
2883 LOGI("apply audio effect(custom) setting success");
2887 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2888 && (player->set_mode.rich_audio)) {
2889 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2893 /* create audio sink */
2894 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2895 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2896 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2898 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2899 if (player->is_360_feature_enabled &&
2900 player->is_content_spherical &&
2902 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2903 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2904 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2906 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2908 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2910 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2911 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2912 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2913 gst_caps_unref(acaps);
2915 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2917 player->is_openal_plugin_used = TRUE;
2919 if (player->is_360_feature_enabled && player->is_content_spherical)
2920 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2921 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2924 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2925 (player->videodec_linked && player->ini.use_system_clock)) {
2926 LOGD("system clock will be used.");
2927 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2930 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2931 __mmplayer_gst_set_pulsesink_property(player);
2932 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2933 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2938 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2939 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2941 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2942 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2943 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2944 gst_object_unref(GST_OBJECT(sink_pad));
2946 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2949 return MM_ERROR_NONE;
2951 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2953 return MM_ERROR_PLAYER_INTERNAL;
2957 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2959 mmplayer_gst_element_t *audiobin = NULL;
2960 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2962 gchar *dst_format = NULL;
2964 int dst_samplerate = 0;
2965 int dst_channels = 0;
2966 GstCaps *caps = NULL;
2967 char *caps_str = NULL;
2970 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2971 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2973 audiobin = player->pipeline->audiobin;
2975 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2977 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2979 [case 1] extract interleave audio pcm without playback
2980 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2981 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2983 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2985 [case 2] deinterleave for each channel without playback
2986 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2987 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2989 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2990 - fakesink (sync or not)
2993 [case 3] [case 1(sync only)] + playback
2994 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2996 * src - ... - tee - queue1 - playback path
2997 - queue2 - [case1 pipeline with sync]
2999 [case 4] [case 2(sync only)] + playback
3000 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3002 * src - ... - tee - queue1 - playback path
3003 - queue2 - [case2 pipeline with sync]
3007 /* 1. create tee and playback path
3008 'tee' should be added at first to copy the decoded stream
3010 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3011 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3012 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3014 /* tee - path 1 : for playback path */
3015 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3016 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3018 /* tee - path 2 : for extract path */
3019 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3020 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3023 /* if there is tee, 'tee - path 2' is linked here */
3025 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3028 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3030 /* 2. decide the extract pcm format */
3031 mm_attrs_multiple_get(player->attrs, NULL,
3032 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3033 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3034 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3037 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3038 dst_format, dst_len, dst_samplerate, dst_channels);
3040 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3041 mm_attrs_multiple_get(player->attrs, NULL,
3042 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3043 "content_audio_samplerate", &dst_samplerate,
3044 "content_audio_channels", &dst_channels,
3047 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3048 dst_format, dst_len, dst_samplerate, dst_channels);
3050 /* If there is no enough information, set it to platform default value. */
3051 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3052 LOGD("set platform default format");
3053 dst_format = DEFAULT_PCM_OUT_FORMAT;
3055 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3056 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3059 /* 3. create capsfilter */
3060 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3061 caps = gst_caps_new_simple("audio/x-raw",
3062 "format", G_TYPE_STRING, dst_format,
3063 "rate", G_TYPE_INT, dst_samplerate,
3064 "channels", G_TYPE_INT, dst_channels,
3067 caps_str = gst_caps_to_string(caps);
3068 LOGD("new caps : %s", caps_str);
3070 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3073 gst_caps_unref(caps);
3074 MMPLAYER_FREEIF(caps_str);
3076 /* 4-1. create deinterleave to extract pcm for each channel */
3077 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3078 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3079 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3081 /* audiosink will be added after getting signal for each channel */
3082 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3083 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3084 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3085 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3086 player->no_more_pad = FALSE;
3088 /* 4-2. create fakesink to extract interleaved pcm */
3089 LOGD("add audio fakesink for interleaved audio");
3090 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3091 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3092 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3093 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3095 _mmplayer_add_signal_connection(player,
3096 G_OBJECT(audiobin[extract_sink_id].gst),
3097 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3099 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3102 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3106 return MM_ERROR_NONE;
3108 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3110 return MM_ERROR_PLAYER_INTERNAL;
3114 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3116 int ret = MM_ERROR_NONE;
3117 mmplayer_gst_element_t *audiobin = NULL;
3118 GList *element_bucket = NULL;
3121 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3122 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3124 audiobin = player->pipeline->audiobin;
3126 if (player->build_audio_offload) { /* skip all the audio filters */
3127 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3129 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3130 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3131 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3133 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3137 /* FIXME: need to mention the supportable condition at API reference */
3138 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3139 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3141 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3143 if (ret != MM_ERROR_NONE)
3146 LOGD("success to make audio bin element");
3147 *bucket = element_bucket;
3150 return MM_ERROR_NONE;
3153 LOGE("failed to make audio bin element");
3154 g_list_free(element_bucket);
3158 return MM_ERROR_PLAYER_INTERNAL;
3162 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3164 mmplayer_gst_element_t *first_element = NULL;
3165 mmplayer_gst_element_t *audiobin = NULL;
3167 GstPad *ghostpad = NULL;
3168 GList *element_bucket = NULL;
3172 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3175 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3177 LOGE("failed to allocate memory for audiobin");
3178 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3182 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3183 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3184 if (!audiobin[MMPLAYER_A_BIN].gst) {
3185 LOGE("failed to create audiobin");
3190 player->pipeline->audiobin = audiobin;
3192 /* create audio filters and audiosink */
3193 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3196 /* adding created elements to bin */
3197 LOGD("adding created elements to bin");
3198 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3201 /* linking elements in the bucket by added order. */
3202 LOGD("Linking elements in the bucket by added order.");
3203 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3206 /* get first element's sinkpad for creating ghostpad */
3207 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3208 if (!first_element) {
3209 LOGE("failed to get first elem");
3213 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3215 LOGE("failed to get pad from first element of audiobin");
3219 ghostpad = gst_ghost_pad_new("sink", pad);
3221 LOGE("failed to create ghostpad");
3225 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3226 LOGE("failed to add ghostpad to audiobin");
3230 gst_object_unref(pad);
3232 g_list_free(element_bucket);
3235 return MM_ERROR_NONE;
3238 LOGD("ERROR : releasing audiobin");
3241 gst_object_unref(GST_OBJECT(pad));
3244 gst_object_unref(GST_OBJECT(ghostpad));
3247 g_list_free(element_bucket);
3249 /* release element which are not added to bin */
3250 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3251 /* NOTE : skip bin */
3252 if (audiobin[i].gst) {
3253 GstObject *parent = NULL;
3254 parent = gst_element_get_parent(audiobin[i].gst);
3257 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3258 audiobin[i].gst = NULL;
3260 gst_object_unref(GST_OBJECT(parent));
3264 /* release audiobin with it's children */
3265 if (audiobin[MMPLAYER_A_BIN].gst)
3266 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3268 MMPLAYER_FREEIF(audiobin);
3270 player->pipeline->audiobin = NULL;
3272 return MM_ERROR_PLAYER_INTERNAL;
3276 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3278 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3282 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3284 int ret = MM_ERROR_NONE;
3286 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3287 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3289 MMPLAYER_VIDEO_BO_LOCK(player);
3291 if (player->video_bo_list) {
3292 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3293 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3294 if (tmp && tmp->bo == bo) {
3296 LOGD("release bo %p", bo);
3297 tbm_bo_unref(tmp->bo);
3298 MMPLAYER_VIDEO_BO_UNLOCK(player);
3299 MMPLAYER_VIDEO_BO_SIGNAL(player);
3304 /* hw codec is running or the list was reset for DRC. */
3305 LOGW("there is no bo list.");
3307 MMPLAYER_VIDEO_BO_UNLOCK(player);
3309 LOGW("failed to find bo %p", bo);
3313 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3319 tbm_bo_unref(tmp->bo);
3324 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3327 MMPLAYER_RETURN_IF_FAIL(player);
3329 MMPLAYER_VIDEO_BO_LOCK(player);
3330 if (player->video_bo_list) {
3331 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3332 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3333 player->video_bo_list = NULL;
3335 player->video_bo_size = 0;
3336 MMPLAYER_VIDEO_BO_UNLOCK(player);
3343 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3346 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3347 gboolean ret = TRUE;
3348 gint64 end_time = 0;
3350 /* check DRC, if it is, destroy the prev bo list to create again */
3351 if (player->video_bo_size != size) {
3352 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3353 __mmplayer_video_stream_destroy_bo_list(player);
3354 player->video_bo_size = size;
3357 MMPLAYER_VIDEO_BO_LOCK(player);
3359 if ((!player->video_bo_list) ||
3360 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3362 /* create bo list */
3364 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3366 if (player->video_bo_list) {
3367 /* if bo list did not created all, try it again. */
3368 idx = g_list_length(player->video_bo_list);
3369 LOGD("bo list exist(len: %d)", idx);
3372 for (; idx < player->ini.num_of_video_bo; idx++) {
3373 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3375 LOGE("Fail to alloc bo_info.");
3378 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3380 LOGE("Fail to tbm_bo_alloc.");
3381 MMPLAYER_FREEIF(bo_info);
3384 bo_info->used = FALSE;
3385 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3388 /* update video num buffers */
3389 LOGD("video_num_buffers : %d", idx);
3390 mm_player_set_attribute((MMHandleType)player, NULL,
3391 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3392 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3396 MMPLAYER_VIDEO_BO_UNLOCK(player);
3401 if (player->ini.video_bo_timeout > 0)
3402 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3405 /* get bo from list*/
3406 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3407 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3408 if (tmp && (tmp->used == FALSE)) {
3409 LOGD("found bo %p to use", tmp->bo);
3411 MMPLAYER_VIDEO_BO_UNLOCK(player);
3412 return tbm_bo_ref(tmp->bo);
3416 if (player->ini.video_bo_timeout <= 0) {
3417 MMPLAYER_VIDEO_BO_WAIT(player);
3419 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3421 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3427 MMPLAYER_VIDEO_BO_UNLOCK(player);
3432 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3434 mmplayer_t *player = (mmplayer_t *)data;
3436 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3438 /* send prerolled pkt */
3439 player->video_stream_prerolled = false;
3441 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3443 /* not to send prerolled pkt again */
3444 player->video_stream_prerolled = true;
3448 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3450 mmplayer_t *player = (mmplayer_t *)data;
3451 mmplayer_video_decoded_data_info_t *stream = NULL;
3452 GstMemory *mem = NULL;
3455 MMPLAYER_RETURN_IF_FAIL(player);
3456 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3458 if (player->video_stream_prerolled) {
3459 player->video_stream_prerolled = false;
3460 LOGD("skip the prerolled pkt not to send it again");
3464 /* clear stream data structure */
3465 stream = __mmplayer_create_stream_from_pad(pad);
3467 LOGE("failed to alloc stream");
3471 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3473 /* set size and timestamp */
3474 mem = gst_buffer_peek_memory(buffer, 0);
3475 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3476 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3478 /* check zero-copy */
3479 if (player->set_mode.video_zc &&
3480 player->set_mode.video_export &&
3481 gst_is_tizen_memory(mem)) {
3482 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3483 stream->internal_buffer = gst_buffer_ref(buffer);
3484 } else { /* sw codec */
3485 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3488 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3492 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3493 LOGE("failed to send video decoded data.");
3500 LOGE("release video stream resource.");
3501 if (gst_is_tizen_memory(mem)) {
3503 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3505 tbm_bo_unref(stream->bo[i]);
3508 /* unref gst buffer */
3509 if (stream->internal_buffer)
3510 gst_buffer_unref(stream->internal_buffer);
3513 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3515 MMPLAYER_FREEIF(stream);
3520 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3522 mmplayer_gst_element_t *videobin = NULL;
3525 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3527 videobin = player->pipeline->videobin;
3529 /* Set spatial media metadata and/or user settings to the element.
3531 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3532 "projection-type", player->video360_metadata.projection_type, NULL);
3534 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3535 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3537 if (player->video360_metadata.full_pano_width_pixels &&
3538 player->video360_metadata.full_pano_height_pixels &&
3539 player->video360_metadata.cropped_area_image_width &&
3540 player->video360_metadata.cropped_area_image_height) {
3541 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3542 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3543 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3544 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3545 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3546 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3547 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3551 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3552 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3553 "horizontal-fov", player->video360_horizontal_fov,
3554 "vertical-fov", player->video360_vertical_fov, NULL);
3557 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3558 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3559 "zoom", 1.0f / player->video360_zoom, NULL);
3562 if (player->video360_yaw_radians <= M_PI &&
3563 player->video360_yaw_radians >= -M_PI &&
3564 player->video360_pitch_radians <= M_PI_2 &&
3565 player->video360_pitch_radians >= -M_PI_2) {
3566 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3567 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3568 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3569 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3570 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3571 "pose-yaw", player->video360_metadata.init_view_heading,
3572 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3575 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3576 "passthrough", !player->is_video360_enabled, NULL);
3583 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3585 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3586 GList *element_bucket = NULL;
3589 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3591 /* create video360 filter */
3592 if (player->is_360_feature_enabled && player->is_content_spherical) {
3593 LOGD("create video360 element");
3594 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3595 __mmplayer_gst_set_video360_property(player);
3599 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3600 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3601 player->set_mode.video_zc) {
3602 LOGD("skip creating the videoconv and rotator");
3603 return MM_ERROR_NONE;
3606 /* in case of sw codec & overlay surface type, except 360 playback.
3607 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3608 LOGD("create video converter: %s", video_csc);
3609 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3612 *bucket = element_bucket;
3614 return MM_ERROR_NONE;
3616 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3617 g_list_free(element_bucket);
3621 return MM_ERROR_PLAYER_INTERNAL;
3625 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3627 gchar *factory_name = NULL;
3629 switch (surface_type) {
3630 case MM_DISPLAY_SURFACE_OVERLAY:
3632 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3633 if (strlen(player->ini.videosink_element_overlay) > 0)
3634 factory_name = player->ini.videosink_element_overlay;
3636 case MM_DISPLAY_SURFACE_REMOTE:
3638 case MM_DISPLAY_SURFACE_NULL:
3639 if (strlen(player->ini.videosink_element_fake) > 0)
3640 factory_name = player->ini.videosink_element_fake;
3643 LOGE("unidentified surface type");
3647 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3648 return factory_name;
3652 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3654 gchar *factory_name = NULL;
3655 mmplayer_gst_element_t *videobin = NULL;
3660 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3662 videobin = player->pipeline->videobin;
3663 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3665 attrs = MMPLAYER_GET_ATTRS(player);
3667 LOGE("cannot get content attribute");
3668 return MM_ERROR_PLAYER_INTERNAL;
3671 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3672 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3673 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3674 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3675 "use-tbm", use_tbm, NULL);
3678 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3679 return MM_ERROR_PLAYER_INTERNAL;
3681 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3684 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3685 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3688 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3690 LOGD("disable last-sample");
3691 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3694 if (player->set_mode.video_export) {
3696 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3697 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3698 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3700 _mmplayer_add_signal_connection(player,
3701 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3702 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3704 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3707 _mmplayer_add_signal_connection(player,
3708 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3709 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3711 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3715 if (videobin[MMPLAYER_V_SINK].gst) {
3716 GstPad *sink_pad = NULL;
3717 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3719 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3720 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3721 gst_object_unref(GST_OBJECT(sink_pad));
3723 LOGE("failed to get sink pad from videosink");
3727 return MM_ERROR_NONE;
3732 * - video overlay surface(arm/x86) : tizenwlsink
3735 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3738 GList *element_bucket = NULL;
3739 mmplayer_gst_element_t *first_element = NULL;
3740 mmplayer_gst_element_t *videobin = NULL;
3741 gchar *videosink_factory_name = NULL;
3744 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3747 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3749 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3751 player->pipeline->videobin = videobin;
3754 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3755 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3756 if (!videobin[MMPLAYER_V_BIN].gst) {
3757 LOGE("failed to create videobin");
3761 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3764 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3765 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3767 /* additional setting for sink plug-in */
3768 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3769 LOGE("failed to set video property");
3773 /* store it as it's sink element */
3774 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3776 /* adding created elements to bin */
3777 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3778 LOGE("failed to add elements");
3782 /* Linking elements in the bucket by added order */
3783 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3784 LOGE("failed to link elements");
3788 /* get first element's sinkpad for creating ghostpad */
3789 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3790 if (!first_element) {
3791 LOGE("failed to get first element from bucket");
3795 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3797 LOGE("failed to get pad from first element");
3801 /* create ghostpad */
3802 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3803 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3804 LOGE("failed to add ghostpad to videobin");
3807 gst_object_unref(pad);
3809 /* done. free allocated variables */
3810 g_list_free(element_bucket);
3814 return MM_ERROR_NONE;
3817 LOGE("ERROR : releasing videobin");
3818 g_list_free(element_bucket);
3821 gst_object_unref(GST_OBJECT(pad));
3823 /* release videobin with it's children */
3824 if (videobin[MMPLAYER_V_BIN].gst)
3825 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3827 MMPLAYER_FREEIF(videobin);
3828 player->pipeline->videobin = NULL;
3830 return MM_ERROR_PLAYER_INTERNAL;
3834 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3836 GList *element_bucket = NULL;
3837 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3839 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3840 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3841 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3842 "signal-handoffs", FALSE,
3845 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3846 _mmplayer_add_signal_connection(player,
3847 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3848 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3850 G_CALLBACK(__mmplayer_update_subtitle),
3853 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3854 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3856 if (!player->play_subtitle) {
3857 LOGD("add textbin sink as sink element of whole pipeline.");
3858 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3861 /* adding created elements to bin */
3862 LOGD("adding created elements to bin");
3863 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3864 LOGE("failed to add elements");
3868 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3869 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3870 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3872 /* linking elements in the bucket by added order. */
3873 LOGD("Linking elements in the bucket by added order.");
3874 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3875 LOGE("failed to link elements");
3879 if (textbin[MMPLAYER_T_QUEUE].gst) {
3881 GstPad *ghostpad = NULL;
3883 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3885 LOGE("failed to get sink pad of text queue");
3889 ghostpad = gst_ghost_pad_new("text_sink", pad);
3890 gst_object_unref(pad);
3893 LOGE("failed to create ghostpad of textbin");
3897 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3898 LOGE("failed to add ghostpad to textbin");
3899 gst_object_unref(ghostpad);
3904 g_list_free(element_bucket);
3906 return MM_ERROR_NONE;
3910 g_list_free(element_bucket);
3912 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3913 LOGE("remove textbin sink from sink list");
3914 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3917 /* release element at __mmplayer_gst_create_text_sink_bin */
3918 return MM_ERROR_PLAYER_INTERNAL;
3922 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3924 mmplayer_gst_element_t *textbin = NULL;
3925 int surface_type = 0;
3930 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3933 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3935 LOGE("failed to allocate memory for textbin");
3936 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3940 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3941 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3942 if (!textbin[MMPLAYER_T_BIN].gst) {
3943 LOGE("failed to create textbin");
3948 player->pipeline->textbin = textbin;
3951 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3952 LOGD("surface type for subtitle : %d", surface_type);
3953 switch (surface_type) {
3954 case MM_DISPLAY_SURFACE_OVERLAY:
3955 case MM_DISPLAY_SURFACE_NULL:
3956 case MM_DISPLAY_SURFACE_REMOTE:
3957 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3958 LOGE("failed to make plain text elements");
3969 return MM_ERROR_NONE;
3973 LOGD("ERROR : releasing textbin");
3975 /* release signal */
3976 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3978 /* release element which are not added to bin */
3979 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3980 /* NOTE : skip bin */
3981 if (textbin[i].gst) {
3982 GstObject *parent = NULL;
3983 parent = gst_element_get_parent(textbin[i].gst);
3986 gst_object_unref(GST_OBJECT(textbin[i].gst));
3987 textbin[i].gst = NULL;
3989 gst_object_unref(GST_OBJECT(parent));
3994 /* release textbin with it's children */
3995 if (textbin[MMPLAYER_T_BIN].gst)
3996 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3998 MMPLAYER_FREEIF(textbin);
3999 player->pipeline->textbin = NULL;
4002 return MM_ERROR_PLAYER_INTERNAL;
4006 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4008 mmplayer_gst_element_t *mainbin = NULL;
4009 mmplayer_gst_element_t *textbin = NULL;
4010 MMHandleType attrs = 0;
4011 GstElement *subsrc = NULL;
4012 GstElement *subparse = NULL;
4013 gchar *subtitle_uri = NULL;
4014 const gchar *charset = NULL;
4020 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4022 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4024 mainbin = player->pipeline->mainbin;
4026 attrs = MMPLAYER_GET_ATTRS(player);
4028 LOGE("cannot get content attribute");
4029 return MM_ERROR_PLAYER_INTERNAL;
4032 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4033 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4034 LOGE("subtitle uri is not proper filepath.");
4035 return MM_ERROR_PLAYER_INVALID_URI;
4038 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4039 LOGE("failed to get storage info of subtitle path");
4040 return MM_ERROR_PLAYER_INVALID_URI;
4043 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4045 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4046 player->subtitle_language_list = NULL;
4047 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4049 /* create the subtitle source */
4050 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4052 LOGE("failed to create filesrc element");
4055 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4057 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4058 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4060 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4061 LOGW("failed to add queue");
4062 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4063 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4064 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4069 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4071 LOGE("failed to create subparse element");
4075 charset = _mmplayer_get_charset(subtitle_uri);
4077 LOGD("detected charset is %s", charset);
4078 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4081 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4082 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4084 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4085 LOGW("failed to add subparse");
4086 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4087 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4088 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4092 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4093 LOGW("failed to link subsrc and subparse");
4097 player->play_subtitle = TRUE;
4098 player->adjust_subtitle_pos = 0;
4100 LOGD("play subtitle using subtitle file");
4102 if (player->pipeline->textbin == NULL) {
4103 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4104 LOGE("failed to create text sink bin. continuing without text");
4108 textbin = player->pipeline->textbin;
4110 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4111 LOGW("failed to add textbin");
4113 /* release signal */
4114 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4116 /* release textbin with it's children */
4117 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4118 MMPLAYER_FREEIF(player->pipeline->textbin);
4119 player->pipeline->textbin = textbin = NULL;
4123 LOGD("link text input selector and textbin ghost pad");
4125 player->textsink_linked = 1;
4126 player->external_text_idx = 0;
4127 LOGI("textsink is linked");
4129 textbin = player->pipeline->textbin;
4130 LOGD("text bin has been created. reuse it.");
4131 player->external_text_idx = 1;
4134 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4135 LOGW("failed to link subparse and textbin");
4139 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4141 LOGE("failed to get sink pad from textsink to probe data");
4145 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4146 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4148 gst_object_unref(pad);
4151 /* create dot. for debugging */
4152 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4155 return MM_ERROR_NONE;
4158 /* release text pipeline resource */
4159 player->textsink_linked = 0;
4161 /* release signal */
4162 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4164 if (player->pipeline->textbin) {
4165 LOGE("remove textbin");
4167 /* release textbin with it's children */
4168 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4169 MMPLAYER_FREEIF(player->pipeline->textbin);
4170 player->pipeline->textbin = NULL;
4174 /* release subtitle elem */
4175 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4176 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4178 return MM_ERROR_PLAYER_INTERNAL;
4182 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4184 mmplayer_t *player = (mmplayer_t *)data;
4185 MMMessageParamType msg = {0, };
4186 GstClockTime duration = 0;
4187 gpointer text = NULL;
4188 guint text_size = 0;
4189 gboolean ret = TRUE;
4190 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4194 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4195 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4197 if (player->is_subtitle_force_drop) {
4198 LOGW("subtitle is dropped forcedly.");
4202 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4203 text = mapinfo.data;
4204 text_size = mapinfo.size;
4206 if (player->set_mode.subtitle_off) {
4207 LOGD("subtitle is OFF.");
4211 if (!text || (text_size == 0)) {
4212 LOGD("There is no subtitle to be displayed.");
4216 msg.data = (void *)text;
4218 duration = GST_BUFFER_DURATION(buffer);
4220 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4221 if (player->duration > GST_BUFFER_PTS(buffer))
4222 duration = player->duration - GST_BUFFER_PTS(buffer);
4225 LOGI("subtitle duration is invalid, subtitle duration change "
4226 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4228 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4230 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4232 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4233 gst_buffer_unmap(buffer, &mapinfo);
4240 static GstPadProbeReturn
4241 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4243 mmplayer_t *player = (mmplayer_t *)u_data;
4244 GstClockTime cur_timestamp = 0;
4245 gint64 adjusted_timestamp = 0;
4246 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4248 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4250 if (player->set_mode.subtitle_off) {
4251 LOGD("subtitle is OFF.");
4255 if (player->adjust_subtitle_pos == 0) {
4256 LOGD("nothing to do");
4260 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4261 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4263 if (adjusted_timestamp < 0) {
4264 LOGD("adjusted_timestamp under zero");
4269 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4270 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4271 GST_TIME_ARGS(cur_timestamp),
4272 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4274 return GST_PAD_PROBE_OK;
4278 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4282 /* check player and subtitlebin are created */
4283 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4284 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4286 if (position == 0) {
4287 LOGD("nothing to do");
4289 return MM_ERROR_NONE;
4292 /* check current position */
4293 player->adjust_subtitle_pos = position;
4295 LOGD("save adjust_subtitle_pos in player");
4299 return MM_ERROR_NONE;
4303 * This function is to create audio or video pipeline for playing.
4305 * @param player [in] handle of player
4307 * @return This function returns zero on success.
4312 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4314 int ret = MM_ERROR_NONE;
4315 mmplayer_gst_element_t *mainbin = NULL;
4316 MMHandleType attrs = 0;
4319 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4321 /* get profile attribute */
4322 attrs = MMPLAYER_GET_ATTRS(player);
4324 LOGE("failed to get content attribute");
4328 /* create pipeline handles */
4329 if (player->pipeline) {
4330 LOGE("pipeline should be released before create new one");
4334 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4336 /* create mainbin */
4337 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4338 if (mainbin == NULL)
4341 /* create pipeline */
4342 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4343 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4344 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4345 LOGE("failed to create pipeline");
4350 player->pipeline->mainbin = mainbin;
4352 /* create the source and decoder elements */
4353 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4354 ret = _mmplayer_gst_build_es_pipeline(player);
4356 if (MMPLAYER_USE_DECODEBIN(player))
4357 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4359 ret = _mmplayer_gst_build_pipeline_with_src(player);
4362 if (ret != MM_ERROR_NONE) {
4363 LOGE("failed to create some elements");
4367 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4368 if (__mmplayer_check_subtitle(player)
4369 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4370 LOGE("failed to create text pipeline");
4373 ret = _mmplayer_gst_add_bus_watch(player);
4374 if (ret != MM_ERROR_NONE) {
4375 LOGE("failed to add bus watch");
4380 return MM_ERROR_NONE;
4383 _mmplayer_bus_watcher_remove(player);
4384 __mmplayer_gst_destroy_pipeline(player);
4385 return MM_ERROR_PLAYER_INTERNAL;
4389 __mmplayer_reset_gapless_state(mmplayer_t *player)
4392 MMPLAYER_RETURN_IF_FAIL(player
4394 && player->pipeline->audiobin
4395 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4397 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4404 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4407 int ret = MM_ERROR_NONE;
4411 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4413 /* cleanup stuffs */
4414 MMPLAYER_FREEIF(player->type);
4415 player->no_more_pad = FALSE;
4416 player->num_dynamic_pad = 0;
4418 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4419 player->subtitle_language_list = NULL;
4420 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4422 MMPLAYER_RECONFIGURE_LOCK(player);
4423 __mmplayer_reset_gapless_state(player);
4424 MMPLAYER_RECONFIGURE_UNLOCK(player);
4426 if (player->streamer) {
4427 _mm_player_streaming_initialize(player->streamer, FALSE);
4428 _mm_player_streaming_destroy(player->streamer);
4429 player->streamer = NULL;
4432 /* cleanup unlinked mime type */
4433 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4434 MMPLAYER_FREEIF(player->unlinked_video_mime);
4435 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4437 /* cleanup running stuffs */
4438 _mmplayer_cancel_eos_timer(player);
4440 /* cleanup gst stuffs */
4441 if (player->pipeline) {
4442 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4443 GstTagList *tag_list = player->pipeline->tag_list;
4445 /* first we need to disconnect all signal hander */
4446 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4449 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4450 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4451 gst_object_unref(bus);
4453 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4454 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4455 if (ret != MM_ERROR_NONE) {
4456 LOGE("fail to change state to NULL");
4457 return MM_ERROR_PLAYER_INTERNAL;
4460 LOGW("succeeded in changing state to NULL");
4462 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4465 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4466 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4468 MMPLAYER_FREEIF(player->pipeline->audiobin);
4469 MMPLAYER_FREEIF(player->pipeline->videobin);
4470 MMPLAYER_FREEIF(player->pipeline->textbin);
4471 MMPLAYER_FREEIF(mainbin);
4475 gst_tag_list_unref(tag_list);
4477 MMPLAYER_FREEIF(player->pipeline);
4479 MMPLAYER_FREEIF(player->album_art);
4481 if (player->type_caps) {
4482 gst_caps_unref(player->type_caps);
4483 player->type_caps = NULL;
4486 if (player->v_stream_caps) {
4487 gst_caps_unref(player->v_stream_caps);
4488 player->v_stream_caps = NULL;
4491 if (player->a_stream_caps) {
4492 gst_caps_unref(player->a_stream_caps);
4493 player->a_stream_caps = NULL;
4496 if (player->s_stream_caps) {
4497 gst_caps_unref(player->s_stream_caps);
4498 player->s_stream_caps = NULL;
4500 _mmplayer_track_destroy(player);
4502 if (player->sink_elements)
4503 g_list_free(player->sink_elements);
4504 player->sink_elements = NULL;
4506 if (player->bufmgr) {
4507 tbm_bufmgr_deinit(player->bufmgr);
4508 player->bufmgr = NULL;
4511 LOGW("finished destroy pipeline");
4519 __mmplayer_gst_realize(mmplayer_t *player)
4522 int ret = MM_ERROR_NONE;
4526 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4528 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4530 ret = __mmplayer_gst_create_pipeline(player);
4532 LOGE("failed to create pipeline");
4536 /* set pipeline state to READY */
4537 /* NOTE : state change to READY must be performed sync. */
4538 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4539 ret = _mmplayer_gst_set_state(player,
4540 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4542 if (ret != MM_ERROR_NONE) {
4543 /* return error if failed to set state */
4544 LOGE("failed to set READY state");
4548 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4550 /* create dot before error-return. for debugging */
4551 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4559 __mmplayer_gst_unrealize(mmplayer_t *player)
4561 int ret = MM_ERROR_NONE;
4565 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4567 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4568 MMPLAYER_PRINT_STATE(player);
4570 /* release miscellaneous information */
4571 __mmplayer_release_misc(player);
4573 /* destroy pipeline */
4574 ret = __mmplayer_gst_destroy_pipeline(player);
4575 if (ret != MM_ERROR_NONE) {
4576 LOGE("failed to destroy pipeline");
4580 /* release miscellaneous information.
4581 these info needs to be released after pipeline is destroyed. */
4582 __mmplayer_release_misc_post(player);
4584 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4592 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4597 LOGW("set_message_callback is called with invalid player handle");
4598 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4601 player->msg_cb = callback;
4602 player->msg_cb_param = user_param;
4604 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4608 return MM_ERROR_NONE;
4612 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4614 int ret = MM_ERROR_NONE;
4619 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4620 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4621 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4623 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4625 if (strstr(uri, "es_buff://")) {
4626 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4627 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4628 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4629 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4631 tmp = g_ascii_strdown(uri, strlen(uri));
4632 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4633 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4635 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4637 } else if (strstr(uri, "mms://")) {
4638 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4639 } else if ((path = strstr(uri, "mem://"))) {
4640 ret = __mmplayer_set_mem_uri(data, path, param);
4642 ret = __mmplayer_set_file_uri(data, uri);
4645 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4646 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4647 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4648 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4650 /* dump parse result */
4651 SECURE_LOGW("incoming uri : %s", uri);
4652 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4653 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4661 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4664 mmplayer_t *player = NULL;
4665 MMMessageParamType msg = {0, };
4667 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4672 LOGE("user_data is null");
4676 player = (mmplayer_t *)user_data;
4678 if (!player->pipeline || !player->attrs) {
4679 LOGW("not initialized");
4683 LOGD("cmd lock player, cmd state : %d", player->cmd);
4684 MMPLAYER_CMD_LOCK(player);
4685 LOGD("cmd locked player");
4687 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4688 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4689 LOGW("player already destroyed");
4690 MMPLAYER_CMD_UNLOCK(player);
4694 player->interrupted_by_resource = TRUE;
4696 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4698 /* get last play position */
4699 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4700 msg.union_type = MM_MSG_UNION_TIME;
4701 msg.time.elapsed = pos;
4702 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4704 LOGW("failed to get play position.");
4707 LOGD("video resource conflict so, resource will be freed by unrealizing");
4708 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4709 LOGE("failed to unrealize");
4711 MMPLAYER_CMD_UNLOCK(player);
4713 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4714 player->hw_resource[res_idx] = NULL;
4718 return TRUE; /* release all the resources */
4722 __mmplayer_initialize_video_roi(mmplayer_t *player)
4724 player->video_roi.scale_x = 0.0;
4725 player->video_roi.scale_y = 0.0;
4726 player->video_roi.scale_width = 1.0;
4727 player->video_roi.scale_height = 1.0;
4731 _mmplayer_create_player(MMHandleType handle)
4733 int ret = MM_ERROR_PLAYER_INTERNAL;
4734 bool enabled = false;
4736 mmplayer_t *player = MM_PLAYER_CAST(handle);
4740 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4742 /* initialize player state */
4743 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4744 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4745 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4746 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4748 /* check current state */
4749 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4751 /* construct attributes */
4752 player->attrs = _mmplayer_construct_attribute(handle);
4754 if (!player->attrs) {
4755 LOGE("Failed to construct attributes");
4759 /* initialize gstreamer with configured parameter */
4760 if (!__mmplayer_init_gstreamer(player)) {
4761 LOGE("Initializing gstreamer failed");
4762 _mmplayer_deconstruct_attribute(handle);
4766 /* create lock. note that g_tread_init() has already called in gst_init() */
4767 g_mutex_init(&player->fsink_lock);
4769 /* create update tag lock */
4770 g_mutex_init(&player->update_tag_lock);
4772 /* create gapless play mutex */
4773 g_mutex_init(&player->gapless_play_thread_mutex);
4775 /* create gapless play cond */
4776 g_cond_init(&player->gapless_play_thread_cond);
4778 /* create gapless play thread */
4779 player->gapless_play_thread =
4780 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4781 if (!player->gapless_play_thread) {
4782 LOGE("failed to create gapless play thread");
4783 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4784 g_mutex_clear(&player->gapless_play_thread_mutex);
4785 g_cond_clear(&player->gapless_play_thread_cond);
4789 player->bus_msg_q = g_queue_new();
4790 if (!player->bus_msg_q) {
4791 LOGE("failed to create queue for bus_msg");
4792 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4796 ret = _mmplayer_initialize_video_capture(player);
4797 if (ret != MM_ERROR_NONE) {
4798 LOGW("video capture is not supported");
4799 /* do not handle as error for headless profile */
4802 /* initialize resource manager */
4803 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4804 __resource_release_cb, player, &player->resource_manager)
4805 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4806 LOGE("failed to create resource manager");
4807 ret = MM_ERROR_PLAYER_INTERNAL;
4811 /* create video bo lock and cond */
4812 g_mutex_init(&player->video_bo_mutex);
4813 g_cond_init(&player->video_bo_cond);
4815 /* create subtitle info lock and cond */
4816 g_mutex_init(&player->subtitle_info_mutex);
4817 g_cond_init(&player->subtitle_info_cond);
4819 player->streaming_type = STREAMING_SERVICE_NONE;
4821 /* give default value of audio effect setting */
4822 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4823 player->sound.rg_enable = false;
4824 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4826 player->play_subtitle = FALSE;
4827 player->has_closed_caption = FALSE;
4828 player->pending_resume = FALSE;
4829 if (player->ini.dump_element_keyword[0][0] == '\0')
4830 player->ini.set_dump_element_flag = FALSE;
4832 player->ini.set_dump_element_flag = TRUE;
4834 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4835 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4836 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4838 /* Set video360 settings to their defaults for just-created player.
4841 player->is_360_feature_enabled = FALSE;
4842 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4843 LOGI("spherical feature info: %d", enabled);
4845 player->is_360_feature_enabled = TRUE;
4847 LOGE("failed to get spherical feature info");
4850 player->is_content_spherical = FALSE;
4851 player->is_video360_enabled = TRUE;
4852 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4853 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4854 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4855 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4856 player->video360_zoom = 1.0f;
4857 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4858 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4860 __mmplayer_initialize_video_roi(player);
4862 /* set player state to null */
4863 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4864 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4868 return MM_ERROR_NONE;
4872 g_mutex_clear(&player->fsink_lock);
4873 /* free update tag lock */
4874 g_mutex_clear(&player->update_tag_lock);
4875 g_queue_free(player->bus_msg_q);
4876 player->bus_msg_q = NULL;
4877 /* free gapless play thread */
4878 if (player->gapless_play_thread) {
4879 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4880 player->gapless_play_thread_exit = TRUE;
4881 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4882 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4884 g_thread_join(player->gapless_play_thread);
4885 player->gapless_play_thread = NULL;
4887 g_mutex_clear(&player->gapless_play_thread_mutex);
4888 g_cond_clear(&player->gapless_play_thread_cond);
4891 /* release attributes */
4892 _mmplayer_deconstruct_attribute(handle);
4900 __mmplayer_init_gstreamer(mmplayer_t *player)
4902 static gboolean initialized = FALSE;
4903 static const int max_argc = 50;
4905 gchar **argv = NULL;
4906 gchar **argv2 = NULL;
4912 LOGD("gstreamer already initialized.");
4917 argc = malloc(sizeof(int));
4918 argv = malloc(sizeof(gchar *) * max_argc);
4919 argv2 = malloc(sizeof(gchar *) * max_argc);
4921 if (!argc || !argv || !argv2)
4924 memset(argv, 0, sizeof(gchar *) * max_argc);
4925 memset(argv2, 0, sizeof(gchar *) * max_argc);
4929 argv[0] = g_strdup("mmplayer");
4932 for (i = 0; i < 5; i++) {
4933 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4934 if (strlen(player->ini.gst_param[i]) > 0) {
4935 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4940 /* we would not do fork for scanning plugins */
4941 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4944 /* check disable registry scan */
4945 if (player->ini.skip_rescan) {
4946 argv[*argc] = g_strdup("--gst-disable-registry-update");
4950 /* check disable segtrap */
4951 if (player->ini.disable_segtrap) {
4952 argv[*argc] = g_strdup("--gst-disable-segtrap");
4956 LOGD("initializing gstreamer with following parameter");
4957 LOGD("argc : %d", *argc);
4960 for (i = 0; i < arg_count; i++) {
4962 LOGD("argv[%d] : %s", i, argv2[i]);
4965 /* initializing gstreamer */
4966 if (!gst_init_check(argc, &argv, &err)) {
4967 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4974 for (i = 0; i < arg_count; i++) {
4976 LOGD("release - argv[%d] : %s", i, argv2[i]);
4978 MMPLAYER_FREEIF(argv2[i]);
4981 MMPLAYER_FREEIF(argv);
4982 MMPLAYER_FREEIF(argv2);
4983 MMPLAYER_FREEIF(argc);
4993 for (i = 0; i < arg_count; i++) {
4994 LOGD("free[%d] : %s", i, argv2[i]);
4995 MMPLAYER_FREEIF(argv2[i]);
4998 MMPLAYER_FREEIF(argv);
4999 MMPLAYER_FREEIF(argv2);
5000 MMPLAYER_FREEIF(argc);
5006 __mmplayer_check_async_state_transition(mmplayer_t *player)
5008 GstState element_state = GST_STATE_VOID_PENDING;
5009 GstState element_pending_state = GST_STATE_VOID_PENDING;
5010 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5011 GstElement *element = NULL;
5012 gboolean async = FALSE;
5014 /* check player handle */
5015 MMPLAYER_RETURN_IF_FAIL(player &&
5017 player->pipeline->mainbin &&
5018 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5021 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5023 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5024 LOGD("don't need to check the pipeline state");
5028 MMPLAYER_PRINT_STATE(player);
5030 /* wait for state transition */
5031 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5032 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5034 if (ret == GST_STATE_CHANGE_FAILURE) {
5035 LOGE(" [%s] state : %s pending : %s",
5036 GST_ELEMENT_NAME(element),
5037 gst_element_state_get_name(element_state),
5038 gst_element_state_get_name(element_pending_state));
5040 /* dump state of all element */
5041 _mmplayer_dump_pipeline_state(player);
5046 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5051 _mmplayer_destroy(MMHandleType handle)
5053 mmplayer_t *player = MM_PLAYER_CAST(handle);
5057 /* check player handle */
5058 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5060 /* destroy can called at anytime */
5061 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5063 /* check async state transition */
5064 __mmplayer_check_async_state_transition(player);
5066 /* release gapless play thread */
5067 if (player->gapless_play_thread) {
5068 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5069 player->gapless_play_thread_exit = TRUE;
5070 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5071 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5073 LOGD("waiting for gapless play thread exit");
5074 g_thread_join(player->gapless_play_thread);
5075 g_mutex_clear(&player->gapless_play_thread_mutex);
5076 g_cond_clear(&player->gapless_play_thread_cond);
5077 LOGD("gapless play thread released");
5080 _mmplayer_release_video_capture(player);
5082 /* release miscellaneous information */
5083 __mmplayer_release_misc(player);
5085 /* release pipeline */
5086 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5087 LOGE("failed to destroy pipeline");
5088 return MM_ERROR_PLAYER_INTERNAL;
5091 __mmplayer_destroy_hw_resource(player);
5093 g_queue_free(player->bus_msg_q);
5095 /* release subtitle info lock and cond */
5096 g_mutex_clear(&player->subtitle_info_mutex);
5097 g_cond_clear(&player->subtitle_info_cond);
5099 __mmplayer_release_dump_list(player->dump_list);
5101 /* release miscellaneous information.
5102 these info needs to be released after pipeline is destroyed. */
5103 __mmplayer_release_misc_post(player);
5105 /* release attributes */
5106 _mmplayer_deconstruct_attribute(handle);
5108 if (player->uri_info.uri_list) {
5109 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5110 player->uri_info.uri_list = NULL;
5114 g_mutex_clear(&player->fsink_lock);
5117 g_mutex_clear(&player->update_tag_lock);
5119 /* release video bo lock and cond */
5120 g_mutex_clear(&player->video_bo_mutex);
5121 g_cond_clear(&player->video_bo_cond);
5125 return MM_ERROR_NONE;
5129 _mmplayer_realize(MMHandleType hplayer)
5131 mmplayer_t *player = (mmplayer_t *)hplayer;
5132 int ret = MM_ERROR_NONE;
5135 MMHandleType attrs = 0;
5139 /* check player handle */
5140 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5142 /* check current state */
5143 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5145 attrs = MMPLAYER_GET_ATTRS(player);
5147 LOGE("fail to get attributes.");
5148 return MM_ERROR_PLAYER_INTERNAL;
5150 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5151 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5153 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5154 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5156 if (ret != MM_ERROR_NONE) {
5157 LOGE("failed to parse profile");
5162 if (uri && (strstr(uri, "es_buff://"))) {
5163 if (strstr(uri, "es_buff://push_mode"))
5164 player->es_player_push_mode = TRUE;
5166 player->es_player_push_mode = FALSE;
5169 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5170 LOGW("mms protocol is not supported format.");
5171 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5174 if (MMPLAYER_IS_STREAMING(player))
5175 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5177 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5179 player->smooth_streaming = FALSE;
5180 player->videodec_linked = 0;
5181 player->audiodec_linked = 0;
5182 player->textsink_linked = 0;
5183 player->is_external_subtitle_present = FALSE;
5184 player->is_external_subtitle_added_now = FALSE;
5185 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5186 player->video360_metadata.is_spherical = -1;
5187 player->is_openal_plugin_used = FALSE;
5188 player->subtitle_language_list = NULL;
5189 player->is_subtitle_force_drop = FALSE;
5191 _mmplayer_track_initialize(player);
5192 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5194 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5195 gint prebuffer_ms = 0, rebuffer_ms = 0;
5197 player->streamer = _mm_player_streaming_create();
5198 _mm_player_streaming_initialize(player->streamer, TRUE);
5200 mm_attrs_multiple_get(player->attrs, NULL,
5201 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5202 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5204 if (prebuffer_ms > 0) {
5205 prebuffer_ms = MAX(prebuffer_ms, 1000);
5206 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5209 if (rebuffer_ms > 0) {
5210 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5211 rebuffer_ms = MAX(rebuffer_ms, 1000);
5212 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5215 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5216 player->streamer->buffering_req.rebuffer_time);
5219 /* realize pipeline */
5220 ret = __mmplayer_gst_realize(player);
5221 if (ret != MM_ERROR_NONE)
5222 LOGE("fail to realize the player.");
5224 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5232 _mmplayer_unrealize(MMHandleType hplayer)
5234 mmplayer_t *player = (mmplayer_t *)hplayer;
5235 int ret = MM_ERROR_NONE;
5236 int rm_ret = MM_ERROR_NONE;
5237 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5241 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5243 MMPLAYER_CMD_UNLOCK(player);
5244 _mmplayer_bus_watcher_remove(player);
5245 /* destroy the gst bus msg thread which is created during realize.
5246 this funct have to be called before getting cmd lock. */
5247 _mmplayer_bus_msg_thread_destroy(player);
5248 MMPLAYER_CMD_LOCK(player);
5250 /* check current state */
5251 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5253 /* check async state transition */
5254 __mmplayer_check_async_state_transition(player);
5256 /* unrealize pipeline */
5257 ret = __mmplayer_gst_unrealize(player);
5259 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5260 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5261 if (rm_ret != MM_ERROR_NONE)
5262 LOGE("failed to release [%d] resources", res_idx);
5265 player->interrupted_by_resource = FALSE;
5272 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5274 mmplayer_t *player = (mmplayer_t *)hplayer;
5276 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5278 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5282 _mmplayer_get_state(MMHandleType hplayer, int *state)
5284 mmplayer_t *player = (mmplayer_t *)hplayer;
5286 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5288 *state = MMPLAYER_CURRENT_STATE(player);
5290 return MM_ERROR_NONE;
5294 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5296 GstElement *vol_element = NULL;
5297 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5300 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5301 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5303 /* check pipeline handle */
5304 if (!player->pipeline || !player->pipeline->audiobin) {
5305 LOGD("'%s' will be applied when audiobin is created", prop_name);
5307 /* NOTE : stored value will be used in create_audiobin
5308 * returning MM_ERROR_NONE here makes application to able to
5309 * set audio volume or mute at anytime.
5311 return MM_ERROR_NONE;
5314 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5315 volume_elem_id = MMPLAYER_A_SINK;
5317 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5319 LOGE("failed to get vol element %d", volume_elem_id);
5320 return MM_ERROR_PLAYER_INTERNAL;
5323 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5325 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5326 LOGE("there is no '%s' property", prop_name);
5327 return MM_ERROR_PLAYER_INTERNAL;
5330 if (!strcmp(prop_name, "volume")) {
5331 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5332 } else if (!strcmp(prop_name, "mute")) {
5333 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5335 LOGE("invalid property %s", prop_name);
5336 return MM_ERROR_PLAYER_INTERNAL;
5339 return MM_ERROR_NONE;
5343 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5345 int ret = MM_ERROR_NONE;
5346 mmplayer_t *player = (mmplayer_t *)hplayer;
5349 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5351 LOGD("volume = %f", volume);
5353 /* invalid factor range or not */
5354 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5355 LOGE("Invalid volume value");
5356 return MM_ERROR_INVALID_ARGUMENT;
5359 player->sound.volume = volume;
5361 ret = __mmplayer_gst_set_volume_property(player, "volume");
5368 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5370 mmplayer_t *player = (mmplayer_t *)hplayer;
5374 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5375 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5377 *volume = player->sound.volume;
5379 LOGD("current vol = %f", *volume);
5382 return MM_ERROR_NONE;
5386 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5388 int ret = MM_ERROR_NONE;
5389 mmplayer_t *player = (mmplayer_t *)hplayer;
5392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5394 LOGD("mute = %d", mute);
5396 player->sound.mute = mute;
5398 ret = __mmplayer_gst_set_volume_property(player, "mute");
5405 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5407 mmplayer_t *player = (mmplayer_t *)hplayer;
5411 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5412 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5414 *mute = player->sound.mute;
5416 LOGD("current mute = %d", *mute);
5420 return MM_ERROR_NONE;
5424 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5426 mmplayer_t *player = (mmplayer_t *)hplayer;
5430 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5432 player->audio_stream_changed_cb = callback;
5433 player->audio_stream_changed_cb_user_param = user_param;
5434 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5438 return MM_ERROR_NONE;
5442 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5444 mmplayer_t *player = (mmplayer_t *)hplayer;
5448 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5450 player->audio_decoded_cb = callback;
5451 player->audio_decoded_cb_user_param = user_param;
5452 player->audio_extract_opt = opt;
5453 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5457 return MM_ERROR_NONE;
5461 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5463 mmplayer_t *player = (mmplayer_t *)hplayer;
5467 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5469 if (callback && !player->bufmgr)
5470 player->bufmgr = tbm_bufmgr_init(-1);
5472 player->set_mode.video_export = (callback) ? true : false;
5473 player->video_decoded_cb = callback;
5474 player->video_decoded_cb_user_param = user_param;
5476 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5480 return MM_ERROR_NONE;
5484 _mmplayer_start(MMHandleType hplayer)
5486 mmplayer_t *player = (mmplayer_t *)hplayer;
5487 gint ret = MM_ERROR_NONE;
5491 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5493 /* check current state */
5494 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5496 /* start pipeline */
5497 ret = _mmplayer_gst_start(player);
5498 if (ret != MM_ERROR_NONE)
5499 LOGE("failed to start player.");
5501 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5502 LOGD("force playing start even during buffering");
5503 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5511 /* NOTE: post "not supported codec message" to application
5512 * when one codec is not found during AUTOPLUGGING in MSL.
5513 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5514 * And, if any codec is not found, don't send message here.
5515 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5518 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5520 MMMessageParamType msg_param;
5521 memset(&msg_param, 0, sizeof(MMMessageParamType));
5522 gboolean post_msg_direct = FALSE;
5526 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5528 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5529 player->not_supported_codec, player->can_support_codec);
5531 if (player->not_found_demuxer) {
5532 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5533 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5535 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5536 MMPLAYER_FREEIF(msg_param.data);
5538 return MM_ERROR_NONE;
5541 if (player->not_supported_codec) {
5542 if (player->can_support_codec) {
5543 // There is one codec to play
5544 post_msg_direct = TRUE;
5546 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5547 post_msg_direct = TRUE;
5550 if (post_msg_direct) {
5551 MMMessageParamType msg_param;
5552 memset(&msg_param, 0, sizeof(MMMessageParamType));
5554 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5555 LOGW("not found AUDIO codec, posting error code to application.");
5557 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5558 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5559 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5560 LOGW("not found VIDEO codec, posting error code to application.");
5562 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5563 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5566 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5568 MMPLAYER_FREEIF(msg_param.data);
5570 return MM_ERROR_NONE;
5572 // no any supported codec case
5573 LOGW("not found any codec, posting error code to application.");
5575 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5576 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5577 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5579 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5580 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5583 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5585 MMPLAYER_FREEIF(msg_param.data);
5591 return MM_ERROR_NONE;
5594 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5596 GstState element_state = GST_STATE_VOID_PENDING;
5597 GstState element_pending_state = GST_STATE_VOID_PENDING;
5598 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5599 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5601 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5603 MMPLAYER_RECONFIGURE_LOCK(player);
5604 if (!player->gapless.reconfigure) {
5605 MMPLAYER_RECONFIGURE_UNLOCK(player);
5609 LOGI("reconfigure is under process");
5610 MMPLAYER_RECONFIGURE_WAIT(player);
5611 MMPLAYER_RECONFIGURE_UNLOCK(player);
5612 LOGI("reconfigure is completed.");
5614 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5615 &element_state, &element_pending_state, timeout * GST_SECOND);
5616 if (result == GST_STATE_CHANGE_FAILURE)
5617 LOGW("failed to get pipeline state in %d sec", timeout);
5622 /* NOTE : it should be able to call 'stop' anytime*/
5624 _mmplayer_stop(MMHandleType hplayer)
5626 mmplayer_t *player = (mmplayer_t *)hplayer;
5627 int ret = MM_ERROR_NONE;
5631 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5633 /* check current state */
5634 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5636 /* need to wait till the rebuilding pipeline is completed */
5637 __mmplayer_check_pipeline_reconfigure_state(player);
5638 MMPLAYER_RECONFIGURE_LOCK(player);
5639 __mmplayer_reset_gapless_state(player);
5640 MMPLAYER_RECONFIGURE_UNLOCK(player);
5642 /* NOTE : application should not wait for EOS after calling STOP */
5643 _mmplayer_cancel_eos_timer(player);
5646 player->seek_state = MMPLAYER_SEEK_NONE;
5649 ret = _mmplayer_gst_stop(player);
5651 if (ret != MM_ERROR_NONE)
5652 LOGE("failed to stop player.");
5660 _mmplayer_pause(MMHandleType hplayer)
5662 mmplayer_t *player = (mmplayer_t *)hplayer;
5663 gint64 pos_nsec = 0;
5664 gboolean async = FALSE;
5665 gint ret = MM_ERROR_NONE;
5669 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5671 /* check current state */
5672 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5674 /* check pipeline reconfigure state */
5675 __mmplayer_check_pipeline_reconfigure_state(player);
5677 switch (MMPLAYER_CURRENT_STATE(player)) {
5678 case MM_PLAYER_STATE_READY:
5680 /* check prepare async or not.
5681 * In the case of streaming playback, it's recommended to avoid blocking wait.
5683 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5684 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5686 /* Changing back sync of rtspsrc to async */
5687 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5688 LOGD("async prepare working mode for rtsp");
5694 case MM_PLAYER_STATE_PLAYING:
5696 /* NOTE : store current point to overcome some bad operation
5697 *(returning zero when getting current position in paused state) of some
5700 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5701 LOGW("getting current position failed in paused");
5703 player->last_position = pos_nsec;
5705 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5706 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5707 This causes problem is position calculation during normal pause resume scenarios also.
5708 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5709 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5710 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5711 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5717 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5718 LOGD("doing async pause in case of ms buff src");
5722 /* pause pipeline */
5723 ret = _mmplayer_gst_pause(player, async);
5724 if (ret != MM_ERROR_NONE) {
5725 LOGE("failed to pause player. ret : 0x%x", ret);
5726 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5730 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5731 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5732 LOGE("failed to update display_rotation");
5736 return MM_ERROR_NONE;
5739 /* in case of streaming, pause could take long time.*/
5741 _mmplayer_abort_pause(MMHandleType hplayer)
5743 mmplayer_t *player = (mmplayer_t *)hplayer;
5744 int ret = MM_ERROR_NONE;
5748 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5750 player->pipeline->mainbin,
5751 MM_ERROR_PLAYER_NOT_INITIALIZED);
5753 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5754 LOGD("set the videobin state to READY");
5755 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5756 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5760 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5761 LOGD("set the audiobin state to READY");
5762 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5763 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5767 LOGD("set the pipeline state to READY");
5768 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5769 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5771 if (ret != MM_ERROR_NONE) {
5772 LOGE("fail to change state to READY");
5773 return MM_ERROR_PLAYER_INTERNAL;
5776 LOGD("succeeded in changing state to READY");
5781 _mmplayer_resume(MMHandleType hplayer)
5783 mmplayer_t *player = (mmplayer_t *)hplayer;
5784 int ret = MM_ERROR_NONE;
5785 gboolean async = FALSE;
5789 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5791 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5792 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5793 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5797 /* Changing back sync mode rtspsrc to async */
5798 LOGD("async resume for rtsp case");
5802 /* check current state */
5803 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5805 ret = _mmplayer_gst_resume(player, async);
5806 if (ret != MM_ERROR_NONE)
5807 LOGE("failed to resume player.");
5809 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5810 LOGD("force resume even during buffering");
5811 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5820 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5822 mmplayer_t *player = (mmplayer_t *)hplayer;
5823 gint64 pos_nsec = 0;
5824 int ret = MM_ERROR_NONE;
5826 signed long long start = 0, stop = 0;
5827 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5830 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5831 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5833 /* The sound of video is not supported under 0.0 and over 2.0. */
5834 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5835 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5838 _mmplayer_set_mute(hplayer, mute);
5840 if (player->playback_rate == rate)
5841 return MM_ERROR_NONE;
5843 /* If the position is reached at start potion during fast backward, EOS is posted.
5844 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5846 player->playback_rate = rate;
5848 current_state = MMPLAYER_CURRENT_STATE(player);
5850 if (current_state != MM_PLAYER_STATE_PAUSED)
5851 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5853 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5855 if ((current_state == MM_PLAYER_STATE_PAUSED)
5856 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5857 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5858 pos_nsec = player->last_position;
5863 stop = GST_CLOCK_TIME_NONE;
5865 start = GST_CLOCK_TIME_NONE;
5869 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5870 player->playback_rate,
5872 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5873 GST_SEEK_TYPE_SET, start,
5874 GST_SEEK_TYPE_SET, stop)) {
5875 LOGE("failed to set speed playback");
5876 return MM_ERROR_PLAYER_SEEK;
5879 LOGD("succeeded to set speed playback as %0.1f", rate);
5883 return MM_ERROR_NONE;;
5887 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5889 mmplayer_t *player = (mmplayer_t *)hplayer;
5890 int ret = MM_ERROR_NONE;
5894 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5896 /* check pipeline reconfigure state */
5897 __mmplayer_check_pipeline_reconfigure_state(player);
5899 ret = _mmplayer_gst_set_position(player, position, FALSE);
5907 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5909 mmplayer_t *player = (mmplayer_t *)hplayer;
5910 int ret = MM_ERROR_NONE;
5912 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5913 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5915 if (g_strrstr(player->type, "video/mpegts"))
5916 __mmplayer_update_duration_value(player);
5918 *duration = player->duration;
5923 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5925 mmplayer_t *player = (mmplayer_t *)hplayer;
5926 int ret = MM_ERROR_NONE;
5928 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5930 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5936 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5938 mmplayer_t *player = (mmplayer_t *)hplayer;
5939 int ret = MM_ERROR_NONE;
5943 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5945 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5953 __mmplayer_is_midi_type(gchar *str_caps)
5955 if ((g_strrstr(str_caps, "audio/midi")) ||
5956 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5957 (g_strrstr(str_caps, "application/x-smaf")) ||
5958 (g_strrstr(str_caps, "audio/x-imelody")) ||
5959 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5960 (g_strrstr(str_caps, "audio/xmf")) ||
5961 (g_strrstr(str_caps, "audio/mxmf"))) {
5970 __mmplayer_is_only_mp3_type(gchar *str_caps)
5972 if (g_strrstr(str_caps, "application/x-id3") ||
5973 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5979 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5981 GstStructure *caps_structure = NULL;
5982 gint samplerate = 0;
5986 MMPLAYER_RETURN_IF_FAIL(player && caps);
5988 caps_structure = gst_caps_get_structure(caps, 0);
5990 /* set stream information */
5991 gst_structure_get_int(caps_structure, "rate", &samplerate);
5992 gst_structure_get_int(caps_structure, "channels", &channels);
5994 mm_player_set_attribute((MMHandleType)player, NULL,
5995 "content_audio_samplerate", samplerate,
5996 "content_audio_channels", channels, NULL);
5998 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6002 __mmplayer_update_content_type_info(mmplayer_t *player)
6005 MMPLAYER_RETURN_IF_FAIL(player && player->type);
6007 if (__mmplayer_is_midi_type(player->type)) {
6008 player->bypass_audio_effect = TRUE;
6012 if (!player->streamer) {
6013 LOGD("no need to check streaming type");
6017 if (g_strrstr(player->type, "application/x-hls")) {
6018 /* If it can't know exact type when it parses uri because of redirection case,
6019 * it will be fixed by typefinder or when doing autoplugging.
6021 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6022 player->streamer->is_adaptive_streaming = TRUE;
6023 } else if (g_strrstr(player->type, "application/dash+xml")) {
6024 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6025 player->streamer->is_adaptive_streaming = TRUE;
6028 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6029 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
6030 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6032 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6033 if (player->streamer->is_adaptive_streaming)
6034 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6036 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6040 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6045 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6046 GstCaps *caps, gpointer data)
6048 mmplayer_t *player = (mmplayer_t *)data;
6052 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6054 /* store type string */
6055 if (player->type_caps) {
6056 gst_caps_unref(player->type_caps);
6057 player->type_caps = NULL;
6060 player->type_caps = gst_caps_copy(caps);
6061 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
6063 MMPLAYER_FREEIF(player->type);
6064 player->type = gst_caps_to_string(caps);
6066 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6067 player, player->type, probability, gst_caps_get_size(caps));
6069 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6070 (g_strrstr(player->type, "audio/x-raw-int"))) {
6071 LOGE("not support media format");
6073 if (player->msg_posted == FALSE) {
6074 MMMessageParamType msg_param;
6075 memset(&msg_param, 0, sizeof(MMMessageParamType));
6077 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6078 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6080 /* don't post more if one was sent already */
6081 player->msg_posted = TRUE;
6086 __mmplayer_update_content_type_info(player);
6088 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6091 pad = gst_element_get_static_pad(tf, "src");
6093 LOGE("fail to get typefind src pad.");
6097 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6098 gboolean async = FALSE;
6099 LOGE("failed to autoplug %s", player->type);
6101 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6103 if (async && player->msg_posted == FALSE)
6104 __mmplayer_handle_missed_plugin(player);
6106 gst_object_unref(GST_OBJECT(pad));
6113 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6115 GstElement *decodebin = NULL;
6119 /* create decodebin */
6120 decodebin = gst_element_factory_make("decodebin", NULL);
6123 LOGE("fail to create decodebin");
6127 /* raw pad handling signal */
6128 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6129 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6131 /* no-more-pad pad handling signal */
6132 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6133 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6135 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6136 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6138 /* This signal is emitted when a pad for which there is no further possible
6139 decoding is added to the decodebin.*/
6140 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6141 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6143 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6144 before looking for any elements that can handle that stream.*/
6145 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6146 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6148 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6149 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6150 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6152 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6153 before looking for any elements that can handle that stream.*/
6154 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6155 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6157 /* This signal is emitted once decodebin has finished decoding all the data.*/
6158 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6159 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6161 /* This signal is emitted when a element is added to the bin.*/
6162 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6163 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6170 __mmplayer_gst_make_queue2(mmplayer_t *player)
6172 GstElement *queue2 = NULL;
6173 gint64 dur_bytes = 0L;
6174 mmplayer_gst_element_t *mainbin = NULL;
6175 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6178 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6180 mainbin = player->pipeline->mainbin;
6182 queue2 = gst_element_factory_make("queue2", "queue2");
6184 LOGE("failed to create buffering queue element");
6188 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6189 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6191 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6193 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6194 * skip the pull mode(file or ring buffering) setting. */
6195 if (dur_bytes > 0) {
6196 if (!g_strrstr(player->type, "video/mpegts")) {
6197 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6198 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6204 _mm_player_streaming_set_queue2(player->streamer,
6208 (guint64)dur_bytes); /* no meaning at the moment */
6214 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6216 mmplayer_gst_element_t *mainbin = NULL;
6217 GstElement *decodebin = NULL;
6218 GstElement *queue2 = NULL;
6219 GstPad *sinkpad = NULL;
6220 GstPad *qsrcpad = NULL;
6223 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6225 mainbin = player->pipeline->mainbin;
6227 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6229 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6230 LOGW("need to check: muxed buffer is not null");
6233 queue2 = __mmplayer_gst_make_queue2(player);
6235 LOGE("failed to make queue2");
6239 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6240 LOGE("failed to add buffering queue");
6244 sinkpad = gst_element_get_static_pad(queue2, "sink");
6245 qsrcpad = gst_element_get_static_pad(queue2, "src");
6247 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6248 LOGE("failed to link [%s:%s]-[%s:%s]",
6249 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6253 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6254 LOGE("failed to sync queue2 state with parent");
6258 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6259 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6263 gst_object_unref(GST_OBJECT(sinkpad));
6267 /* create decodebin */
6268 decodebin = _mmplayer_gst_make_decodebin(player);
6270 LOGE("failed to make decodebin");
6274 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6275 LOGE("failed to add decodebin");
6279 /* to force caps on the decodebin element and avoid reparsing stuff by
6280 * typefind. It also avoids a deadlock in the way typefind activates pads in
6281 * the state change */
6282 g_object_set(decodebin, "sink-caps", caps, NULL);
6284 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6286 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6287 LOGE("failed to link [%s:%s]-[%s:%s]",
6288 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6292 gst_object_unref(GST_OBJECT(sinkpad));
6294 gst_object_unref(GST_OBJECT(qsrcpad));
6297 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6298 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6300 /* set decodebin property about buffer in streaming playback. *
6301 * in case of HLS/DASH, it does not need to have big buffer *
6302 * because it is kind of adaptive streaming. */
6303 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6304 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6305 gint high_percent = 0;
6307 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6308 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6310 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6312 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6314 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6315 "high-percent", high_percent,
6316 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6317 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6318 "max-size-buffers", 0, NULL); // disable or automatic
6321 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6322 LOGE("failed to sync decodebin state with parent");
6333 gst_object_unref(GST_OBJECT(sinkpad));
6336 gst_object_unref(GST_OBJECT(qsrcpad));
6339 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6340 * You need to explicitly set elements to the NULL state before
6341 * dropping the final reference, to allow them to clean up.
6343 gst_element_set_state(queue2, GST_STATE_NULL);
6345 /* And, it still has a parent "player".
6346 * You need to let the parent manage the object instead of unreffing the object directly.
6348 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6349 LOGE("failed to remove queue2");
6350 gst_object_unref(queue2);
6356 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6357 * You need to explicitly set elements to the NULL state before
6358 * dropping the final reference, to allow them to clean up.
6360 gst_element_set_state(decodebin, GST_STATE_NULL);
6362 /* And, it still has a parent "player".
6363 * You need to let the parent manage the object instead of unreffing the object directly.
6366 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6367 LOGE("failed to remove decodebin");
6368 gst_object_unref(decodebin);
6377 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6381 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6382 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6384 LOGD("class : %s, mime : %s", factory_class, mime);
6386 /* add missing plugin */
6387 /* NOTE : msl should check missing plugin for image mime type.
6388 * Some motion jpeg clips can have playable audio track.
6389 * So, msl have to play audio after displaying popup written video format not supported.
6391 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6392 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6393 LOGD("not found demuxer");
6394 player->not_found_demuxer = TRUE;
6395 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6401 if (!g_strrstr(factory_class, "Demuxer")) {
6402 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6403 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6404 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6406 /* check that clip have multi tracks or not */
6407 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6408 LOGD("video plugin is already linked");
6410 LOGW("add VIDEO to missing plugin");
6411 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6412 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6414 } else if (g_str_has_prefix(mime, "audio")) {
6415 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6416 LOGD("audio plugin is already linked");
6418 LOGW("add AUDIO to missing plugin");
6419 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6420 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6428 return MM_ERROR_NONE;
6432 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6434 mmplayer_t *player = (mmplayer_t *)data;
6438 MMPLAYER_RETURN_IF_FAIL(player);
6440 /* remove fakesink. */
6441 if (!_mmplayer_gst_remove_fakesink(player,
6442 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6443 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6444 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6445 * source element are not same. To overcome this situation, this function will called
6446 * several places and several times. Therefore, this is not an error case.
6451 LOGD("[handle: %p] pipeline has completely constructed", player);
6453 if ((player->msg_posted == FALSE) &&
6454 (player->cmd >= MMPLAYER_COMMAND_START))
6455 __mmplayer_handle_missed_plugin(player);
6457 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6461 __mmplayer_check_profile(void)
6464 static int profile_tv = -1;
6466 if (__builtin_expect(profile_tv != -1, 1))
6469 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6470 switch (*profileName) {
6485 __mmplayer_get_next_uri(mmplayer_t *player)
6487 mmplayer_parse_profile_t profile;
6489 guint num_of_list = 0;
6492 num_of_list = g_list_length(player->uri_info.uri_list);
6493 uri_idx = player->uri_info.uri_idx;
6495 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6496 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6497 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6499 LOGW("next uri does not exist");
6503 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6504 LOGE("failed to parse profile");
6508 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6509 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6510 LOGW("uri type is not supported(%d)", profile.uri_type);
6514 LOGD("success to find next uri %d", uri_idx);
6518 if (!uri || uri_idx == num_of_list) {
6519 LOGE("failed to find next uri");
6523 player->uri_info.uri_idx = uri_idx;
6524 if (mm_player_set_attribute((MMHandleType)player, NULL,
6525 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6526 LOGE("failed to set attribute");
6530 SECURE_LOGD("next playback uri: %s", uri);
6535 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6537 #define REPEAT_COUNT_INFINITE -1
6538 #define REPEAT_COUNT_MIN 2
6539 #define ORIGINAL_URI_ONLY 1
6541 MMHandleType attrs = 0;
6545 guint num_of_uri = 0;
6546 int profile_tv = -1;
6550 LOGD("checking for gapless play option");
6552 if (player->build_audio_offload) {
6553 LOGE("offload path is not supportable.");
6557 if (player->pipeline->textbin) {
6558 LOGE("subtitle path is enabled. gapless play is not supported.");
6562 attrs = MMPLAYER_GET_ATTRS(player);
6564 LOGE("fail to get attributes.");
6568 mm_attrs_multiple_get(player->attrs, NULL,
6569 "content_video_found", &video,
6570 "profile_play_count", &count,
6571 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6573 /* gapless playback is not supported in case of video at TV profile. */
6574 profile_tv = __mmplayer_check_profile();
6575 if (profile_tv && video) {
6576 LOGW("not support video gapless playback");
6580 /* check repeat count in case of audio */
6582 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6583 LOGW("gapless is disabled");
6587 num_of_uri = g_list_length(player->uri_info.uri_list);
6589 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6591 if (num_of_uri == ORIGINAL_URI_ONLY) {
6592 /* audio looping path */
6593 if (count >= REPEAT_COUNT_MIN) {
6594 /* decrease play count */
6595 /* we succeeded to rewind. update play count and then wait for next EOS */
6597 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6598 } else if (count != REPEAT_COUNT_INFINITE) {
6599 LOGD("there is no next uri and no repeat");
6602 LOGD("looping cnt %d", count);
6604 /* gapless playback path */
6605 if (!__mmplayer_get_next_uri(player)) {
6606 LOGE("failed to get next uri");
6613 LOGE("unable to play gapless path. EOS will be posted soon");
6618 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6620 GstPad *sinkpad = g_value_get_object (item);
6621 GstElement *element = GST_ELEMENT(user_data);
6622 if (!sinkpad || !element) {
6623 LOGE("invalid parameter");
6627 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6628 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6632 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6634 mmplayer_gst_element_t *sinkbin = NULL;
6635 main_element_id_e concatId = MMPLAYER_M_NUM;
6636 main_element_id_e sinkId = MMPLAYER_M_NUM;
6637 gboolean send_notice = FALSE;
6638 GstElement *element;
6642 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6644 LOGD("type %d", type);
6647 case MM_PLAYER_TRACK_TYPE_AUDIO:
6648 concatId = MMPLAYER_M_A_CONCAT;
6649 sinkId = MMPLAYER_A_BIN;
6650 sinkbin = player->pipeline->audiobin;
6652 case MM_PLAYER_TRACK_TYPE_VIDEO:
6653 concatId = MMPLAYER_M_V_CONCAT;
6654 sinkId = MMPLAYER_V_BIN;
6655 sinkbin = player->pipeline->videobin;
6658 case MM_PLAYER_TRACK_TYPE_TEXT:
6659 concatId = MMPLAYER_M_T_CONCAT;
6660 sinkId = MMPLAYER_T_BIN;
6661 sinkbin = player->pipeline->textbin;
6664 LOGE("requested type is not supportable");
6669 element = player->pipeline->mainbin[concatId].gst;
6673 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6674 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6675 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6676 if (srcpad && sinkpad) {
6677 /* after getting drained signal there is no data flows, so no need to do pad_block */
6678 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6679 gst_pad_unlink(srcpad, sinkpad);
6681 /* send custom event to sink pad to handle it at video sink */
6683 LOGD("send custom event to sinkpad");
6684 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6685 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6686 gst_pad_send_event(sinkpad, event);
6689 gst_object_unref(srcpad);
6690 gst_object_unref(sinkpad);
6693 LOGD("release concat request pad");
6694 /* release and unref requests pad from the selector */
6695 iter = gst_element_iterate_sink_pads(element);
6696 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6697 gst_iterator_resync(iter);
6698 gst_iterator_free(iter);
6704 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6706 mmplayer_track_t *selector = &player->track[type];
6707 mmplayer_gst_element_t *sinkbin = NULL;
6708 main_element_id_e selectorId = MMPLAYER_M_NUM;
6709 main_element_id_e sinkId = MMPLAYER_M_NUM;
6710 GstPad *srcpad = NULL;
6711 GstPad *sinkpad = NULL;
6712 gboolean send_notice = FALSE;
6715 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6717 LOGD("type %d", type);
6720 case MM_PLAYER_TRACK_TYPE_AUDIO:
6721 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6722 sinkId = MMPLAYER_A_BIN;
6723 sinkbin = player->pipeline->audiobin;
6725 case MM_PLAYER_TRACK_TYPE_VIDEO:
6726 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6727 sinkId = MMPLAYER_V_BIN;
6728 sinkbin = player->pipeline->videobin;
6731 case MM_PLAYER_TRACK_TYPE_TEXT:
6732 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6733 sinkId = MMPLAYER_T_BIN;
6734 sinkbin = player->pipeline->textbin;
6737 LOGE("requested type is not supportable");
6742 if (player->pipeline->mainbin[selectorId].gst) {
6745 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6747 if (selector->event_probe_id != 0)
6748 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6749 selector->event_probe_id = 0;
6751 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6752 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6754 if (srcpad && sinkpad) {
6755 /* after getting drained signal there is no data flows, so no need to do pad_block */
6756 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6757 gst_pad_unlink(srcpad, sinkpad);
6759 /* send custom event to sink pad to handle it at video sink */
6761 LOGD("send custom event to sinkpad");
6762 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6763 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6764 gst_pad_send_event(sinkpad, event);
6768 gst_object_unref(sinkpad);
6771 gst_object_unref(srcpad);
6774 LOGD("selector release");
6776 /* release and unref requests pad from the selector */
6777 for (n = 0; n < selector->streams->len; n++) {
6778 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6779 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6782 g_ptr_array_set_size(selector->streams, 0);
6784 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6785 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6786 player->pipeline->mainbin[selectorId].gst)) {
6787 LOGE("failed to remove selector");
6788 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6791 player->pipeline->mainbin[selectorId].gst = NULL;
6799 __mmplayer_deactivate_old_path(mmplayer_t *player)
6802 MMPLAYER_RETURN_IF_FAIL(player);
6804 if (MMPLAYER_USE_DECODEBIN(player)) {
6805 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6806 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6807 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6808 LOGE("deactivate selector error");
6812 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6813 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6814 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6815 LOGE("deactivate concat error");
6820 _mmplayer_track_destroy(player);
6821 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6823 if (player->streamer) {
6824 _mm_player_streaming_initialize(player->streamer, FALSE);
6825 _mm_player_streaming_destroy(player->streamer);
6826 player->streamer = NULL;
6829 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6835 if (!player->msg_posted) {
6836 MMMessageParamType msg = {0,};
6839 msg.code = MM_ERROR_PLAYER_INTERNAL;
6840 LOGE("gapless_uri_play> deactivate error");
6842 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6843 player->msg_posted = TRUE;
6849 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6851 int result = MM_ERROR_NONE;
6852 mmplayer_t *player = (mmplayer_t *)hplayer;
6855 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6856 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6858 if (mm_player_set_attribute(hplayer, NULL,
6859 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6860 LOGE("failed to set attribute");
6861 result = MM_ERROR_PLAYER_INTERNAL;
6863 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6864 LOGE("failed to add the original uri in the uri list.");
6872 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6874 mmplayer_t *player = (mmplayer_t *)hplayer;
6875 guint num_of_list = 0;
6879 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6880 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6882 if (player->pipeline && player->pipeline->textbin) {
6883 LOGE("subtitle path is enabled.");
6884 return MM_ERROR_PLAYER_INVALID_STATE;
6887 num_of_list = g_list_length(player->uri_info.uri_list);
6889 if (is_first_path) {
6890 if (num_of_list == 0) {
6891 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6892 SECURE_LOGD("add original path : %s", uri);
6894 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6895 player->uri_info.uri_list = g_list_prepend(
6896 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6897 SECURE_LOGD("change original path : %s", uri);
6900 MMHandleType attrs = 0;
6901 attrs = MMPLAYER_GET_ATTRS(player);
6903 if (num_of_list == 0) {
6904 char *original_uri = NULL;
6907 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6909 if (!original_uri) {
6910 LOGE("there is no original uri.");
6911 return MM_ERROR_PLAYER_INVALID_STATE;
6914 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6915 player->uri_info.uri_idx = 0;
6917 SECURE_LOGD("add original path at first : %s", original_uri);
6921 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6922 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6926 return MM_ERROR_NONE;
6930 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6932 mmplayer_t *player = (mmplayer_t *)hplayer;
6933 char *next_uri = NULL;
6934 guint num_of_list = 0;
6937 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6939 num_of_list = g_list_length(player->uri_info.uri_list);
6941 if (num_of_list > 0) {
6942 gint uri_idx = player->uri_info.uri_idx;
6944 if (uri_idx < num_of_list - 1)
6949 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6950 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6952 *uri = g_strdup(next_uri);
6956 return MM_ERROR_NONE;
6960 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6961 GstCaps *caps, gpointer data)
6963 mmplayer_t *player = (mmplayer_t *)data;
6964 const gchar *klass = NULL;
6965 const gchar *mime = NULL;
6966 gchar *caps_str = NULL;
6968 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6969 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6970 caps_str = gst_caps_to_string(caps);
6972 LOGW("unknown type of caps : %s from %s",
6973 caps_str, GST_ELEMENT_NAME(elem));
6975 MMPLAYER_FREEIF(caps_str);
6977 /* There is no available codec. */
6978 __mmplayer_check_not_supported_codec(player, klass, mime);
6982 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6983 GstCaps *caps, gpointer data)
6985 mmplayer_t *player = (mmplayer_t *)data;
6986 const char *mime = NULL;
6987 gboolean ret = TRUE;
6989 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6990 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6992 if (g_str_has_prefix(mime, "audio")) {
6993 GstStructure *caps_structure = NULL;
6994 gint samplerate = 0;
6996 gchar *caps_str = NULL;
6998 caps_structure = gst_caps_get_structure(caps, 0);
6999 gst_structure_get_int(caps_structure, "rate", &samplerate);
7000 gst_structure_get_int(caps_structure, "channels", &channels);
7002 if ((channels > 0 && samplerate == 0)) {
7003 LOGD("exclude audio...");
7007 caps_str = gst_caps_to_string(caps);
7008 /* set it directly because not sent by TAG */
7009 if (g_strrstr(caps_str, "mobile-xmf"))
7010 mm_player_set_attribute((MMHandleType)player, NULL,
7011 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7013 MMPLAYER_FREEIF(caps_str);
7014 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7015 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7016 LOGD("video is already linked, allow the stream switch");
7019 LOGD("video is already linked");
7023 LOGD("found new stream");
7030 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7032 gboolean ret = FALSE;
7033 GDBusConnection *conn = NULL;
7035 GVariant *result = NULL;
7036 const gchar *dbus_device_type = NULL;
7037 const gchar *dbus_ret = NULL;
7040 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7042 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7047 result = g_dbus_connection_call_sync(conn,
7048 "org.pulseaudio.Server",
7049 "/org/pulseaudio/StreamManager",
7050 "org.pulseaudio.StreamManager",
7051 "GetCurrentMediaRoutingPath",
7052 g_variant_new("(s)", "out"),
7053 G_VARIANT_TYPE("(ss)"),
7054 G_DBUS_CALL_FLAGS_NONE,
7058 if (!result || err) {
7059 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7064 /* device type is listed in stream-map.json at mmfw-sysconf */
7065 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7067 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7068 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7071 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7072 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7073 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7074 LOGD("audio offload is supportable");
7080 LOGD("audio offload is not supportable");
7083 g_variant_unref(result);
7085 g_object_unref(conn);
7090 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7092 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7093 gint64 position = 0;
7095 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7096 player->pipeline && player->pipeline->mainbin);
7098 MMPLAYER_CMD_LOCK(player);
7099 current_state = MMPLAYER_CURRENT_STATE(player);
7101 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7102 LOGW("getting current position failed in paused");
7104 _mmplayer_unrealize((MMHandleType)player);
7105 _mmplayer_realize((MMHandleType)player);
7107 _mmplayer_set_position((MMHandleType)player, position);
7109 /* async not to be blocked in streaming case */
7110 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7112 _mmplayer_pause((MMHandleType)player);
7114 if (current_state == MM_PLAYER_STATE_PLAYING)
7115 _mmplayer_start((MMHandleType)player);
7116 MMPLAYER_CMD_UNLOCK(player);
7118 LOGD("rebuilding audio pipeline is completed.");
7121 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7123 mmplayer_t *player = (mmplayer_t *)user_data;
7124 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7125 gboolean is_supportable = FALSE;
7127 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7128 LOGW("failed to get device type");
7130 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7132 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7133 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7134 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7135 LOGD("ignore this dev connected info");
7139 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7140 if (player->build_audio_offload == is_supportable) {
7141 LOGD("keep current pipeline without re-building");
7145 /* rebuild pipeline */
7146 LOGD("re-build pipeline - offload: %d", is_supportable);
7147 player->build_audio_offload = FALSE;
7148 __mmplayer_rebuild_audio_pipeline(player);
7154 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7156 unsigned int id = 0;
7158 if (player->audio_device_cb_id != 0) {
7159 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7163 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7164 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7165 LOGD("added device connected cb (%u)", id);
7166 player->audio_device_cb_id = id;
7168 LOGW("failed to add device connected cb");
7175 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7177 mmplayer_t *player = (mmplayer_t *)hplayer;
7180 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7181 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7183 *activated = player->build_audio_offload;
7185 LOGD("offload activated : %d", (int)*activated);
7188 return MM_ERROR_NONE;
7192 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7195 this function need to be updated according to the supported media format
7196 @see player->ini.audio_offload_media_format */
7198 if (__mmplayer_is_only_mp3_type(player->type)) {
7199 LOGD("offload supportable media format type");
7207 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7209 gboolean ret = FALSE;
7210 GstElementFactory *factory = NULL;
7213 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7215 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7216 if (!__mmplayer_is_offload_supported_type(player))
7219 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7220 LOGD("there is no audio offload sink");
7224 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7225 LOGW("there is no audio device type to support offload");
7229 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7231 LOGW("there is no installed audio offload sink element");
7234 gst_object_unref(factory);
7236 if (_mmplayer_acquire_hw_resource(player,
7237 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7238 LOGE("failed to acquire audio offload decoder resource");
7242 if (!__mmplayer_add_audio_device_connected_cb(player))
7245 if (!__mmplayer_is_audio_offload_device_type(player))
7248 LOGD("audio offload can be built");
7253 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7259 static GstAutoplugSelectResult
7260 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7262 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7263 int audio_offload = 0;
7265 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7266 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7268 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7269 LOGD("expose audio path to build offload output path");
7270 player->build_audio_offload = TRUE;
7271 /* update codec info */
7272 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7273 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7274 player->audiodec_linked = 1;
7276 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7280 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7281 And need to consider the multi-track audio content.
7282 There is no HW audio decoder in public. */
7284 /* set stream information */
7285 if (!player->audiodec_linked)
7286 _mmplayer_set_audio_attrs(player, caps);
7288 /* update codec info */
7289 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7290 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7291 player->audiodec_linked = 1;
7293 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7295 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7296 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7298 /* mark video decoder for acquire */
7299 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7300 LOGW("video decoder resource is already acquired, skip it.");
7301 ret = GST_AUTOPLUG_SELECT_SKIP;
7305 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7306 LOGE("failed to acquire video decoder resource");
7307 ret = GST_AUTOPLUG_SELECT_SKIP;
7310 player->interrupted_by_resource = FALSE;
7313 /* update codec info */
7314 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7315 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7316 player->videodec_linked = 1;
7324 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7325 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7327 #define DEFAULT_IDX 0xFFFF
7328 #define MIN_FACTORY_NUM 2
7329 mmplayer_t *player = (mmplayer_t *)data;
7330 GValueArray *new_factories = NULL;
7331 GValue val = { 0, };
7332 GstElementFactory *factory = NULL;
7333 const gchar *klass = NULL;
7334 gchar *factory_name = NULL;
7335 guint hw_dec_idx = DEFAULT_IDX;
7336 guint first_sw_dec_idx = DEFAULT_IDX;
7337 guint last_sw_dec_idx = DEFAULT_IDX;
7338 guint new_pos = DEFAULT_IDX;
7339 guint rm_pos = DEFAULT_IDX;
7340 int audio_codec_type;
7341 int video_codec_type;
7342 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7344 if (factories->n_values < MIN_FACTORY_NUM)
7347 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7348 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7351 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7353 for (int i = 0 ; i < factories->n_values ; i++) {
7354 gchar *hw_dec_info = NULL;
7355 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7357 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7359 LOGW("failed to get factory object");
7362 klass = gst_element_factory_get_klass(factory);
7363 factory_name = GST_OBJECT_NAME(factory);
7366 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7368 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7369 if (!player->need_audio_dec_sorting) {
7370 LOGD("sorting is not required");
7373 codec_type = audio_codec_type;
7374 hw_dec_info = player->ini.audiocodec_element_hw;
7375 sw_dec_info = player->ini.audiocodec_element_sw;
7376 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7377 if (!player->need_video_dec_sorting) {
7378 LOGD("sorting is not required");
7381 codec_type = video_codec_type;
7382 hw_dec_info = player->ini.videocodec_element_hw;
7383 sw_dec_info = player->ini.videocodec_element_sw;
7388 if (g_strrstr(factory_name, hw_dec_info)) {
7391 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7392 if (strstr(factory_name, sw_dec_info[j])) {
7393 last_sw_dec_idx = i;
7394 if (first_sw_dec_idx == DEFAULT_IDX) {
7395 first_sw_dec_idx = i;
7400 if (first_sw_dec_idx == DEFAULT_IDX)
7401 LOGW("unknown codec %s", factory_name);
7405 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7408 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7409 if (hw_dec_idx < first_sw_dec_idx)
7411 new_pos = first_sw_dec_idx;
7412 rm_pos = hw_dec_idx + 1;
7413 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7414 if (last_sw_dec_idx < hw_dec_idx)
7416 new_pos = last_sw_dec_idx + 1;
7417 rm_pos = hw_dec_idx;
7422 /* change position - insert H/W decoder according to the new position */
7423 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7425 LOGW("failed to get factory object");
7428 new_factories = g_value_array_copy(factories);
7429 g_value_init (&val, G_TYPE_OBJECT);
7430 g_value_set_object (&val, factory);
7431 g_value_array_insert(new_factories, new_pos, &val);
7432 g_value_unset (&val);
7433 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7435 for (int i = 0 ; i < new_factories->n_values ; i++) {
7436 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7438 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7439 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7441 LOGE("[Re-arranged] failed to get factory object");
7444 return new_factories;
7448 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7449 GstCaps *caps, GstElementFactory *factory, gpointer data)
7451 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7452 mmplayer_t *player = (mmplayer_t *)data;
7454 gchar *factory_name = NULL;
7455 gchar *caps_str = NULL;
7456 const gchar *klass = NULL;
7459 factory_name = GST_OBJECT_NAME(factory);
7460 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7461 caps_str = gst_caps_to_string(caps);
7463 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7465 /* store type string */
7466 if (player->type == NULL) {
7467 player->type = gst_caps_to_string(caps);
7468 __mmplayer_update_content_type_info(player);
7471 /* filtering exclude keyword */
7472 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7473 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7474 LOGW("skipping [%s] by exclude keyword [%s]",
7475 factory_name, player->ini.exclude_element_keyword[idx]);
7477 result = GST_AUTOPLUG_SELECT_SKIP;
7482 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7483 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7484 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7485 factory_name, player->ini.unsupported_codec_keyword[idx]);
7486 result = GST_AUTOPLUG_SELECT_SKIP;
7491 /* exclude webm format */
7492 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7493 * because webm format is not supportable.
7494 * If webm is disabled in "autoplug-continue", there is no state change
7495 * failure or error because the decodebin will expose the pad directly.
7496 * It make MSL invoke _prepare_async_callback.
7497 * So, we need to disable webm format in "autoplug-select" */
7498 if (caps_str && strstr(caps_str, "webm")) {
7499 LOGW("webm is not supported");
7500 result = GST_AUTOPLUG_SELECT_SKIP;
7504 /* check factory class for filtering */
7505 /* NOTE : msl don't need to use image plugins.
7506 * So, those plugins should be skipped for error handling.
7508 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7509 LOGD("skipping [%s] by not required", factory_name);
7510 result = GST_AUTOPLUG_SELECT_SKIP;
7514 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7515 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7516 // TO CHECK : subtitle if needed, add subparse exception.
7517 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7518 result = GST_AUTOPLUG_SELECT_SKIP;
7522 if (g_strrstr(factory_name, "mpegpsdemux")) {
7523 LOGD("skipping PS container - not support");
7524 result = GST_AUTOPLUG_SELECT_SKIP;
7528 if (g_strrstr(factory_name, "mssdemux"))
7529 player->smooth_streaming = TRUE;
7531 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7532 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7535 GstStructure *str = NULL;
7536 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7538 /* don't make video because of not required */
7539 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7540 (!player->set_mode.video_export)) {
7541 LOGD("no need video decoding, expose pad");
7542 result = GST_AUTOPLUG_SELECT_EXPOSE;
7546 /* get w/h for omx state-tune */
7547 /* FIXME: deprecated? */
7548 str = gst_caps_get_structure(caps, 0);
7549 gst_structure_get_int(str, "width", &width);
7552 if (player->v_stream_caps) {
7553 gst_caps_unref(player->v_stream_caps);
7554 player->v_stream_caps = NULL;
7557 player->v_stream_caps = gst_caps_copy(caps);
7558 LOGD("take caps for video state tune");
7559 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7563 if (g_strrstr(klass, "Codec/Decoder")) {
7564 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7565 if (result != GST_AUTOPLUG_SELECT_TRY) {
7566 LOGW("skip add decoder");
7572 MMPLAYER_FREEIF(caps_str);
7578 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7581 int ret = MM_ERROR_NONE;
7582 mmplayer_t *player = (mmplayer_t *)data;
7583 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7584 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7587 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7589 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7591 if (MMPLAYER_USE_DECODEBIN(player))
7594 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7597 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7599 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7600 LOGE("failed to remove videobin");
7601 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7604 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7605 LOGE("failed to remove video concat");
7606 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7609 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7610 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7611 MMPLAYER_FREEIF(player->pipeline->videobin);
7613 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7614 if (ret != MM_ERROR_NONE)
7615 LOGE("failed to release overlay resources");
7617 player->videodec_linked = 0;
7619 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7624 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7626 mmplayer_t *player = (mmplayer_t *)data;
7629 MMPLAYER_RETURN_IF_FAIL(player);
7631 LOGD("got about to finish signal");
7633 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7634 LOGW("Fail to get cmd lock");
7638 if (!__mmplayer_verify_gapless_play_path(player)) {
7639 LOGD("decoding is finished.");
7640 MMPLAYER_CMD_UNLOCK(player);
7644 _mmplayer_set_reconfigure_state(player, TRUE);
7645 MMPLAYER_CMD_UNLOCK(player);
7647 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7648 __mmplayer_deactivate_old_path(player);
7654 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7656 mmplayer_t *player = (mmplayer_t *)data;
7657 GstIterator *iter = NULL;
7658 GValue item = { 0, };
7660 gboolean done = FALSE;
7661 gboolean is_all_drained = TRUE;
7664 MMPLAYER_RETURN_IF_FAIL(player);
7666 LOGD("got drained signal");
7668 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7669 LOGW("Fail to get cmd lock");
7673 if (!__mmplayer_verify_gapless_play_path(player)) {
7674 LOGD("decoding is finished.");
7675 MMPLAYER_CMD_UNLOCK(player);
7679 _mmplayer_set_reconfigure_state(player, TRUE);
7680 MMPLAYER_CMD_UNLOCK(player);
7682 /* check decodebin src pads whether they received EOS or not */
7683 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7686 switch (gst_iterator_next(iter, &item)) {
7687 case GST_ITERATOR_OK:
7688 pad = g_value_get_object(&item);
7689 if (pad && !GST_PAD_IS_EOS(pad)) {
7690 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7691 is_all_drained = FALSE;
7694 g_value_reset(&item);
7696 case GST_ITERATOR_RESYNC:
7697 gst_iterator_resync(iter);
7699 case GST_ITERATOR_ERROR:
7700 case GST_ITERATOR_DONE:
7705 g_value_unset(&item);
7706 gst_iterator_free(iter);
7708 if (!is_all_drained) {
7709 LOGD("Wait util the all pads get EOS.");
7714 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7715 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7717 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7718 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7719 __mmplayer_deactivate_old_path(player);
7725 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7727 mmplayer_t *player = (mmplayer_t *)data;
7728 const gchar *klass = NULL;
7729 gchar *factory_name = NULL;
7731 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7732 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7734 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7736 if (__mmplayer_add_dump_buffer_probe(player, element))
7737 LOGD("add buffer probe");
7739 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7740 gchar *selected = NULL;
7741 selected = g_strdup(GST_ELEMENT_NAME(element));
7742 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7744 /* update codec info */
7745 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7746 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7747 player->audiodec_linked = 1;
7748 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7749 /* update codec info */
7750 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7751 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7752 player->videodec_linked = 1;
7755 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7756 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7757 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7759 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7760 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7762 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7763 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7764 "max-video-width", player->adaptive_info.limit.width,
7765 "max-video-height", player->adaptive_info.limit.height, NULL);
7767 } else if (g_strrstr(klass, "Demuxer")) {
7769 LOGD("plugged element is demuxer. take it");
7771 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7772 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7773 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7774 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7775 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7778 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7779 int surface_type = 0;
7781 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7784 // to support trust-zone only
7785 if (g_strrstr(factory_name, "asfdemux")) {
7786 LOGD("set file-location %s", player->profile.uri);
7787 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7788 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7789 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7790 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7791 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7792 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7793 (__mmplayer_is_only_mp3_type(player->type))) {
7794 LOGD("[mpegaudioparse] set streaming pull mode.");
7795 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7797 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7798 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7799 } else if (g_strrstr(factory_name, "omxdec_h264")) {
7800 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7801 if (video_parse && (g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7802 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7803 LOGD("Send SPS and PPS Insertion every IDR frame");
7807 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7808 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7809 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7811 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7812 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7814 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7815 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7816 (MMPLAYER_IS_DASH_STREAMING(player))) {
7817 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7818 _mm_player_streaming_set_multiqueue(player->streamer, element);
7819 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7828 __mmplayer_release_misc(mmplayer_t *player)
7831 bool cur_mode = player->set_mode.rich_audio;
7834 MMPLAYER_RETURN_IF_FAIL(player);
7836 player->sent_bos = FALSE;
7837 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7839 player->seek_state = MMPLAYER_SEEK_NONE;
7841 player->total_bitrate = 0;
7842 player->total_maximum_bitrate = 0;
7844 player->not_found_demuxer = 0;
7846 player->last_position = 0;
7847 player->duration = 0;
7848 player->http_content_size = 0;
7849 player->not_supported_codec = MISSING_PLUGIN_NONE;
7850 player->can_support_codec = FOUND_PLUGIN_NONE;
7851 player->pending_seek.is_pending = false;
7852 player->pending_seek.pos = 0;
7853 player->msg_posted = FALSE;
7854 player->has_many_types = FALSE;
7855 player->is_subtitle_force_drop = FALSE;
7856 player->play_subtitle = FALSE;
7857 player->adjust_subtitle_pos = 0;
7858 player->has_closed_caption = FALSE;
7859 player->set_mode.video_export = false;
7860 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7861 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7863 player->set_mode.rich_audio = cur_mode;
7865 if (player->audio_device_cb_id > 0 &&
7866 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7867 LOGW("failed to remove audio device_connected_callback");
7868 player->audio_device_cb_id = 0;
7870 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7871 player->bitrate[i] = 0;
7872 player->maximum_bitrate[i] = 0;
7875 /* free memory related to audio effect */
7876 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7878 if (player->adaptive_info.var_list) {
7879 g_list_free_full(player->adaptive_info.var_list, g_free);
7880 player->adaptive_info.var_list = NULL;
7883 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7884 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7885 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7887 /* Reset video360 settings to their defaults in case if the pipeline is to be
7890 player->video360_metadata.is_spherical = -1;
7891 player->is_openal_plugin_used = FALSE;
7893 player->is_content_spherical = FALSE;
7894 player->is_video360_enabled = TRUE;
7895 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7896 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7897 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7898 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7899 player->video360_zoom = 1.0f;
7900 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7901 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7903 player->sound.rg_enable = false;
7905 __mmplayer_initialize_video_roi(player);
7910 __mmplayer_release_misc_post(mmplayer_t *player)
7912 gchar *original_uri = NULL;
7915 /* player->pipeline is already released before. */
7916 MMPLAYER_RETURN_IF_FAIL(player);
7918 player->video_decoded_cb = NULL;
7919 player->video_decoded_cb_user_param = NULL;
7920 player->video_stream_prerolled = false;
7922 player->audio_decoded_cb = NULL;
7923 player->audio_decoded_cb_user_param = NULL;
7924 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7926 player->audio_stream_changed_cb = NULL;
7927 player->audio_stream_changed_cb_user_param = NULL;
7929 mm_player_set_attribute((MMHandleType)player, NULL,
7930 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7932 /* clean found audio decoders */
7933 if (player->audio_decoders) {
7934 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7935 player->audio_decoders = NULL;
7938 /* clean the uri list except original uri */
7939 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7941 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7942 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7943 g_list_free_full(tmp, (GDestroyNotify)g_free);
7946 LOGW("failed to get original uri info");
7948 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7949 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7950 MMPLAYER_FREEIF(original_uri);
7953 /* clear the audio stream buffer list */
7954 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7956 /* clear the video stream bo list */
7957 __mmplayer_video_stream_destroy_bo_list(player);
7958 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7960 if (player->profile.input_mem.buf) {
7961 free(player->profile.input_mem.buf);
7962 player->profile.input_mem.buf = NULL;
7964 player->profile.input_mem.len = 0;
7965 player->profile.input_mem.offset = 0;
7967 player->uri_info.uri_idx = 0;
7972 __mmplayer_check_subtitle(mmplayer_t *player)
7974 MMHandleType attrs = 0;
7975 char *subtitle_uri = NULL;
7979 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7981 /* get subtitle attribute */
7982 attrs = MMPLAYER_GET_ATTRS(player);
7986 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7987 if (!subtitle_uri || !strlen(subtitle_uri))
7990 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7991 player->is_external_subtitle_present = TRUE;
7999 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8001 MMPLAYER_RETURN_IF_FAIL(player);
8003 if (player->eos_timer) {
8004 LOGD("cancel eos timer");
8005 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8006 player->eos_timer = 0;
8013 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8017 MMPLAYER_RETURN_IF_FAIL(player);
8018 MMPLAYER_RETURN_IF_FAIL(sink);
8021 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8023 player->sink_elements = g_list_append(player->sink_elements, sink);
8029 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8033 MMPLAYER_RETURN_IF_FAIL(player);
8034 MMPLAYER_RETURN_IF_FAIL(sink);
8036 player->sink_elements = g_list_remove(player->sink_elements, sink);
8042 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8043 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8045 mmplayer_signal_item_t *item = NULL;
8048 MMPLAYER_RETURN_IF_FAIL(player);
8050 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8051 LOGE("invalid signal type [%d]", type);
8055 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8057 LOGE("cannot connect signal [%s]", signal);
8062 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8063 player->signals[type] = g_list_append(player->signals[type], item);
8069 /* NOTE : be careful with calling this api. please refer to below glib comment
8070 * glib comment : Note that there is a bug in GObject that makes this function much
8071 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8072 * will no longer be called, but, the signal handler is not currently disconnected.
8073 * If the instance is itself being freed at the same time than this doesn't matter,
8074 * since the signal will automatically be removed, but if instance persists,
8075 * then the signal handler will leak. You should not remove the signal yourself
8076 * because in a future versions of GObject, the handler will automatically be
8079 * It's possible to work around this problem in a way that will continue to work
8080 * with future versions of GObject by checking that the signal handler is still
8081 * connected before disconnected it:
8083 * if (g_signal_handler_is_connected(instance, id))
8084 * g_signal_handler_disconnect(instance, id);
8087 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8089 GList *sig_list = NULL;
8090 mmplayer_signal_item_t *item = NULL;
8094 MMPLAYER_RETURN_IF_FAIL(player);
8096 LOGD("release signals type : %d", type);
8098 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8099 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8100 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8101 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8102 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8103 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8107 sig_list = player->signals[type];
8109 for (; sig_list; sig_list = sig_list->next) {
8110 item = sig_list->data;
8112 if (item && item->obj) {
8113 if (g_signal_handler_is_connected(item->obj, item->sig))
8114 g_signal_handler_disconnect(item->obj, item->sig);
8117 MMPLAYER_FREEIF(item);
8120 g_list_free(player->signals[type]);
8121 player->signals[type] = NULL;
8129 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8131 mmplayer_t *player = 0;
8132 int prev_display_surface_type = 0;
8136 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8138 player = MM_PLAYER_CAST(handle);
8140 /* check video sinkbin is created */
8141 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8142 LOGW("Videosink is already created");
8143 return MM_ERROR_NONE;
8146 LOGD("videosink element is not yet ready");
8148 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8149 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8151 return MM_ERROR_INVALID_ARGUMENT;
8154 /* load previous attributes */
8155 if (player->attrs) {
8156 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8157 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8158 if (prev_display_surface_type == surface_type) {
8159 LOGD("incoming display surface type is same as previous one, do nothing..");
8161 return MM_ERROR_NONE;
8164 LOGE("failed to load attributes");
8166 return MM_ERROR_PLAYER_INTERNAL;
8169 /* videobin is not created yet, so we just set attributes related to display surface */
8170 LOGD("store display attribute for given surface type(%d)", surface_type);
8171 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8172 "display_overlay", wl_surface_id, NULL);
8175 return MM_ERROR_NONE;
8178 /* Note : if silent is true, then subtitle would not be displayed. :*/
8180 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8182 mmplayer_t *player = (mmplayer_t *)hplayer;
8186 /* check player handle */
8187 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8189 player->set_mode.subtitle_off = silent;
8191 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8195 return MM_ERROR_NONE;
8199 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8201 mmplayer_gst_element_t *mainbin = NULL;
8202 mmplayer_gst_element_t *textbin = NULL;
8203 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8204 GstState current_state = GST_STATE_VOID_PENDING;
8205 GstState element_state = GST_STATE_VOID_PENDING;
8206 GstState element_pending_state = GST_STATE_VOID_PENDING;
8208 GstEvent *event = NULL;
8209 int result = MM_ERROR_NONE;
8211 GstClock *curr_clock = NULL;
8212 GstClockTime base_time, start_time, curr_time;
8217 /* check player handle */
8218 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8220 player->pipeline->mainbin &&
8221 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8223 mainbin = player->pipeline->mainbin;
8224 textbin = player->pipeline->textbin;
8226 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8228 // sync clock with current pipeline
8229 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8230 curr_time = gst_clock_get_time(curr_clock);
8232 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8233 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8235 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8236 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8238 if (current_state > GST_STATE_READY) {
8239 // sync state with current pipeline
8240 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8241 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8242 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8244 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8245 if (GST_STATE_CHANGE_FAILURE == ret) {
8246 LOGE("fail to state change.");
8247 result = MM_ERROR_PLAYER_INTERNAL;
8251 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8252 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8255 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8256 gst_object_unref(curr_clock);
8259 // seek to current position
8260 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8261 result = MM_ERROR_PLAYER_INVALID_STATE;
8262 LOGE("gst_element_query_position failed, invalid state");
8266 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8267 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);
8269 _mmplayer_gst_send_event_to_sink(player, event);
8271 result = MM_ERROR_PLAYER_INTERNAL;
8272 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8276 /* sync state with current pipeline */
8277 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8278 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8279 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8281 return MM_ERROR_NONE;
8284 /* release text pipeline resource */
8285 player->textsink_linked = 0;
8287 /* release signal */
8288 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8290 /* release textbin with it's children */
8291 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8292 MMPLAYER_FREEIF(player->pipeline->textbin);
8293 player->pipeline->textbin = NULL;
8295 /* release subtitle elem */
8296 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8297 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8303 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8305 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8306 GstState current_state = GST_STATE_VOID_PENDING;
8308 MMHandleType attrs = 0;
8309 mmplayer_gst_element_t *mainbin = NULL;
8310 mmplayer_gst_element_t *textbin = NULL;
8312 gchar *subtitle_uri = NULL;
8313 int result = MM_ERROR_NONE;
8314 const gchar *charset = NULL;
8318 /* check player handle */
8319 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8321 player->pipeline->mainbin &&
8322 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8323 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8325 mainbin = player->pipeline->mainbin;
8326 textbin = player->pipeline->textbin;
8328 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8329 if (current_state < GST_STATE_READY) {
8330 result = MM_ERROR_PLAYER_INVALID_STATE;
8331 LOGE("Pipeline is not in proper state");
8335 attrs = MMPLAYER_GET_ATTRS(player);
8337 LOGE("cannot get content attribute");
8338 result = MM_ERROR_PLAYER_INTERNAL;
8342 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8343 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8344 LOGE("subtitle uri is not proper filepath");
8345 result = MM_ERROR_PLAYER_INVALID_URI;
8349 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8350 LOGE("failed to get storage info of subtitle path");
8351 result = MM_ERROR_PLAYER_INVALID_URI;
8355 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8356 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8358 if (!strcmp(filepath, subtitle_uri)) {
8359 LOGD("subtitle path is not changed");
8362 if (mm_player_set_attribute((MMHandleType)player, NULL,
8363 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8364 LOGE("failed to set attribute");
8369 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8370 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8371 player->subtitle_language_list = NULL;
8372 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8374 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8375 if (ret != GST_STATE_CHANGE_SUCCESS) {
8376 LOGE("failed to change state of textbin to READY");
8377 result = MM_ERROR_PLAYER_INTERNAL;
8381 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8382 if (ret != GST_STATE_CHANGE_SUCCESS) {
8383 LOGE("failed to change state of subparse to READY");
8384 result = MM_ERROR_PLAYER_INTERNAL;
8388 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8389 if (ret != GST_STATE_CHANGE_SUCCESS) {
8390 LOGE("failed to change state of filesrc to READY");
8391 result = MM_ERROR_PLAYER_INTERNAL;
8395 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8397 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8399 charset = _mmplayer_get_charset(filepath);
8401 LOGD("detected charset is %s", charset);
8402 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8405 result = _mmplayer_sync_subtitle_pipeline(player);
8412 /* API to switch between external subtitles */
8414 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8416 int result = MM_ERROR_NONE;
8417 mmplayer_t *player = (mmplayer_t *)hplayer;
8422 /* check player handle */
8423 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8425 /* filepath can be null in idle state */
8427 /* check file path */
8428 if ((path = strstr(filepath, "file://")))
8429 result = _mmplayer_exist_file_path(path + 7);
8431 result = _mmplayer_exist_file_path(filepath);
8433 if (result != MM_ERROR_NONE) {
8434 LOGE("invalid subtitle path 0x%X", result);
8435 return result; /* file not found or permission denied */
8439 if (!player->pipeline) {
8441 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8442 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8443 LOGE("failed to set attribute");
8444 return MM_ERROR_PLAYER_INTERNAL;
8447 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8448 /* check filepath */
8449 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8451 if (!__mmplayer_check_subtitle(player)) {
8452 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8453 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8454 LOGE("failed to set attribute");
8455 return MM_ERROR_PLAYER_INTERNAL;
8458 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8459 LOGE("fail to create text pipeline");
8460 return MM_ERROR_PLAYER_INTERNAL;
8463 result = _mmplayer_sync_subtitle_pipeline(player);
8465 result = __mmplayer_change_external_subtitle_language(player, filepath);
8468 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8469 player->is_external_subtitle_added_now = TRUE;
8471 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8472 if (!player->subtitle_language_list) {
8473 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8474 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8475 LOGW("subtitle language list is not updated yet");
8477 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8485 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8487 guint active_idx = 0;
8488 GstStream *stream = NULL;
8489 GList *streams = NULL;
8490 GstCaps *caps = NULL;
8493 LOGD("Switching Streams... type: %d, index: %d", type, index);
8495 player->track[type].active_track_index = index;
8497 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8498 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8499 LOGD("track type:%d, total: %d, active: %d", i,
8500 player->track[i].total_track_num, player->track[i].active_track_index);
8501 if (player->track[i].total_track_num > 0 &&
8502 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8503 active_idx = player->track[i].active_track_index;
8504 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8505 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8506 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8508 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8509 caps = gst_stream_get_caps(stream);
8511 _mmplayer_set_audio_attrs(player, caps);
8512 gst_caps_unref(caps);
8519 LOGD("send select stream event");
8520 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8521 gst_event_new_select_streams(streams));
8522 g_list_free(streams);
8526 return MM_ERROR_NONE;
8530 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8532 int result = MM_ERROR_NONE;
8533 gchar *change_pad_name = NULL;
8534 GstPad *sinkpad = NULL;
8535 mmplayer_gst_element_t *mainbin = NULL;
8536 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8537 GstCaps *caps = NULL;
8538 gint total_track_num = 0;
8542 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8543 MM_ERROR_PLAYER_NOT_INITIALIZED);
8545 LOGD("Change Track(%d) to %d", type, index);
8547 mainbin = player->pipeline->mainbin;
8549 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8550 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8551 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8552 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8554 /* Changing Video Track is not supported. */
8555 LOGE("Track Type Error");
8559 if (mainbin[elem_idx].gst == NULL) {
8560 result = MM_ERROR_PLAYER_NO_OP;
8561 LOGD("Req track doesn't exist");
8565 total_track_num = player->track[type].total_track_num;
8566 if (total_track_num <= 0) {
8567 result = MM_ERROR_PLAYER_NO_OP;
8568 LOGD("Language list is not available");
8572 if ((index < 0) || (index >= total_track_num)) {
8573 result = MM_ERROR_INVALID_ARGUMENT;
8574 LOGD("Not a proper index : %d", index);
8578 /*To get the new pad from the selector*/
8579 change_pad_name = g_strdup_printf("sink_%u", index);
8580 if (change_pad_name == NULL) {
8581 result = MM_ERROR_PLAYER_INTERNAL;
8582 LOGD("Pad does not exists");
8586 LOGD("new active pad name: %s", change_pad_name);
8588 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8589 if (sinkpad == NULL) {
8590 LOGD("sinkpad is NULL");
8591 result = MM_ERROR_PLAYER_INTERNAL;
8595 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8596 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8598 caps = gst_pad_get_current_caps(sinkpad);
8599 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8602 gst_object_unref(sinkpad);
8604 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8605 _mmplayer_set_audio_attrs(player, caps);
8608 gst_caps_unref(caps);
8611 MMPLAYER_FREEIF(change_pad_name);
8616 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8618 int result = MM_ERROR_NONE;
8619 mmplayer_t *player = NULL;
8620 mmplayer_gst_element_t *mainbin = NULL;
8622 gint current_active_index = 0;
8624 GstState current_state = GST_STATE_VOID_PENDING;
8629 player = (mmplayer_t *)hplayer;
8630 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8632 if (!player->pipeline) {
8633 LOGE("Track %d pre setting -> %d", type, index);
8635 player->track[type].active_track_index = index;
8639 mainbin = player->pipeline->mainbin;
8641 current_active_index = player->track[type].active_track_index;
8643 /*If index is same as running index no need to change the pad*/
8644 if (current_active_index == index)
8647 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8648 result = MM_ERROR_PLAYER_INVALID_STATE;
8652 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8653 if (current_state < GST_STATE_PAUSED) {
8654 result = MM_ERROR_PLAYER_INVALID_STATE;
8655 LOGW("Pipeline not in proper state");
8659 if (MMPLAYER_USE_DECODEBIN(player))
8660 result = __mmplayer_change_selector_pad(player, type, index);
8662 result = __mmplayer_switch_stream(player, type, index);
8664 if (result != MM_ERROR_NONE) {
8665 LOGE("failed to change track");
8669 player->track[type].active_track_index = index;
8671 if (MMPLAYER_USE_DECODEBIN(player)) {
8672 GstEvent *event = NULL;
8673 if (current_state == GST_STATE_PLAYING) {
8674 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8675 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8676 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8678 _mmplayer_gst_send_event_to_sink(player, event);
8680 result = MM_ERROR_PLAYER_INTERNAL;
8691 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8693 mmplayer_t *player = (mmplayer_t *)hplayer;
8697 /* check player handle */
8698 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8700 *silent = player->set_mode.subtitle_off;
8702 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8706 return MM_ERROR_NONE;
8710 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8712 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8713 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8715 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8716 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8720 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8721 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8722 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8723 mmplayer_dump_t *dump_s;
8724 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8725 if (dump_s == NULL) {
8726 LOGE("malloc fail");
8730 dump_s->dump_element_file = NULL;
8731 dump_s->dump_pad = NULL;
8732 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8734 if (dump_s->dump_pad) {
8735 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8736 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]);
8737 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8738 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);
8739 /* add list for removed buffer probe and close FILE */
8740 player->dump_list = g_list_append(player->dump_list, dump_s);
8741 LOGD("%s sink pad added buffer probe for dump", factory_name);
8744 MMPLAYER_FREEIF(dump_s);
8745 LOGE("failed to get %s sink pad added", factory_name);
8752 static GstPadProbeReturn
8753 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8755 FILE *dump_data = (FILE *)u_data;
8757 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8758 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8760 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8762 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8764 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8766 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8768 gst_buffer_unmap(buffer, &probe_info);
8770 return GST_PAD_PROBE_OK;
8774 __mmplayer_release_dump_list(GList *dump_list)
8776 GList *d_list = dump_list;
8781 for (; d_list; d_list = g_list_next(d_list)) {
8782 mmplayer_dump_t *dump_s = d_list->data;
8783 if (dump_s->dump_pad) {
8784 if (dump_s->probe_handle_id)
8785 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8786 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8788 if (dump_s->dump_element_file) {
8789 fclose(dump_s->dump_element_file);
8790 dump_s->dump_element_file = NULL;
8792 MMPLAYER_FREEIF(dump_s);
8794 g_list_free(dump_list);
8799 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8801 mmplayer_t *player = (mmplayer_t *)hplayer;
8805 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8806 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8808 *exist = (bool)player->has_closed_caption;
8812 return MM_ERROR_NONE;
8816 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8821 LOGD("unref internal gst buffer %p", buffer);
8823 gst_buffer_unref((GstBuffer *)buffer);
8830 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8832 mmplayer_t *player = (mmplayer_t *)hplayer;
8836 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8837 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8839 if (MMPLAYER_IS_STREAMING(player))
8840 *timeout = (int)player->ini.live_state_change_timeout;
8842 *timeout = (int)player->ini.localplayback_state_change_timeout;
8844 LOGD("timeout = %d", *timeout);
8847 return MM_ERROR_NONE;
8851 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8855 MMPLAYER_RETURN_IF_FAIL(player);
8857 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8859 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8860 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8861 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8862 player->storage_info[i].id = -1;
8863 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8865 if (path_type != MMPLAYER_PATH_MAX)
8874 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8876 int ret = MM_ERROR_NONE;
8877 mmplayer_t *player = (mmplayer_t *)hplayer;
8878 MMMessageParamType msg_param = {0, };
8881 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8883 LOGW("state changed storage %d:%d", id, state);
8885 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8886 return MM_ERROR_NONE;
8888 /* FIXME: text path should be handled separately. */
8889 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8890 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8891 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8892 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8893 LOGW("external storage is removed");
8895 if (player->msg_posted == FALSE) {
8896 memset(&msg_param, 0, sizeof(MMMessageParamType));
8897 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8898 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8899 player->msg_posted = TRUE;
8902 /* unrealize the player */
8903 ret = _mmplayer_unrealize(hplayer);
8904 if (ret != MM_ERROR_NONE)
8905 LOGE("failed to unrealize");
8913 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8915 int ret = MM_ERROR_NONE;
8916 mmplayer_t *player = (mmplayer_t *)hplayer;
8917 int idx = 0, total = 0;
8918 gchar *result = NULL, *tmp = NULL;
8921 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8922 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8924 total = *num = g_list_length(player->adaptive_info.var_list);
8926 LOGW("There is no stream variant info.");
8930 result = g_strdup("");
8931 for (idx = 0 ; idx < total ; idx++) {
8932 stream_variant_t *v_data = NULL;
8933 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8936 gchar data[64] = {0};
8937 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8939 tmp = g_strconcat(result, data, NULL);
8943 LOGW("There is no variant data in %d", idx);
8948 *var_info = (char *)result;
8950 LOGD("variant info %d:%s", *num, *var_info);
8956 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8958 int ret = MM_ERROR_NONE;
8959 mmplayer_t *player = (mmplayer_t *)hplayer;
8962 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8964 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8966 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8967 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8968 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8970 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8971 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8972 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8973 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8975 /* FIXME: seek to current position for applying new variant limitation */
8984 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8986 int ret = MM_ERROR_NONE;
8987 mmplayer_t *player = (mmplayer_t *)hplayer;
8990 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8991 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8993 *bandwidth = player->adaptive_info.limit.bandwidth;
8994 *width = player->adaptive_info.limit.width;
8995 *height = player->adaptive_info.limit.height;
8997 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9004 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9006 int ret = MM_ERROR_NONE;
9007 mmplayer_t *player = (mmplayer_t *)hplayer;
9010 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9011 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9012 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9014 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9016 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9017 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9018 else /* live case */
9019 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9021 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9028 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9030 #define IDX_FIRST_SW_CODEC 0
9031 mmplayer_t *player = (mmplayer_t *)hplayer;
9032 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9033 const char *attr_name = NULL;
9034 const char *default_type = NULL;
9035 const char *element_hw = NULL;
9036 const char *element_sw = NULL;
9039 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9041 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9043 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9044 switch (stream_type) {
9045 case MM_PLAYER_STREAM_TYPE_AUDIO:
9046 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9047 default_type = player->ini.audiocodec_default_type;
9048 element_hw = player->ini.audiocodec_element_hw;
9049 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9051 case MM_PLAYER_STREAM_TYPE_VIDEO:
9052 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9053 default_type = player->ini.videocodec_default_type;
9054 element_hw = player->ini.videocodec_element_hw;
9055 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9058 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9059 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9063 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9065 if (!strcmp(default_type, "sw"))
9066 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9068 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9070 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9071 codec_type = default_codec_type;
9073 /* to support codec selection, codec info have to be added in ini file.
9074 in case of hw codec is selected, filter elements should be applied
9075 depending on the hw capabilities. */
9076 if (codec_type != default_codec_type) {
9077 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9078 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9079 LOGE("There is no codec for type %d", codec_type);
9080 return MM_ERROR_PLAYER_NO_OP;
9083 LOGD("sorting is required");
9084 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9085 player->need_audio_dec_sorting = TRUE;
9087 player->need_video_dec_sorting = TRUE;
9090 LOGD("update %s codec_type to %d", attr_name, codec_type);
9091 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9094 return MM_ERROR_NONE;
9098 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9100 mmplayer_t *player = (mmplayer_t *)hplayer;
9101 GstElement *rg_vol_element = NULL;
9105 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9107 player->sound.rg_enable = enabled;
9109 /* just hold rgvolume enable value if pipeline is not ready */
9110 if (!player->pipeline || !player->pipeline->audiobin) {
9111 LOGD("pipeline is not ready. holding rgvolume enable value");
9112 return MM_ERROR_NONE;
9115 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9117 if (!rg_vol_element) {
9118 LOGD("rgvolume element is not created");
9119 return MM_ERROR_PLAYER_INTERNAL;
9123 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9125 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9129 return MM_ERROR_NONE;
9133 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9135 mmplayer_t *player = (mmplayer_t *)hplayer;
9136 GstElement *rg_vol_element = NULL;
9137 gboolean enable = FALSE;
9141 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9142 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9144 /* just hold enable_rg value if pipeline is not ready */
9145 if (!player->pipeline || !player->pipeline->audiobin) {
9146 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9147 *enabled = player->sound.rg_enable;
9148 return MM_ERROR_NONE;
9151 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9153 if (!rg_vol_element) {
9154 LOGD("rgvolume element is not created");
9155 return MM_ERROR_PLAYER_INTERNAL;
9158 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9159 *enabled = (bool)enable;
9163 return MM_ERROR_NONE;
9167 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9169 mmplayer_t *player = (mmplayer_t *)hplayer;
9170 MMHandleType attrs = 0;
9172 int ret = MM_ERROR_NONE;
9176 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9178 attrs = MMPLAYER_GET_ATTRS(player);
9179 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9181 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9183 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9184 return MM_ERROR_PLAYER_INTERNAL;
9187 player->video_roi.scale_x = scale_x;
9188 player->video_roi.scale_y = scale_y;
9189 player->video_roi.scale_width = scale_width;
9190 player->video_roi.scale_height = scale_height;
9192 /* check video sinkbin is created */
9193 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9194 return MM_ERROR_NONE;
9196 if (!gst_video_overlay_set_video_roi_area(
9197 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9198 scale_x, scale_y, scale_width, scale_height))
9199 ret = MM_ERROR_PLAYER_INTERNAL;
9201 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9202 scale_x, scale_y, scale_width, scale_height);
9210 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9212 mmplayer_t *player = (mmplayer_t *)hplayer;
9213 int ret = MM_ERROR_NONE;
9217 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9218 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9220 *scale_x = player->video_roi.scale_x;
9221 *scale_y = player->video_roi.scale_y;
9222 *scale_width = player->video_roi.scale_width;
9223 *scale_height = player->video_roi.scale_height;
9225 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9226 *scale_x, *scale_y, *scale_width, *scale_height);
9232 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9234 mmplayer_t *player = (mmplayer_t *)hplayer;
9238 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9240 player->client_pid = pid;
9242 LOGD("client pid[%d] %p", pid, player);
9246 return MM_ERROR_NONE;
9250 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9252 mmplayer_t *player = (mmplayer_t *)hplayer;
9253 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9254 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9258 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9259 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9262 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9264 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9266 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9267 return MM_ERROR_NONE;
9269 /* in case of audio codec default type is HW */
9271 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9272 if (player->ini.support_audio_effect)
9273 return MM_ERROR_NONE;
9274 elem_id = MMPLAYER_A_FILTER;
9276 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9277 if (player->ini.support_replaygain_control)
9278 return MM_ERROR_NONE;
9279 elem_id = MMPLAYER_A_RGVOL;
9281 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9282 if (player->ini.support_pitch_control)
9283 return MM_ERROR_NONE;
9284 elem_id = MMPLAYER_A_PITCH;
9286 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9287 if (player->ini.support_audio_effect)
9288 return MM_ERROR_NONE;
9290 /* default case handling is not required */
9293 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9294 LOGW("audio control option [%d] is not available", opt);
9297 /* setting pcm exporting option is allowed before READY state */
9298 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9299 return MM_ERROR_PLAYER_INVALID_STATE;
9301 /* check whether the audio filter exist or not after READY state,
9302 because the sw codec could be added during auto-plugging in some cases */
9303 if (!player->pipeline ||
9304 !player->pipeline->audiobin ||
9305 !player->pipeline->audiobin[elem_id].gst) {
9306 LOGW("there is no audio elem [%d]", elem_id);
9311 LOGD("audio control opt %d, available %d", opt, *available);
9315 return MM_ERROR_NONE;
9319 __mmplayer_update_duration_value(mmplayer_t *player)
9321 gboolean ret = FALSE;
9322 gint64 dur_nsec = 0;
9323 LOGD("try to update duration");
9325 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9326 player->duration = dur_nsec;
9327 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9331 if (player->duration < 0) {
9332 LOGW("duration is Non-Initialized !!!");
9333 player->duration = 0;
9336 /* update streaming service type */
9337 player->streaming_type = _mmplayer_get_stream_service_type(player);
9339 /* check duration is OK */
9340 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9341 /* FIXIT : find another way to get duration here. */
9342 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9348 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9350 /* update audio params
9351 NOTE : We need original audio params and it can be only obtained from src pad of audio
9352 decoder. Below code only valid when we are not using 'resampler' just before
9353 'audioconverter'. */
9354 GstCaps *caps_a = NULL;
9356 gint samplerate = 0, channels = 0;
9357 GstStructure *p = NULL;
9358 GstElement *aconv = NULL;
9360 LOGD("try to update audio attrs");
9362 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9364 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9365 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9366 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9367 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9369 LOGE("there is no audio converter");
9373 pad = gst_element_get_static_pad(aconv, "sink");
9376 LOGW("failed to get pad from audio converter");
9380 caps_a = gst_pad_get_current_caps(pad);
9382 LOGW("not ready to get audio caps");
9383 gst_object_unref(pad);
9387 p = gst_caps_get_structure(caps_a, 0);
9388 gst_structure_get_int(p, "rate", &samplerate);
9389 gst_structure_get_int(p, "channels", &channels);
9391 mm_player_set_attribute((MMHandleType)player, NULL,
9392 "content_audio_samplerate", samplerate,
9393 "content_audio_channels", channels, NULL);
9395 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9397 gst_caps_unref(caps_a);
9398 gst_object_unref(pad);
9404 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9406 LOGD("try to update video attrs");
9408 GstCaps *caps_v = NULL;
9412 GstStructure *p = NULL;
9414 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9415 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9417 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9419 LOGD("no videosink sink pad");
9423 caps_v = gst_pad_get_current_caps(pad);
9424 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9425 if (!caps_v && player->v_stream_caps) {
9426 caps_v = player->v_stream_caps;
9427 gst_caps_ref(caps_v);
9431 LOGD("no negotiated caps from videosink");
9432 gst_object_unref(pad);
9436 p = gst_caps_get_structure(caps_v, 0);
9437 gst_structure_get_int(p, "width", &width);
9438 gst_structure_get_int(p, "height", &height);
9440 mm_player_set_attribute((MMHandleType)player, NULL,
9441 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9443 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9445 SECURE_LOGD("width : %d height : %d", width, height);
9447 gst_caps_unref(caps_v);
9448 gst_object_unref(pad);
9451 mm_player_set_attribute((MMHandleType)player, NULL,
9452 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9453 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9460 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9462 gboolean ret = FALSE;
9463 guint64 data_size = 0;
9467 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9468 if (!player->duration)
9471 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9472 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9473 if (stat(path, &sb) == 0)
9474 data_size = (guint64)sb.st_size;
9476 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9477 data_size = player->http_content_size;
9480 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9483 guint64 bitrate = 0;
9484 guint64 msec_dur = 0;
9486 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9488 bitrate = data_size * 8 * 1000 / msec_dur;
9489 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9490 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9491 mm_player_set_attribute((MMHandleType)player, NULL,
9492 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9495 LOGD("player duration is less than 0");
9499 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9500 if (player->total_bitrate) {
9501 mm_player_set_attribute((MMHandleType)player, NULL,
9502 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9511 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9513 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9514 data->uri_type = uri_type;
9518 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9520 int ret = MM_ERROR_PLAYER_INVALID_URI;
9522 char *buffer = NULL;
9523 char *seperator = strchr(path, ',');
9524 char ext[100] = {0,}, size[100] = {0,};
9527 if ((buffer = strstr(path, "ext="))) {
9528 buffer += strlen("ext=");
9530 if (strlen(buffer)) {
9531 strncpy(ext, buffer, 99);
9533 if ((seperator = strchr(ext, ','))
9534 || (seperator = strchr(ext, ' '))
9535 || (seperator = strchr(ext, '\0'))) {
9536 seperator[0] = '\0';
9541 if ((buffer = strstr(path, "size="))) {
9542 buffer += strlen("size=");
9544 if (strlen(buffer) > 0) {
9545 strncpy(size, buffer, 99);
9547 if ((seperator = strchr(size, ','))
9548 || (seperator = strchr(size, ' '))
9549 || (seperator = strchr(size, '\0'))) {
9550 seperator[0] = '\0';
9553 mem_size = atoi(size);
9558 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9560 if (mem_size && param) {
9561 if (data->input_mem.buf)
9562 free(data->input_mem.buf);
9563 data->input_mem.buf = malloc(mem_size);
9565 if (data->input_mem.buf) {
9566 memcpy(data->input_mem.buf, param, mem_size);
9567 data->input_mem.len = mem_size;
9568 ret = MM_ERROR_NONE;
9570 LOGE("failed to alloc mem %d", mem_size);
9571 ret = MM_ERROR_PLAYER_INTERNAL;
9574 data->input_mem.offset = 0;
9575 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9582 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9584 gchar *location = NULL;
9587 int ret = MM_ERROR_NONE;
9589 if ((path = strstr(uri, "file://"))) {
9590 location = g_filename_from_uri(uri, NULL, &err);
9591 if (!location || (err != NULL)) {
9592 LOGE("Invalid URI '%s' for filesrc: %s", path,
9593 (err != NULL) ? err->message : "unknown error");
9597 MMPLAYER_FREEIF(location);
9599 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9600 return MM_ERROR_PLAYER_INVALID_URI;
9602 LOGD("path from uri: %s", location);
9605 path = (location != NULL) ? (location) : ((char *)uri);
9608 ret = _mmplayer_exist_file_path(path);
9610 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9611 if (ret == MM_ERROR_NONE) {
9612 if (_mmplayer_is_sdp_file(path)) {
9613 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9614 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9615 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9617 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9618 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9620 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9621 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9623 LOGE("invalid uri, could not play..");
9624 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9627 MMPLAYER_FREEIF(location);
9632 static mmplayer_video_decoded_data_info_t *
9633 __mmplayer_create_stream_from_pad(GstPad *pad)
9635 GstCaps *caps = NULL;
9636 GstStructure *structure = NULL;
9637 unsigned int fourcc = 0;
9638 const gchar *string_format = NULL;
9639 mmplayer_video_decoded_data_info_t *stream = NULL;
9641 MMPixelFormatType format;
9644 caps = gst_pad_get_current_caps(pad);
9646 LOGE("Caps is NULL.");
9651 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9653 structure = gst_caps_get_structure(caps, 0);
9654 gst_structure_get_int(structure, "width", &width);
9655 gst_structure_get_int(structure, "height", &height);
9656 string_format = gst_structure_get_string(structure, "format");
9659 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9660 format = _mmplayer_get_pixtype(fourcc);
9661 gst_video_info_from_caps(&info, caps);
9662 gst_caps_unref(caps);
9665 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9666 LOGE("Wrong condition!!");
9670 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9672 LOGE("failed to alloc mem for video data");
9676 stream->width = width;
9677 stream->height = height;
9678 stream->format = format;
9679 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9685 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9687 unsigned int pitch = 0;
9688 unsigned int size = 0;
9690 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9693 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9694 bo = gst_tizen_memory_get_bos(mem, index);
9696 stream->bo[index] = tbm_bo_ref(bo);
9698 LOGE("failed to get bo for index %d", index);
9701 for (index = 0; index < stream->plane_num; index++) {
9702 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9703 stream->stride[index] = pitch;
9705 stream->elevation[index] = size / pitch;
9707 stream->elevation[index] = stream->height;
9712 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9714 if (stream->format == MM_PIXEL_FORMAT_I420) {
9715 int ret = TBM_SURFACE_ERROR_NONE;
9716 tbm_surface_h surface;
9717 tbm_surface_info_s info;
9719 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9721 ret = tbm_surface_get_info(surface, &info);
9722 if (ret != TBM_SURFACE_ERROR_NONE) {
9723 tbm_surface_destroy(surface);
9727 tbm_surface_destroy(surface);
9728 stream->stride[0] = info.planes[0].stride;
9729 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9730 stream->stride[1] = info.planes[1].stride;
9731 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9732 stream->stride[2] = info.planes[2].stride;
9733 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9734 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9735 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9736 stream->stride[0] = stream->width * 4;
9737 stream->elevation[0] = stream->height;
9738 stream->bo_size = stream->stride[0] * stream->height;
9740 LOGE("Not support format %d", stream->format);
9748 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9750 tbm_bo_handle thandle;
9752 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9753 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9754 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9758 unsigned char *src = NULL;
9759 unsigned char *dest = NULL;
9760 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9762 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9764 LOGE("fail to gst_memory_map");
9768 if (!mapinfo.data) {
9769 LOGE("data pointer is wrong");
9773 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9774 if (!stream->bo[0]) {
9775 LOGE("Fail to tbm_bo_alloc!!");
9779 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9781 LOGE("thandle pointer is wrong");
9785 if (stream->format == MM_PIXEL_FORMAT_I420) {
9786 src_stride[0] = GST_ROUND_UP_4(stream->width);
9787 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9788 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9789 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9792 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9793 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9795 for (i = 0; i < 3; i++) {
9796 src = mapinfo.data + src_offset[i];
9797 dest = thandle.ptr + dest_offset[i];
9802 for (j = 0; j < stream->height >> k; j++) {
9803 memcpy(dest, src, stream->width>>k);
9804 src += src_stride[i];
9805 dest += stream->stride[i];
9808 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9809 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9811 LOGE("Not support format %d", stream->format);
9815 tbm_bo_unmap(stream->bo[0]);
9816 gst_memory_unmap(mem, &mapinfo);
9822 tbm_bo_unmap(stream->bo[0]);
9825 gst_memory_unmap(mem, &mapinfo);
9831 __mmplayer_set_pause_state(mmplayer_t *player)
9833 if (player->sent_bos)
9836 /* rtsp case, get content attrs by GstMessage */
9837 if (MMPLAYER_IS_RTSP_STREAMING(player))
9840 /* it's first time to update all content attrs. */
9841 _mmplayer_update_content_attrs(player, ATTR_ALL);
9845 __mmplayer_set_playing_state(mmplayer_t *player)
9847 gchar *audio_codec = NULL;
9849 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9850 /* initialize because auto resume is done well. */
9851 player->resumed_by_rewind = FALSE;
9852 player->playback_rate = 1.0;
9855 if (player->sent_bos)
9858 /* try to get content metadata */
9860 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9861 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9862 * legacy mmfw-player api
9864 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9866 if ((player->cmd == MMPLAYER_COMMAND_START)
9867 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9868 __mmplayer_handle_missed_plugin(player);
9871 /* check audio codec field is set or not
9872 * we can get it from typefinder or codec's caps.
9874 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9876 /* The codec format can't be sent for audio only case like amr, mid etc.
9877 * Because, parser don't make related TAG.
9878 * So, if it's not set yet, fill it with found data.
9881 if (g_strrstr(player->type, "audio/midi"))
9882 audio_codec = "MIDI";
9883 else if (g_strrstr(player->type, "audio/x-amr"))
9884 audio_codec = "AMR";
9885 else if (g_strrstr(player->type, "audio/mpeg")
9886 && !g_strrstr(player->type, "mpegversion=(int)1"))
9887 audio_codec = "AAC";
9889 audio_codec = "unknown";
9891 if (mm_player_set_attribute((MMHandleType)player, NULL,
9892 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9893 LOGE("failed to set attribute");
9895 LOGD("set audio codec type with caps");