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 /* store it as it's sink element */
1151 __mmplayer_add_sink(player, fakesink, FALSE);
1153 gst_bin_add(GST_BIN(pipeline), fakesink);
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");
1162 gst_object_unref(GST_OBJECT(fakesink));
1166 if (strstr(name, "video")) {
1167 if (player->v_stream_caps) {
1168 gst_caps_unref(player->v_stream_caps);
1169 player->v_stream_caps = NULL;
1171 if (player->ini.set_dump_element_flag)
1172 __mmplayer_add_dump_buffer_probe(player, fakesink);
1175 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1176 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1180 gst_object_unref(GST_OBJECT(sinkpad));
1187 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1189 GstElement *pipeline = NULL;
1190 GstElement *concat = NULL;
1193 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1195 concat = gst_element_factory_make("concat", NULL);
1197 LOGE("failed to create concat");
1201 LOGD("Create concat [%d] element", elem_idx);
1203 player->pipeline->mainbin[elem_idx].id = elem_idx;
1204 player->pipeline->mainbin[elem_idx].gst = concat;
1206 gst_element_set_state(concat, GST_STATE_PAUSED);
1208 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1209 gst_bin_add(GST_BIN(pipeline), concat);
1216 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1218 GstElement *pipeline = NULL;
1219 GstElement *selector = NULL;
1220 GstPad *srcpad = NULL;
1223 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1225 selector = gst_element_factory_make("input-selector", NULL);
1227 LOGE("failed to create input-selector");
1230 g_object_set(selector, "sync-streams", TRUE, NULL);
1232 player->pipeline->mainbin[elem_idx].id = elem_idx;
1233 player->pipeline->mainbin[elem_idx].gst = selector;
1235 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1237 srcpad = gst_element_get_static_pad(selector, "src");
1239 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1240 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1241 __mmplayer_gst_selector_blocked, NULL, NULL);
1242 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1243 __mmplayer_gst_selector_event_probe, player, NULL);
1245 gst_element_set_state(selector, GST_STATE_PAUSED);
1247 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1248 gst_bin_add(GST_BIN(pipeline), selector);
1250 gst_object_unref(GST_OBJECT(srcpad));
1257 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1259 mmplayer_t *player = (mmplayer_t *)data;
1260 GstElement *combiner = NULL;
1261 GstCaps *caps = NULL;
1262 GstStructure *str = NULL;
1263 const gchar *name = NULL;
1264 GstPad *sinkpad = NULL;
1265 gboolean first_track = FALSE;
1266 gboolean caps_ret = TRUE;
1268 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1269 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1272 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1273 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1275 LOGD("pad-added signal handling");
1277 /* get mimetype from caps */
1278 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1282 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1284 LOGD("detected mimetype : %s", name);
1287 if (strstr(name, "video")) {
1289 gchar *caps_str = NULL;
1291 caps_str = gst_caps_to_string(caps);
1292 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1293 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1294 player->set_mode.video_zc = true;
1296 MMPLAYER_FREEIF(caps_str);
1298 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1299 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1301 LOGD("surface type : %d", stype);
1303 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1304 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1308 /* in case of exporting video frame, it requires the 360 video filter.
1309 * it will be handled in _no_more_pads(). */
1310 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1311 __mmplayer_gst_make_fakesink(player, pad, name);
1315 if (MMPLAYER_USE_DECODEBIN(player)) {
1316 LOGD("video selector is required");
1317 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1319 LOGD("video concat is required");
1320 elem_idx = MMPLAYER_M_V_CONCAT;
1322 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1323 } else if (strstr(name, "audio")) {
1324 gint samplerate = 0;
1327 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1328 if (player->build_audio_offload)
1329 player->no_more_pad = TRUE; /* remove state holder */
1330 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1334 gst_structure_get_int(str, "rate", &samplerate);
1335 gst_structure_get_int(str, "channels", &channels);
1337 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1338 __mmplayer_gst_make_fakesink(player, pad, name);
1341 if (MMPLAYER_USE_DECODEBIN(player)) {
1342 LOGD("audio selector is required");
1343 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1345 LOGD("audio concat is required");
1346 elem_idx = MMPLAYER_M_A_CONCAT;
1348 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1350 } else if (strstr(name, "text")) {
1351 if (MMPLAYER_USE_DECODEBIN(player)) {
1352 LOGD("text selector is required");
1353 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1355 LOGD("text concat is required");
1356 elem_idx = MMPLAYER_M_T_CONCAT;
1358 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1360 LOGE("invalid caps info");
1364 /* check selector and create it */
1365 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1366 if (MMPLAYER_USE_DECODEBIN(player))
1367 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1369 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1375 LOGD("Combiner element is already created.");
1379 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1381 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1383 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1384 LOGE("failed to link combiner");
1385 gst_object_unref(GST_OBJECT(combiner));
1390 if (MMPLAYER_USE_DECODEBIN(player)) {
1391 LOGD("this track will be activated");
1392 g_object_set(combiner, "active-pad", sinkpad, NULL);
1396 if (MMPLAYER_USE_DECODEBIN(player)) {
1397 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1399 /* apply the text track information */
1400 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1401 mm_player_set_attribute((MMHandleType)player, NULL,
1402 "content_text_track_num", player->track[stream_type].total_track_num,
1403 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1404 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1411 gst_caps_unref(caps);
1414 gst_object_unref(GST_OBJECT(sinkpad));
1422 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1424 GstPad *srcpad = NULL;
1427 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1429 LOGD("type %d", type);
1432 LOGD("there is no %d track", type);
1436 srcpad = gst_element_get_static_pad(combiner, "src");
1438 LOGE("failed to get srcpad from combiner");
1442 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1444 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1446 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1447 if (player->track[type].block_id) {
1448 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1449 player->track[type].block_id = 0;
1453 gst_object_unref(GST_OBJECT(srcpad));
1462 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1464 gint active_index = 0;
1467 MMPLAYER_RETURN_IF_FAIL(player);
1469 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1471 /* change track to active pad */
1472 active_index = player->track[type].active_track_index;
1473 if ((active_index != DEFAULT_TRACK_INDEX) &&
1474 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1475 LOGW("failed to change %d type track to %d", type, active_index);
1476 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1480 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1481 mm_player_set_attribute((MMHandleType)player, NULL,
1482 "content_text_track_num", player->track[type].total_track_num,
1483 "current_text_track_index", player->track[type].active_track_index, NULL);
1490 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1493 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1495 if (!audio_selector) {
1496 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1498 /* in case the source is changed, output can be changed. */
1499 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1500 LOGD("remove previous audiobin if it exist");
1502 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1503 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1505 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1506 MMPLAYER_FREEIF(player->pipeline->audiobin);
1509 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1510 _mmplayer_pipeline_complete(NULL, player);
1515 /* apply the audio track information */
1516 if (MMPLAYER_USE_DECODEBIN(player))
1517 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1519 /* create audio sink path */
1520 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1521 LOGE("failed to create audio sink path");
1530 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1533 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1535 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1536 LOGD("text path is not supported");
1540 /* apply the text track information */
1541 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1543 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1544 player->has_closed_caption = TRUE;
1546 /* create text decode path */
1547 player->no_more_pad = TRUE;
1549 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1550 LOGE("failed to create text sink path");
1559 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1561 gint64 dur_bytes = 0L;
1564 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1565 player->pipeline->mainbin && player->streamer, FALSE);
1567 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1568 LOGE("fail to get duration.");
1570 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1571 * use file information was already set on Q2 when it was created. */
1572 _mm_player_streaming_set_queue2(player->streamer,
1573 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1574 TRUE, /* use_buffering */
1575 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1576 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1583 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1585 mmplayer_t *player = NULL;
1586 GstElement *video_selector = NULL;
1587 GstElement *audio_selector = NULL;
1588 GstElement *text_selector = NULL;
1591 player = (mmplayer_t *)data;
1593 LOGD("no-more-pad signal handling");
1595 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1596 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1597 LOGW("player is shutting down");
1601 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1602 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1603 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1604 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1605 LOGE("failed to set queue2 buffering");
1610 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1611 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1612 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1614 if (!video_selector && !audio_selector && !text_selector) {
1615 LOGW("there is no selector");
1616 player->no_more_pad = TRUE;
1620 /* create video path followed by video-select */
1621 if (video_selector && !audio_selector && !text_selector)
1622 player->no_more_pad = TRUE;
1624 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1627 /* create audio path followed by audio-select */
1628 if (audio_selector && !text_selector)
1629 player->no_more_pad = TRUE;
1631 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1634 /* create text path followed by text-select */
1635 __mmplayer_create_text_sink_path(player, text_selector);
1638 _mmplayer_set_reconfigure_state(player, FALSE);
1643 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1645 gboolean ret = FALSE;
1646 GstElement *pipeline = NULL;
1647 GstPad *sinkpad = NULL;
1650 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1651 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1653 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1655 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1657 LOGE("failed to get pad from sinkbin");
1663 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1664 LOGE("failed to link sinkbin for reusing");
1665 goto EXIT; /* exit either pass or fail */
1669 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1670 LOGE("failed to set state(READY) to sinkbin");
1675 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1676 LOGE("failed to add sinkbin to pipeline");
1681 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1682 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1687 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1688 LOGE("failed to set state(PAUSED) to sinkbin");
1697 gst_object_unref(GST_OBJECT(sinkpad));
1705 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1707 mmplayer_t *player = NULL;
1708 GstCaps *caps = NULL;
1709 gchar *caps_str = NULL;
1710 GstStructure *str = NULL;
1711 const gchar *name = NULL;
1712 GstElement *sinkbin = NULL;
1713 gboolean reusing = FALSE;
1714 gboolean caps_ret = TRUE;
1715 gchar *sink_pad_name = "sink";
1718 player = (mmplayer_t *)data;
1721 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1722 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1723 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1725 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1729 gst_caps_unref(caps);
1730 caps = gst_caps_ref(ref_caps);
1733 caps_str = gst_caps_to_string(caps);
1735 LOGD("detected mimetype : %s", name);
1737 if (strstr(name, "audio")) {
1738 if (player->pipeline->audiobin == NULL) {
1739 const gchar *audio_format = gst_structure_get_string(str, "format");
1741 LOGD("original audio format %s", audio_format);
1742 mm_player_set_attribute((MMHandleType)player, NULL,
1743 "content_audio_format", audio_format, strlen(audio_format), NULL);
1746 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1747 LOGE("failed to create audiobin. continuing without audio");
1751 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1752 LOGD("creating audiobin success");
1755 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1756 LOGD("reusing audiobin");
1757 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1759 } else if (strstr(name, "video")) {
1760 /* 1. zero copy is updated at _decode_pad_added()
1761 * 2. NULL surface type is handled in _decode_pad_added() */
1762 LOGD("zero copy %d", player->set_mode.video_zc);
1763 if (player->pipeline->videobin == NULL) {
1764 int surface_type = 0;
1765 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1766 LOGD("display_surface_type (%d)", surface_type);
1768 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1769 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1770 LOGE("failed to acquire video overlay resource");
1774 player->interrupted_by_resource = FALSE;
1776 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1777 LOGE("failed to create videobin. continuing without video");
1781 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1782 LOGD("creating videosink bin success");
1785 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1786 LOGD("re-using videobin");
1787 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1789 } else if (strstr(name, "text")) {
1790 if (player->pipeline->textbin == NULL) {
1791 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1792 LOGE("failed to create text sink bin. continuing without text");
1796 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1797 player->textsink_linked = 1;
1798 LOGD("creating textsink bin success");
1800 if (!player->textsink_linked) {
1801 LOGD("re-using textbin");
1803 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1804 player->textsink_linked = 1;
1806 /* linked textbin exist which means that the external subtitle path exist already */
1807 LOGW("ignoring internal subtitle since external subtitle is available");
1810 sink_pad_name = "text_sink";
1812 LOGW("unknown mime type %s, ignoring it", name);
1816 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1819 LOGD("[handle: %p] success to create and link sink bin", player);
1821 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1822 * streaming task. if the task blocked, then buffer will not flow to the next element
1823 *(autoplugging element). so this is special hack for streaming. please try to remove it
1825 /* dec stream count. we can remove fakesink if it's zero */
1826 if (player->num_dynamic_pad)
1827 player->num_dynamic_pad--;
1829 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1831 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1832 _mmplayer_pipeline_complete(NULL, player);
1836 MMPLAYER_FREEIF(caps_str);
1839 gst_caps_unref(caps);
1845 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1847 int required_angle = 0; /* Angle required for straight view */
1848 int rotation_angle = 0;
1850 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1851 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1853 /* Counter clockwise */
1854 switch (orientation) {
1859 required_angle = 270;
1862 required_angle = 180;
1865 required_angle = 90;
1869 rotation_angle = display_angle + required_angle;
1870 if (rotation_angle >= 360)
1871 rotation_angle -= 360;
1873 /* check if supported or not */
1874 if (rotation_angle % 90) {
1875 LOGD("not supported rotation angle = %d", rotation_angle);
1879 switch (rotation_angle) {
1881 *value = MM_DISPLAY_ROTATION_NONE;
1884 *value = MM_DISPLAY_ROTATION_90;
1887 *value = MM_DISPLAY_ROTATION_180;
1890 *value = MM_DISPLAY_ROTATION_270;
1894 LOGD("setting rotation property value : %d", *value);
1900 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1902 int display_rotation = 0;
1903 gchar *org_orient = NULL;
1904 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1907 LOGE("cannot get content attribute");
1908 return MM_ERROR_PLAYER_INTERNAL;
1911 if (display_angle) {
1912 /* update user rotation */
1913 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1915 /* Counter clockwise */
1916 switch (display_rotation) {
1917 case MM_DISPLAY_ROTATION_NONE:
1920 case MM_DISPLAY_ROTATION_90:
1921 *display_angle = 90;
1923 case MM_DISPLAY_ROTATION_180:
1924 *display_angle = 180;
1926 case MM_DISPLAY_ROTATION_270:
1927 *display_angle = 270;
1930 LOGW("wrong angle type : %d", display_rotation);
1933 LOGD("check user angle: %d", *display_angle);
1937 /* Counter clockwise */
1938 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1941 if (!strcmp(org_orient, "rotate-90"))
1943 else if (!strcmp(org_orient, "rotate-180"))
1945 else if (!strcmp(org_orient, "rotate-270"))
1948 LOGD("original rotation is %s", org_orient);
1950 LOGD("content_video_orientation get fail");
1953 LOGD("check orientation: %d", *orientation);
1956 return MM_ERROR_NONE;
1959 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1961 int rotation_value = 0;
1962 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1963 int display_angle = 0;
1966 /* check video sinkbin is created */
1967 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1970 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1972 /* get rotation value to set */
1973 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1974 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1975 LOGD("set video param : rotate %d", rotation_value);
1978 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1980 MMHandleType attrs = 0;
1984 /* check video sinkbin is created */
1985 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
1986 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
1989 attrs = MMPLAYER_GET_ATTRS(player);
1990 MMPLAYER_RETURN_IF_FAIL(attrs);
1992 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1993 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1994 LOGD("set video param : visible %d", visible);
1997 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1999 MMHandleType attrs = 0;
2000 int display_method = 0;
2003 /* check video sinkbin is created */
2004 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2007 attrs = MMPLAYER_GET_ATTRS(player);
2008 MMPLAYER_RETURN_IF_FAIL(attrs);
2010 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2011 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2012 LOGD("set video param : method %d", display_method);
2015 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2017 MMHandleType attrs = 0;
2021 /* check video sinkbin is created */
2022 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2025 attrs = MMPLAYER_GET_ATTRS(player);
2026 MMPLAYER_RETURN_IF_FAIL(attrs);
2028 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2029 MMPLAYER_RETURN_IF_FAIL(handle);
2031 gst_video_overlay_set_video_roi_area(
2032 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2033 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2034 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2035 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2038 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2040 MMHandleType attrs = 0;
2045 int win_roi_width = 0;
2046 int win_roi_height = 0;
2049 /* check video sinkbin is created */
2050 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2053 attrs = MMPLAYER_GET_ATTRS(player);
2054 MMPLAYER_RETURN_IF_FAIL(attrs);
2056 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2057 MMPLAYER_RETURN_IF_FAIL(handle);
2059 /* It should be set after setting window */
2060 mm_attrs_multiple_get(attrs, NULL,
2061 "display_win_roi_x", &win_roi_x,
2062 "display_win_roi_y", &win_roi_y,
2063 "display_win_roi_width", &win_roi_width,
2064 "display_win_roi_height", &win_roi_height, NULL);
2066 /* After setting window handle, set display roi area */
2067 gst_video_overlay_set_display_roi_area(
2068 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2069 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2070 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2071 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2074 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2076 MMHandleType attrs = 0;
2077 gchar *handle = NULL;
2079 /* check video sinkbin is created */
2080 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2083 attrs = MMPLAYER_GET_ATTRS(player);
2084 MMPLAYER_RETURN_IF_FAIL(attrs);
2086 /* common case if using overlay surface */
2087 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2088 MMPLAYER_RETURN_IF_FAIL(handle);
2090 gst_video_overlay_set_wl_window_exported_shell_handle(
2091 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2093 LOGD("set video param: exported_shell_handle (%s)", handle);
2096 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2098 MMHandleType attrs = 0;
2101 /* check video sinkbin is created */
2102 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2105 attrs = MMPLAYER_GET_ATTRS(player);
2106 MMPLAYER_RETURN_IF_FAIL(attrs);
2108 /* common case if using overlay surface */
2109 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2110 MMPLAYER_RETURN_IF_FAIL(handle);
2112 /* default is using wl_surface_id */
2113 LOGD("set video param : wl_surface_id %d", handle);
2114 gst_video_overlay_set_wl_window_wl_surface_id(
2115 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2120 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2122 gboolean update_all_param = FALSE;
2123 int curr_type = MM_DISPLAY_SURFACE_NUM;
2127 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2128 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2129 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2130 LOGW("videosink is not ready yet");
2131 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2134 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2136 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2137 LOGE("current type(%d) is wrong", curr_type);
2138 return MM_ERROR_PLAYER_INTERNAL;
2141 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2142 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2143 return MM_ERROR_PLAYER_INTERNAL;
2146 LOGD("param_name : %s", param_name);
2147 if (!g_strcmp0(param_name, "update_all_param"))
2148 update_all_param = TRUE;
2150 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2151 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2153 return MM_ERROR_NONE;
2155 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2156 __mmplayer_video_param_set_display_overlay(player);
2157 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2158 __mmplayer_video_param_set_display_method(player);
2159 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2160 __mmplayer_video_param_set_display_visible(player);
2161 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2162 __mmplayer_video_param_set_display_rotation(player);
2163 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2164 __mmplayer_video_param_set_roi_area(player);
2165 if (update_all_param)
2166 __mmplayer_video_param_set_video_roi_area(player);
2169 return MM_ERROR_NONE;
2172 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2174 gboolean disable_overlay = FALSE;
2177 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2178 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2179 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2181 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2182 LOGW("Display control is not supported");
2183 return MM_ERROR_PLAYER_INTERNAL;
2186 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2188 if (disable == (bool)disable_overlay) {
2189 LOGE("It's the same with current setting: (%d)", disable);
2190 return MM_ERROR_NONE;
2194 LOGE("disable overlay");
2195 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2197 /* release overlay resource */
2198 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2199 LOGE("failed to release overlay resource");
2200 return MM_ERROR_PLAYER_INTERNAL;
2203 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2204 LOGE("failed to acquire video overlay resource");
2205 return MM_ERROR_PLAYER_INTERNAL;
2207 player->interrupted_by_resource = FALSE;
2209 LOGD("enable overlay");
2210 __mmplayer_video_param_set_display_overlay(player);
2211 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2212 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2216 return MM_ERROR_NONE;
2220 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2222 int ret = MM_ERROR_NONE;
2223 mmplayer_t *player = (mmplayer_t *)hplayer;
2226 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2228 if (MMPLAYER_USE_DECODEBIN(player)) {
2229 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2234 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2235 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2236 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2238 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2240 /* release decoder resource */
2241 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2242 LOGE("failed to release video decoder resources");
2243 return MM_ERROR_PLAYER_INTERNAL;
2245 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2247 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2251 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2258 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2260 GList *bucket = element_bucket;
2261 mmplayer_gst_element_t *element = NULL;
2262 mmplayer_gst_element_t *prv_element = NULL;
2263 GstElement *tee_element = NULL;
2264 gint successful_link_count = 0;
2268 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2270 prv_element = (mmplayer_gst_element_t *)bucket->data;
2271 bucket = bucket->next;
2273 for (; bucket; bucket = bucket->next) {
2274 element = (mmplayer_gst_element_t *)bucket->data;
2276 if (element && element->gst) {
2277 if (prv_element && prv_element->gst) {
2278 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2280 prv_element->gst = tee_element;
2282 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2283 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2284 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2288 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2289 LOGD("linking [%s] to [%s] success",
2290 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2291 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2292 successful_link_count++;
2293 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2294 LOGD("keep audio-tee element for next audio pipeline branch");
2295 tee_element = prv_element->gst;
2298 LOGD("linking [%s] to [%s] failed",
2299 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2300 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2306 prv_element = element;
2311 return successful_link_count;
2315 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2317 GList *bucket = element_bucket;
2318 mmplayer_gst_element_t *element = NULL;
2319 int successful_add_count = 0;
2323 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2324 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2326 for (; bucket; bucket = bucket->next) {
2327 element = (mmplayer_gst_element_t *)bucket->data;
2329 if (element && element->gst) {
2330 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2331 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2332 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2333 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2336 successful_add_count++;
2342 return successful_add_count;
2346 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2348 mmplayer_t *player = (mmplayer_t *)data;
2349 GstCaps *caps = NULL;
2350 GstStructure *str = NULL;
2352 gboolean caps_ret = TRUE;
2356 MMPLAYER_RETURN_IF_FAIL(pad);
2357 MMPLAYER_RETURN_IF_FAIL(unused);
2358 MMPLAYER_RETURN_IF_FAIL(data);
2360 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2364 LOGD("name = %s", name);
2366 if (strstr(name, "audio")) {
2367 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2369 if (player->audio_stream_changed_cb) {
2370 LOGE("call the audio stream changed cb");
2371 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2373 } else if (strstr(name, "video")) {
2374 if ((name = gst_structure_get_string(str, "format")))
2375 player->set_mode.video_zc = name[0] == 'S';
2377 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2378 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2380 LOGW("invalid caps info");
2385 gst_caps_unref(caps);
2393 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2398 MMPLAYER_RETURN_IF_FAIL(player);
2400 if (player->audio_stream_buff_list) {
2401 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2402 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2405 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2406 __mmplayer_audio_stream_send_data(player, tmp);
2408 MMPLAYER_FREEIF(tmp->pcm_data);
2409 MMPLAYER_FREEIF(tmp);
2412 g_list_free(player->audio_stream_buff_list);
2413 player->audio_stream_buff_list = NULL;
2420 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2422 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2425 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2427 audio_stream.bitrate = a_buffer->bitrate;
2428 audio_stream.channel = a_buffer->channel;
2429 audio_stream.channel_mask = a_buffer->channel_mask;
2430 audio_stream.data_size = a_buffer->data_size;
2431 audio_stream.data = a_buffer->pcm_data;
2432 audio_stream.pcm_format = a_buffer->pcm_format;
2434 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2436 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2442 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2444 mmplayer_t *player = (mmplayer_t *)data;
2445 const gchar *pcm_format = NULL;
2448 guint64 channel_mask = 0;
2449 void *a_data = NULL;
2451 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2452 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2456 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2458 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2459 a_data = mapinfo.data;
2460 a_size = mapinfo.size;
2462 GstCaps *caps = gst_pad_get_current_caps(pad);
2463 GstStructure *structure = gst_caps_get_structure(caps, 0);
2465 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2467 pcm_format = gst_structure_get_string(structure, "format");
2468 gst_structure_get_int(structure, "rate", &rate);
2469 gst_structure_get_int(structure, "channels", &channel);
2470 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2471 gst_caps_unref(GST_CAPS(caps));
2473 /* In case of the sync is false, use buffer list. *
2474 * The num of buffer list depends on the num of audio channels */
2475 if (player->audio_stream_buff_list) {
2476 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2477 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2479 if (channel_mask == tmp->channel_mask) {
2481 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2483 if (tmp->data_size + a_size < tmp->buff_size) {
2484 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2485 tmp->data_size += a_size;
2487 /* send data to client */
2488 __mmplayer_audio_stream_send_data(player, tmp);
2490 if (a_size > tmp->buff_size) {
2491 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2492 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2493 if (tmp->pcm_data == NULL) {
2494 LOGE("failed to realloc data.");
2497 tmp->buff_size = a_size;
2499 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2500 memcpy(tmp->pcm_data, a_data, a_size);
2501 tmp->data_size = a_size;
2506 LOGE("data is empty in list.");
2512 /* create new audio stream data for newly found audio channel */
2513 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2514 if (a_buffer == NULL) {
2515 LOGE("failed to alloc data.");
2518 a_buffer->bitrate = rate;
2519 a_buffer->channel = channel;
2520 a_buffer->channel_mask = channel_mask;
2521 a_buffer->data_size = a_size;
2522 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2524 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2525 /* If sync is FALSE, use buffer list to reduce the IPC. */
2526 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2527 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2528 if (a_buffer->pcm_data == NULL) {
2529 LOGE("failed to alloc data.");
2530 MMPLAYER_FREEIF(a_buffer);
2533 memcpy(a_buffer->pcm_data, a_data, a_size);
2535 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2537 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2539 /* If sync is TRUE, send data directly. */
2540 a_buffer->pcm_data = a_data;
2541 __mmplayer_audio_stream_send_data(player, a_buffer);
2542 MMPLAYER_FREEIF(a_buffer);
2546 gst_buffer_unmap(buffer, &mapinfo);
2551 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2553 mmplayer_t *player = (mmplayer_t *)data;
2554 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2555 GstPad *sinkpad = NULL;
2556 GstElement *queue = NULL, *sink = NULL;
2559 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2561 queue = gst_element_factory_make("queue", NULL);
2562 if (queue == NULL) {
2563 LOGD("fail make queue");
2567 sink = gst_element_factory_make("fakesink", NULL);
2569 LOGD("fail make fakesink");
2573 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2575 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2576 LOGW("failed to link queue & sink");
2580 sinkpad = gst_element_get_static_pad(queue, "sink");
2582 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2583 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2587 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2589 gst_object_unref(sinkpad);
2590 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2591 g_object_set(sink, "sync", TRUE, NULL);
2592 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2594 /* keep the first sink reference only */
2595 if (!audiobin[MMPLAYER_A_SINK].gst) {
2596 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2597 audiobin[MMPLAYER_A_SINK].gst = sink;
2601 _mmplayer_add_signal_connection(player,
2603 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2605 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2608 __mmplayer_add_sink(player, sink, FALSE);
2610 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2611 LOGE("failed to sync state");
2615 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2616 LOGE("failed to sync state");
2624 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2626 gst_object_unref(GST_OBJECT(queue));
2630 gst_object_unref(GST_OBJECT(sink));
2634 gst_object_unref(GST_OBJECT(sinkpad));
2642 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2644 mmplayer_t *player = (mmplayer_t *)data;
2647 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2649 player->no_more_pad = TRUE;
2650 _mmplayer_pipeline_complete(NULL, player);
2657 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2659 #define MAX_PROPS_LEN 128
2660 mmplayer_gst_element_t *audiobin = NULL;
2661 gint latency_mode = 0;
2662 gchar *stream_type = NULL;
2663 gchar *latency = NULL;
2665 gchar stream_props[MAX_PROPS_LEN] = {0,};
2666 GstStructure *props = NULL;
2669 * It should be set after player creation through attribute.
2670 * But, it can not be changed during playing.
2673 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2675 audiobin = player->pipeline->audiobin;
2677 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2678 if (player->sound.mute) {
2679 LOGD("mute enabled");
2680 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2683 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2684 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2687 snprintf(stream_props, sizeof(stream_props) - 1,
2688 "props,application.process.id.origin=%d", player->client_pid);
2690 snprintf(stream_props, sizeof(stream_props) - 1,
2691 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2692 stream_type, stream_id, player->client_pid);
2694 props = gst_structure_from_string(stream_props, NULL);
2695 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2696 LOGI("props result[%s].", stream_props);
2697 gst_structure_free(props);
2699 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2701 switch (latency_mode) {
2702 case AUDIO_LATENCY_MODE_LOW:
2703 latency = g_strdup("low");
2705 case AUDIO_LATENCY_MODE_MID:
2706 latency = g_strdup("mid");
2708 case AUDIO_LATENCY_MODE_HIGH:
2709 latency = g_strdup("high");
2712 latency = g_strdup("mid");
2716 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2718 LOGD("audiosink property - latency=%s", latency);
2720 MMPLAYER_FREEIF(latency);
2726 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2728 mmplayer_gst_element_t *audiobin = NULL;
2731 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2732 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2734 audiobin = player->pipeline->audiobin;
2736 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2737 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2738 LOGE("failed to create media stream info");
2739 return MM_ERROR_PLAYER_INTERNAL;
2742 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2744 if (player->video360_yaw_radians <= M_PI &&
2745 player->video360_yaw_radians >= -M_PI &&
2746 player->video360_pitch_radians <= M_PI_2 &&
2747 player->video360_pitch_radians >= -M_PI_2) {
2748 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2749 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2750 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2751 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2752 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2753 "source-orientation-y", player->video360_metadata.init_view_heading,
2754 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2758 return MM_ERROR_NONE;
2762 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2764 mmplayer_gst_element_t *audiobin = NULL;
2765 GstPad *sink_pad = NULL;
2766 GstCaps *acaps = NULL;
2768 int pitch_control = 0;
2769 double pitch_value = 1.0;
2772 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2773 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2775 audiobin = player->pipeline->audiobin;
2777 LOGD("make element for normal audio playback");
2779 /* audio bin structure for playback. {} means optional.
2780 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2782 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2783 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2786 /* for pitch control */
2787 mm_attrs_multiple_get(player->attrs, NULL,
2788 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2789 MM_PLAYER_PITCH_VALUE, &pitch_value,
2792 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2793 if (pitch_control && (player->videodec_linked == 0)) {
2794 GstElementFactory *factory;
2796 factory = gst_element_factory_find("pitch");
2798 gst_object_unref(factory);
2801 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2804 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2805 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2807 LOGW("there is no pitch element");
2812 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2814 /* replaygain volume */
2815 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2816 if (player->sound.rg_enable)
2817 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2819 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2822 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2824 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2825 /* currently, only openalsink uses volume element */
2826 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2827 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2829 if (player->sound.mute) {
2830 LOGD("mute enabled");
2831 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2835 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2837 /* audio effect element. if audio effect is enabled */
2838 if ((strcmp(player->ini.audioeffect_element, ""))
2840 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2841 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2843 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2845 if ((!player->bypass_audio_effect)
2846 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2847 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2848 if (!_mmplayer_audio_effect_custom_apply(player))
2849 LOGI("apply audio effect(custom) setting success");
2853 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2854 && (player->set_mode.rich_audio)) {
2855 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2859 /* create audio sink */
2860 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2861 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2862 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2864 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2865 if (player->is_360_feature_enabled &&
2866 player->is_content_spherical &&
2868 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2869 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2870 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2872 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2874 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2876 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2877 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2878 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2879 gst_caps_unref(acaps);
2881 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2883 player->is_openal_plugin_used = TRUE;
2885 if (player->is_360_feature_enabled && player->is_content_spherical)
2886 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2887 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2890 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2891 (player->videodec_linked && player->ini.use_system_clock)) {
2892 LOGD("system clock will be used.");
2893 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2896 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2897 __mmplayer_gst_set_pulsesink_property(player);
2898 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2899 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2904 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2905 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2907 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2908 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2909 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2910 gst_object_unref(GST_OBJECT(sink_pad));
2912 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2915 return MM_ERROR_NONE;
2917 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2919 return MM_ERROR_PLAYER_INTERNAL;
2923 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2925 mmplayer_gst_element_t *audiobin = NULL;
2926 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2928 gchar *dst_format = NULL;
2930 int dst_samplerate = 0;
2931 int dst_channels = 0;
2932 GstCaps *caps = NULL;
2933 char *caps_str = NULL;
2936 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2937 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2939 audiobin = player->pipeline->audiobin;
2941 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2943 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2945 [case 1] extract interleave audio pcm without playback
2946 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2947 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2949 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2951 [case 2] deinterleave for each channel without playback
2952 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2953 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2955 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2956 - fakesink (sync or not)
2959 [case 3] [case 1(sync only)] + playback
2960 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2962 * src - ... - tee - queue1 - playback path
2963 - queue2 - [case1 pipeline with sync]
2965 [case 4] [case 2(sync only)] + playback
2966 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2968 * src - ... - tee - queue1 - playback path
2969 - queue2 - [case2 pipeline with sync]
2973 /* 1. create tee and playback path
2974 'tee' should be added at first to copy the decoded stream
2976 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2977 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2978 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2980 /* tee - path 1 : for playback path */
2981 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2982 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2984 /* tee - path 2 : for extract path */
2985 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2986 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2989 /* if there is tee, 'tee - path 2' is linked here */
2991 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2994 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2996 /* 2. decide the extract pcm format */
2997 mm_attrs_multiple_get(player->attrs, NULL,
2998 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2999 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3000 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3003 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3004 dst_format, dst_len, dst_samplerate, dst_channels);
3006 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3007 mm_attrs_multiple_get(player->attrs, NULL,
3008 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3009 "content_audio_samplerate", &dst_samplerate,
3010 "content_audio_channels", &dst_channels,
3013 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3014 dst_format, dst_len, dst_samplerate, dst_channels);
3016 /* If there is no enough information, set it to platform default value. */
3017 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3018 LOGD("set platform default format");
3019 dst_format = DEFAULT_PCM_OUT_FORMAT;
3021 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3022 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3025 /* 3. create capsfilter */
3026 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3027 caps = gst_caps_new_simple("audio/x-raw",
3028 "format", G_TYPE_STRING, dst_format,
3029 "rate", G_TYPE_INT, dst_samplerate,
3030 "channels", G_TYPE_INT, dst_channels,
3033 caps_str = gst_caps_to_string(caps);
3034 LOGD("new caps : %s", caps_str);
3036 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3039 gst_caps_unref(caps);
3040 MMPLAYER_FREEIF(caps_str);
3042 /* 4-1. create deinterleave to extract pcm for each channel */
3043 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3044 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3045 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3047 /* audiosink will be added after getting signal for each channel */
3048 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3049 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3050 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3051 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3052 player->no_more_pad = FALSE;
3054 /* 4-2. create fakesink to extract interleaved pcm */
3055 LOGD("add audio fakesink for interleaved audio");
3056 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3057 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3058 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3059 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3061 _mmplayer_add_signal_connection(player,
3062 G_OBJECT(audiobin[extract_sink_id].gst),
3063 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3065 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3068 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3072 return MM_ERROR_NONE;
3074 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3076 return MM_ERROR_PLAYER_INTERNAL;
3080 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3082 int ret = MM_ERROR_NONE;
3083 mmplayer_gst_element_t *audiobin = NULL;
3084 GList *element_bucket = NULL;
3087 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3088 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3090 audiobin = player->pipeline->audiobin;
3092 if (player->build_audio_offload) { /* skip all the audio filters */
3093 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3095 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3096 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3097 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3099 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3103 /* FIXME: need to mention the supportable condition at API reference */
3104 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3105 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3107 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3109 if (ret != MM_ERROR_NONE)
3112 LOGD("success to make audio bin element");
3113 *bucket = element_bucket;
3116 return MM_ERROR_NONE;
3119 LOGE("failed to make audio bin element");
3120 g_list_free(element_bucket);
3124 return MM_ERROR_PLAYER_INTERNAL;
3128 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3130 mmplayer_gst_element_t *first_element = NULL;
3131 mmplayer_gst_element_t *audiobin = NULL;
3133 GstPad *ghostpad = NULL;
3134 GList *element_bucket = NULL;
3138 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3141 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3143 LOGE("failed to allocate memory for audiobin");
3144 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3148 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3149 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3150 if (!audiobin[MMPLAYER_A_BIN].gst) {
3151 LOGE("failed to create audiobin");
3156 player->pipeline->audiobin = audiobin;
3158 /* create audio filters and audiosink */
3159 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3162 /* adding created elements to bin */
3163 LOGD("adding created elements to bin");
3164 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3167 /* linking elements in the bucket by added order. */
3168 LOGD("Linking elements in the bucket by added order.");
3169 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3172 /* get first element's sinkpad for creating ghostpad */
3173 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3174 if (!first_element) {
3175 LOGE("failed to get first elem");
3179 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3181 LOGE("failed to get pad from first element of audiobin");
3185 ghostpad = gst_ghost_pad_new("sink", pad);
3187 LOGE("failed to create ghostpad");
3191 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3192 LOGE("failed to add ghostpad to audiobin");
3196 gst_object_unref(pad);
3198 g_list_free(element_bucket);
3201 return MM_ERROR_NONE;
3204 LOGD("ERROR : releasing audiobin");
3207 gst_object_unref(GST_OBJECT(pad));
3210 gst_object_unref(GST_OBJECT(ghostpad));
3213 g_list_free(element_bucket);
3215 /* release element which are not added to bin */
3216 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3217 /* NOTE : skip bin */
3218 if (audiobin[i].gst) {
3219 GstObject *parent = NULL;
3220 parent = gst_element_get_parent(audiobin[i].gst);
3223 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3224 audiobin[i].gst = NULL;
3226 gst_object_unref(GST_OBJECT(parent));
3230 /* release audiobin with it's children */
3231 if (audiobin[MMPLAYER_A_BIN].gst)
3232 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3234 MMPLAYER_FREEIF(audiobin);
3236 player->pipeline->audiobin = NULL;
3238 return MM_ERROR_PLAYER_INTERNAL;
3242 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3244 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3248 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3250 int ret = MM_ERROR_NONE;
3252 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3253 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3255 MMPLAYER_VIDEO_BO_LOCK(player);
3257 if (player->video_bo_list) {
3258 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3259 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3260 if (tmp && tmp->bo == bo) {
3262 LOGD("release bo %p", bo);
3263 tbm_bo_unref(tmp->bo);
3264 MMPLAYER_VIDEO_BO_UNLOCK(player);
3265 MMPLAYER_VIDEO_BO_SIGNAL(player);
3270 /* hw codec is running or the list was reset for DRC. */
3271 LOGW("there is no bo list.");
3273 MMPLAYER_VIDEO_BO_UNLOCK(player);
3275 LOGW("failed to find bo %p", bo);
3279 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3285 tbm_bo_unref(tmp->bo);
3290 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3293 MMPLAYER_RETURN_IF_FAIL(player);
3295 MMPLAYER_VIDEO_BO_LOCK(player);
3296 if (player->video_bo_list) {
3297 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3298 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3299 player->video_bo_list = NULL;
3301 player->video_bo_size = 0;
3302 MMPLAYER_VIDEO_BO_UNLOCK(player);
3309 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3312 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3313 gboolean ret = TRUE;
3314 gint64 end_time = 0;
3316 /* check DRC, if it is, destroy the prev bo list to create again */
3317 if (player->video_bo_size != size) {
3318 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3319 __mmplayer_video_stream_destroy_bo_list(player);
3320 player->video_bo_size = size;
3323 MMPLAYER_VIDEO_BO_LOCK(player);
3325 if ((!player->video_bo_list) ||
3326 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3328 /* create bo list */
3330 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3332 if (player->video_bo_list) {
3333 /* if bo list did not created all, try it again. */
3334 idx = g_list_length(player->video_bo_list);
3335 LOGD("bo list exist(len: %d)", idx);
3338 for (; idx < player->ini.num_of_video_bo; idx++) {
3339 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3341 LOGE("Fail to alloc bo_info.");
3344 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3346 LOGE("Fail to tbm_bo_alloc.");
3347 MMPLAYER_FREEIF(bo_info);
3350 bo_info->used = FALSE;
3351 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3354 /* update video num buffers */
3355 LOGD("video_num_buffers : %d", idx);
3356 mm_player_set_attribute((MMHandleType)player, NULL,
3357 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3358 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3362 MMPLAYER_VIDEO_BO_UNLOCK(player);
3367 if (player->ini.video_bo_timeout > 0)
3368 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3371 /* get bo from list*/
3372 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3373 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3374 if (tmp && (tmp->used == FALSE)) {
3375 LOGD("found bo %p to use", tmp->bo);
3377 MMPLAYER_VIDEO_BO_UNLOCK(player);
3378 return tbm_bo_ref(tmp->bo);
3382 if (player->ini.video_bo_timeout <= 0) {
3383 MMPLAYER_VIDEO_BO_WAIT(player);
3385 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3387 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3393 MMPLAYER_VIDEO_BO_UNLOCK(player);
3398 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3400 mmplayer_t *player = (mmplayer_t *)data;
3402 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3404 /* send prerolled pkt */
3405 player->video_stream_prerolled = false;
3407 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3409 /* not to send prerolled pkt again */
3410 player->video_stream_prerolled = true;
3414 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3416 mmplayer_t *player = (mmplayer_t *)data;
3417 mmplayer_video_decoded_data_info_t *stream = NULL;
3418 GstMemory *mem = NULL;
3421 MMPLAYER_RETURN_IF_FAIL(player);
3422 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3424 if (player->video_stream_prerolled) {
3425 player->video_stream_prerolled = false;
3426 LOGD("skip the prerolled pkt not to send it again");
3430 /* clear stream data structure */
3431 stream = __mmplayer_create_stream_from_pad(pad);
3433 LOGE("failed to alloc stream");
3437 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3439 /* set size and timestamp */
3440 mem = gst_buffer_peek_memory(buffer, 0);
3441 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3442 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3444 /* check zero-copy */
3445 if (player->set_mode.video_zc &&
3446 player->set_mode.video_export &&
3447 gst_is_tizen_memory(mem)) {
3448 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3449 stream->internal_buffer = gst_buffer_ref(buffer);
3450 } else { /* sw codec */
3451 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3454 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3458 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3459 LOGE("failed to send video decoded data.");
3466 LOGE("release video stream resource.");
3467 if (gst_is_tizen_memory(mem)) {
3469 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3471 tbm_bo_unref(stream->bo[i]);
3474 /* unref gst buffer */
3475 if (stream->internal_buffer)
3476 gst_buffer_unref(stream->internal_buffer);
3479 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3481 MMPLAYER_FREEIF(stream);
3486 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3488 mmplayer_gst_element_t *videobin = NULL;
3491 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3493 videobin = player->pipeline->videobin;
3495 /* Set spatial media metadata and/or user settings to the element.
3497 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3498 "projection-type", player->video360_metadata.projection_type, NULL);
3500 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3501 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3503 if (player->video360_metadata.full_pano_width_pixels &&
3504 player->video360_metadata.full_pano_height_pixels &&
3505 player->video360_metadata.cropped_area_image_width &&
3506 player->video360_metadata.cropped_area_image_height) {
3507 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3508 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3509 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3510 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3511 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3512 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3513 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3517 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3518 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3519 "horizontal-fov", player->video360_horizontal_fov,
3520 "vertical-fov", player->video360_vertical_fov, NULL);
3523 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3524 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3525 "zoom", 1.0f / player->video360_zoom, NULL);
3528 if (player->video360_yaw_radians <= M_PI &&
3529 player->video360_yaw_radians >= -M_PI &&
3530 player->video360_pitch_radians <= M_PI_2 &&
3531 player->video360_pitch_radians >= -M_PI_2) {
3532 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3533 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3534 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3535 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3536 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3537 "pose-yaw", player->video360_metadata.init_view_heading,
3538 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3541 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3542 "passthrough", !player->is_video360_enabled, NULL);
3549 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3551 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3552 GList *element_bucket = NULL;
3555 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3557 /* create video360 filter */
3558 if (player->is_360_feature_enabled && player->is_content_spherical) {
3559 LOGD("create video360 element");
3560 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3561 __mmplayer_gst_set_video360_property(player);
3565 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3566 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3567 player->set_mode.video_zc) {
3568 LOGD("skip creating the videoconv and rotator");
3569 return MM_ERROR_NONE;
3572 /* in case of sw codec & overlay surface type, except 360 playback.
3573 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3574 LOGD("create video converter: %s", video_csc);
3575 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3578 *bucket = element_bucket;
3580 return MM_ERROR_NONE;
3582 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3583 g_list_free(element_bucket);
3587 return MM_ERROR_PLAYER_INTERNAL;
3591 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3593 gchar *factory_name = NULL;
3595 switch (surface_type) {
3596 case MM_DISPLAY_SURFACE_OVERLAY:
3598 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3599 if (strlen(player->ini.videosink_element_overlay) > 0)
3600 factory_name = player->ini.videosink_element_overlay;
3602 case MM_DISPLAY_SURFACE_REMOTE:
3604 case MM_DISPLAY_SURFACE_NULL:
3605 if (strlen(player->ini.videosink_element_fake) > 0)
3606 factory_name = player->ini.videosink_element_fake;
3609 LOGE("unidentified surface type");
3613 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3614 return factory_name;
3618 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3620 gchar *factory_name = NULL;
3621 mmplayer_gst_element_t *videobin = NULL;
3626 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3628 videobin = player->pipeline->videobin;
3629 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3631 attrs = MMPLAYER_GET_ATTRS(player);
3633 LOGE("cannot get content attribute");
3634 return MM_ERROR_PLAYER_INTERNAL;
3637 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3638 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3639 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3640 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3641 "use-tbm", use_tbm, NULL);
3644 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3645 return MM_ERROR_PLAYER_INTERNAL;
3647 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3650 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3651 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3654 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3656 LOGD("disable last-sample");
3657 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3660 if (player->set_mode.video_export) {
3662 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3663 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3664 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3666 _mmplayer_add_signal_connection(player,
3667 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3668 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3670 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3673 _mmplayer_add_signal_connection(player,
3674 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3675 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3677 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3681 if (videobin[MMPLAYER_V_SINK].gst) {
3682 GstPad *sink_pad = NULL;
3683 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3685 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3686 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3687 gst_object_unref(GST_OBJECT(sink_pad));
3689 LOGE("failed to get sink pad from videosink");
3693 return MM_ERROR_NONE;
3698 * - video overlay surface(arm/x86) : tizenwlsink
3701 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3704 GList *element_bucket = NULL;
3705 mmplayer_gst_element_t *first_element = NULL;
3706 mmplayer_gst_element_t *videobin = NULL;
3707 gchar *videosink_factory_name = NULL;
3710 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3713 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3715 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3717 player->pipeline->videobin = videobin;
3720 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3721 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3722 if (!videobin[MMPLAYER_V_BIN].gst) {
3723 LOGE("failed to create videobin");
3727 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3730 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3731 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3733 /* additional setting for sink plug-in */
3734 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3735 LOGE("failed to set video property");
3739 /* store it as it's sink element */
3740 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3742 /* adding created elements to bin */
3743 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3744 LOGE("failed to add elements");
3748 /* Linking elements in the bucket by added order */
3749 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3750 LOGE("failed to link elements");
3754 /* get first element's sinkpad for creating ghostpad */
3755 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3756 if (!first_element) {
3757 LOGE("failed to get first element from bucket");
3761 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3763 LOGE("failed to get pad from first element");
3767 /* create ghostpad */
3768 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3769 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3770 LOGE("failed to add ghostpad to videobin");
3773 gst_object_unref(pad);
3775 /* done. free allocated variables */
3776 g_list_free(element_bucket);
3780 return MM_ERROR_NONE;
3783 LOGE("ERROR : releasing videobin");
3784 g_list_free(element_bucket);
3787 gst_object_unref(GST_OBJECT(pad));
3789 /* release videobin with it's children */
3790 if (videobin[MMPLAYER_V_BIN].gst)
3791 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3793 MMPLAYER_FREEIF(videobin);
3794 player->pipeline->videobin = NULL;
3796 return MM_ERROR_PLAYER_INTERNAL;
3800 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3802 GList *element_bucket = NULL;
3803 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3805 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3806 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3807 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3808 "signal-handoffs", FALSE,
3811 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3812 _mmplayer_add_signal_connection(player,
3813 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3814 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3816 G_CALLBACK(__mmplayer_update_subtitle),
3819 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3820 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3822 if (!player->play_subtitle) {
3823 LOGD("add textbin sink as sink element of whole pipeline.");
3824 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3827 /* adding created elements to bin */
3828 LOGD("adding created elements to bin");
3829 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3830 LOGE("failed to add elements");
3834 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3835 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3836 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3838 /* linking elements in the bucket by added order. */
3839 LOGD("Linking elements in the bucket by added order.");
3840 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3841 LOGE("failed to link elements");
3845 if (textbin[MMPLAYER_T_QUEUE].gst) {
3847 GstPad *ghostpad = NULL;
3849 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3851 LOGE("failed to get sink pad of text queue");
3855 ghostpad = gst_ghost_pad_new("text_sink", pad);
3856 gst_object_unref(pad);
3859 LOGE("failed to create ghostpad of textbin");
3863 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3864 LOGE("failed to add ghostpad to textbin");
3865 gst_object_unref(ghostpad);
3870 g_list_free(element_bucket);
3872 return MM_ERROR_NONE;
3876 g_list_free(element_bucket);
3878 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3879 LOGE("remove textbin sink from sink list");
3880 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3883 /* release element at __mmplayer_gst_create_text_sink_bin */
3884 return MM_ERROR_PLAYER_INTERNAL;
3888 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3890 mmplayer_gst_element_t *textbin = NULL;
3891 int surface_type = 0;
3896 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3899 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3901 LOGE("failed to allocate memory for textbin");
3902 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3906 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3907 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3908 if (!textbin[MMPLAYER_T_BIN].gst) {
3909 LOGE("failed to create textbin");
3914 player->pipeline->textbin = textbin;
3917 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3918 LOGD("surface type for subtitle : %d", surface_type);
3919 switch (surface_type) {
3920 case MM_DISPLAY_SURFACE_OVERLAY:
3921 case MM_DISPLAY_SURFACE_NULL:
3922 case MM_DISPLAY_SURFACE_REMOTE:
3923 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3924 LOGE("failed to make plain text elements");
3935 return MM_ERROR_NONE;
3939 LOGD("ERROR : releasing textbin");
3941 /* release signal */
3942 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3944 /* release element which are not added to bin */
3945 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3946 /* NOTE : skip bin */
3947 if (textbin[i].gst) {
3948 GstObject *parent = NULL;
3949 parent = gst_element_get_parent(textbin[i].gst);
3952 gst_object_unref(GST_OBJECT(textbin[i].gst));
3953 textbin[i].gst = NULL;
3955 gst_object_unref(GST_OBJECT(parent));
3960 /* release textbin with it's children */
3961 if (textbin[MMPLAYER_T_BIN].gst)
3962 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3964 MMPLAYER_FREEIF(textbin);
3965 player->pipeline->textbin = NULL;
3968 return MM_ERROR_PLAYER_INTERNAL;
3972 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3974 mmplayer_gst_element_t *mainbin = NULL;
3975 mmplayer_gst_element_t *textbin = NULL;
3976 MMHandleType attrs = 0;
3977 GstElement *subsrc = NULL;
3978 GstElement *subparse = NULL;
3979 gchar *subtitle_uri = NULL;
3980 const gchar *charset = NULL;
3986 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3988 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3990 mainbin = player->pipeline->mainbin;
3992 attrs = MMPLAYER_GET_ATTRS(player);
3994 LOGE("cannot get content attribute");
3995 return MM_ERROR_PLAYER_INTERNAL;
3998 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3999 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4000 LOGE("subtitle uri is not proper filepath.");
4001 return MM_ERROR_PLAYER_INVALID_URI;
4004 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4005 LOGE("failed to get storage info of subtitle path");
4006 return MM_ERROR_PLAYER_INVALID_URI;
4009 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4011 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4012 player->subtitle_language_list = NULL;
4013 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4015 /* create the subtitle source */
4016 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4018 LOGE("failed to create filesrc element");
4021 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4023 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4024 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4026 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4027 LOGW("failed to add queue");
4028 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4029 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4030 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4035 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4037 LOGE("failed to create subparse element");
4041 charset = _mmplayer_get_charset(subtitle_uri);
4043 LOGD("detected charset is %s", charset);
4044 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4047 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4048 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4050 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4051 LOGW("failed to add subparse");
4052 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4053 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4054 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4058 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4059 LOGW("failed to link subsrc and subparse");
4063 player->play_subtitle = TRUE;
4064 player->adjust_subtitle_pos = 0;
4066 LOGD("play subtitle using subtitle file");
4068 if (player->pipeline->textbin == NULL) {
4069 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4070 LOGE("failed to create text sink bin. continuing without text");
4074 textbin = player->pipeline->textbin;
4076 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4077 LOGW("failed to add textbin");
4079 /* release signal */
4080 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4082 /* release textbin with it's children */
4083 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4084 MMPLAYER_FREEIF(player->pipeline->textbin);
4085 player->pipeline->textbin = textbin = NULL;
4089 LOGD("link text input selector and textbin ghost pad");
4091 player->textsink_linked = 1;
4092 player->external_text_idx = 0;
4093 LOGI("textsink is linked");
4095 textbin = player->pipeline->textbin;
4096 LOGD("text bin has been created. reuse it.");
4097 player->external_text_idx = 1;
4100 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4101 LOGW("failed to link subparse and textbin");
4105 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4107 LOGE("failed to get sink pad from textsink to probe data");
4111 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4112 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4114 gst_object_unref(pad);
4117 /* create dot. for debugging */
4118 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4121 return MM_ERROR_NONE;
4124 /* release text pipeline resource */
4125 player->textsink_linked = 0;
4127 /* release signal */
4128 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4130 if (player->pipeline->textbin) {
4131 LOGE("remove textbin");
4133 /* release textbin with it's children */
4134 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4135 MMPLAYER_FREEIF(player->pipeline->textbin);
4136 player->pipeline->textbin = NULL;
4140 /* release subtitle elem */
4141 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4142 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4144 return MM_ERROR_PLAYER_INTERNAL;
4148 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4150 mmplayer_t *player = (mmplayer_t *)data;
4151 MMMessageParamType msg = {0, };
4152 GstClockTime duration = 0;
4153 gpointer text = NULL;
4154 guint text_size = 0;
4155 gboolean ret = TRUE;
4156 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4160 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4161 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4163 if (player->is_subtitle_force_drop) {
4164 LOGW("subtitle is dropped forcedly.");
4168 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4169 text = mapinfo.data;
4170 text_size = mapinfo.size;
4172 if (player->set_mode.subtitle_off) {
4173 LOGD("subtitle is OFF.");
4177 if (!text || (text_size == 0)) {
4178 LOGD("There is no subtitle to be displayed.");
4182 msg.data = (void *)text;
4184 duration = GST_BUFFER_DURATION(buffer);
4186 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4187 if (player->duration > GST_BUFFER_PTS(buffer))
4188 duration = player->duration - GST_BUFFER_PTS(buffer);
4191 LOGI("subtitle duration is invalid, subtitle duration change "
4192 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4194 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4196 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4198 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4199 gst_buffer_unmap(buffer, &mapinfo);
4206 static GstPadProbeReturn
4207 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4209 mmplayer_t *player = (mmplayer_t *)u_data;
4210 GstClockTime cur_timestamp = 0;
4211 gint64 adjusted_timestamp = 0;
4212 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4214 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4216 if (player->set_mode.subtitle_off) {
4217 LOGD("subtitle is OFF.");
4221 if (player->adjust_subtitle_pos == 0) {
4222 LOGD("nothing to do");
4226 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4227 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4229 if (adjusted_timestamp < 0) {
4230 LOGD("adjusted_timestamp under zero");
4235 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4236 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4237 GST_TIME_ARGS(cur_timestamp),
4238 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4240 return GST_PAD_PROBE_OK;
4244 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4248 /* check player and subtitlebin are created */
4249 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4250 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4252 if (position == 0) {
4253 LOGD("nothing to do");
4255 return MM_ERROR_NONE;
4258 /* check current position */
4259 player->adjust_subtitle_pos = position;
4261 LOGD("save adjust_subtitle_pos in player");
4265 return MM_ERROR_NONE;
4269 * This function is to create audio or video pipeline for playing.
4271 * @param player [in] handle of player
4273 * @return This function returns zero on success.
4278 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4280 int ret = MM_ERROR_NONE;
4281 mmplayer_gst_element_t *mainbin = NULL;
4282 MMHandleType attrs = 0;
4285 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4287 /* get profile attribute */
4288 attrs = MMPLAYER_GET_ATTRS(player);
4290 LOGE("failed to get content attribute");
4294 /* create pipeline handles */
4295 if (player->pipeline) {
4296 LOGE("pipeline should be released before create new one");
4300 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4302 /* create mainbin */
4303 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4304 if (mainbin == NULL)
4307 /* create pipeline */
4308 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4309 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4310 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4311 LOGE("failed to create pipeline");
4316 player->pipeline->mainbin = mainbin;
4318 /* create the source and decoder elements */
4319 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4320 ret = _mmplayer_gst_build_es_pipeline(player);
4322 if (MMPLAYER_USE_DECODEBIN(player))
4323 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4325 ret = _mmplayer_gst_build_pipeline_with_src(player);
4328 if (ret != MM_ERROR_NONE) {
4329 LOGE("failed to create some elements");
4333 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4334 if (__mmplayer_check_subtitle(player)
4335 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4336 LOGE("failed to create text pipeline");
4339 ret = _mmplayer_gst_add_bus_watch(player);
4340 if (ret != MM_ERROR_NONE) {
4341 LOGE("failed to add bus watch");
4346 return MM_ERROR_NONE;
4349 _mmplayer_bus_watcher_remove(player);
4350 __mmplayer_gst_destroy_pipeline(player);
4351 return MM_ERROR_PLAYER_INTERNAL;
4355 __mmplayer_reset_gapless_state(mmplayer_t *player)
4358 MMPLAYER_RETURN_IF_FAIL(player
4360 && player->pipeline->audiobin
4361 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4363 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4370 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4373 int ret = MM_ERROR_NONE;
4377 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4379 /* cleanup stuffs */
4380 MMPLAYER_FREEIF(player->type);
4381 player->no_more_pad = FALSE;
4382 player->num_dynamic_pad = 0;
4384 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4385 player->subtitle_language_list = NULL;
4386 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4388 MMPLAYER_RECONFIGURE_LOCK(player);
4389 __mmplayer_reset_gapless_state(player);
4390 MMPLAYER_RECONFIGURE_UNLOCK(player);
4392 if (player->streamer) {
4393 _mm_player_streaming_initialize(player->streamer, FALSE);
4394 _mm_player_streaming_destroy(player->streamer);
4395 player->streamer = NULL;
4398 /* cleanup unlinked mime type */
4399 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4400 MMPLAYER_FREEIF(player->unlinked_video_mime);
4401 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4403 /* cleanup running stuffs */
4404 _mmplayer_cancel_eos_timer(player);
4406 /* cleanup gst stuffs */
4407 if (player->pipeline) {
4408 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4409 GstTagList *tag_list = player->pipeline->tag_list;
4411 /* first we need to disconnect all signal hander */
4412 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4415 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4416 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4417 gst_object_unref(bus);
4419 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4420 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4421 if (ret != MM_ERROR_NONE) {
4422 LOGE("fail to change state to NULL");
4423 return MM_ERROR_PLAYER_INTERNAL;
4426 LOGW("succeeded in changing state to NULL");
4428 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4431 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4432 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4434 MMPLAYER_FREEIF(player->pipeline->audiobin);
4435 MMPLAYER_FREEIF(player->pipeline->videobin);
4436 MMPLAYER_FREEIF(player->pipeline->textbin);
4437 MMPLAYER_FREEIF(mainbin);
4441 gst_tag_list_unref(tag_list);
4443 MMPLAYER_FREEIF(player->pipeline);
4445 MMPLAYER_FREEIF(player->album_art);
4447 if (player->type_caps) {
4448 gst_caps_unref(player->type_caps);
4449 player->type_caps = NULL;
4452 if (player->v_stream_caps) {
4453 gst_caps_unref(player->v_stream_caps);
4454 player->v_stream_caps = NULL;
4457 if (player->a_stream_caps) {
4458 gst_caps_unref(player->a_stream_caps);
4459 player->a_stream_caps = NULL;
4462 if (player->s_stream_caps) {
4463 gst_caps_unref(player->s_stream_caps);
4464 player->s_stream_caps = NULL;
4466 _mmplayer_track_destroy(player);
4468 if (player->sink_elements)
4469 g_list_free(player->sink_elements);
4470 player->sink_elements = NULL;
4472 if (player->bufmgr) {
4473 tbm_bufmgr_deinit(player->bufmgr);
4474 player->bufmgr = NULL;
4477 LOGW("finished destroy pipeline");
4485 __mmplayer_gst_realize(mmplayer_t *player)
4488 int ret = MM_ERROR_NONE;
4492 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4494 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4496 ret = __mmplayer_gst_create_pipeline(player);
4498 LOGE("failed to create pipeline");
4502 /* set pipeline state to READY */
4503 /* NOTE : state change to READY must be performed sync. */
4504 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4505 ret = _mmplayer_gst_set_state(player,
4506 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4508 if (ret != MM_ERROR_NONE) {
4509 /* return error if failed to set state */
4510 LOGE("failed to set READY state");
4514 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4516 /* create dot before error-return. for debugging */
4517 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4525 __mmplayer_gst_unrealize(mmplayer_t *player)
4527 int ret = MM_ERROR_NONE;
4531 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4533 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4534 MMPLAYER_PRINT_STATE(player);
4536 /* release miscellaneous information */
4537 __mmplayer_release_misc(player);
4539 /* destroy pipeline */
4540 ret = __mmplayer_gst_destroy_pipeline(player);
4541 if (ret != MM_ERROR_NONE) {
4542 LOGE("failed to destroy pipeline");
4546 /* release miscellaneous information.
4547 these info needs to be released after pipeline is destroyed. */
4548 __mmplayer_release_misc_post(player);
4550 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4558 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4563 LOGW("set_message_callback is called with invalid player handle");
4564 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4567 player->msg_cb = callback;
4568 player->msg_cb_param = user_param;
4570 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4574 return MM_ERROR_NONE;
4578 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4580 int ret = MM_ERROR_NONE;
4585 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4586 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4587 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4589 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4591 if (strstr(uri, "es_buff://")) {
4592 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4593 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4594 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4595 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4597 tmp = g_ascii_strdown(uri, strlen(uri));
4598 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4599 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4601 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4603 } else if (strstr(uri, "mms://")) {
4604 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4605 } else if ((path = strstr(uri, "mem://"))) {
4606 ret = __mmplayer_set_mem_uri(data, path, param);
4608 ret = __mmplayer_set_file_uri(data, uri);
4611 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4612 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4613 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4614 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4616 /* dump parse result */
4617 SECURE_LOGW("incoming uri : %s", uri);
4618 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4619 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4627 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4630 mmplayer_t *player = NULL;
4631 MMMessageParamType msg = {0, };
4633 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4638 LOGE("user_data is null");
4642 player = (mmplayer_t *)user_data;
4644 if (!player->pipeline || !player->attrs) {
4645 LOGW("not initialized");
4649 LOGD("cmd lock player, cmd state : %d", player->cmd);
4650 MMPLAYER_CMD_LOCK(player);
4651 LOGD("cmd locked player");
4653 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4654 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4655 LOGW("player already destroyed");
4656 MMPLAYER_CMD_UNLOCK(player);
4660 player->interrupted_by_resource = TRUE;
4662 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4664 /* get last play position */
4665 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4666 msg.union_type = MM_MSG_UNION_TIME;
4667 msg.time.elapsed = pos;
4668 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4670 LOGW("failed to get play position.");
4673 LOGD("video resource conflict so, resource will be freed by unrealizing");
4674 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4675 LOGE("failed to unrealize");
4677 MMPLAYER_CMD_UNLOCK(player);
4679 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4680 player->hw_resource[res_idx] = NULL;
4684 return TRUE; /* release all the resources */
4688 __mmplayer_initialize_video_roi(mmplayer_t *player)
4690 player->video_roi.scale_x = 0.0;
4691 player->video_roi.scale_y = 0.0;
4692 player->video_roi.scale_width = 1.0;
4693 player->video_roi.scale_height = 1.0;
4697 _mmplayer_create_player(MMHandleType handle)
4699 int ret = MM_ERROR_PLAYER_INTERNAL;
4700 bool enabled = false;
4702 mmplayer_t *player = MM_PLAYER_CAST(handle);
4706 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4708 /* initialize player state */
4709 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4710 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4711 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4712 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4714 /* check current state */
4715 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4717 /* construct attributes */
4718 player->attrs = _mmplayer_construct_attribute(handle);
4720 if (!player->attrs) {
4721 LOGE("Failed to construct attributes");
4725 /* initialize gstreamer with configured parameter */
4726 if (!__mmplayer_init_gstreamer(player)) {
4727 LOGE("Initializing gstreamer failed");
4728 _mmplayer_deconstruct_attribute(handle);
4732 /* create lock. note that g_tread_init() has already called in gst_init() */
4733 g_mutex_init(&player->fsink_lock);
4735 /* create update tag lock */
4736 g_mutex_init(&player->update_tag_lock);
4738 /* create gapless play mutex */
4739 g_mutex_init(&player->gapless_play_thread_mutex);
4741 /* create gapless play cond */
4742 g_cond_init(&player->gapless_play_thread_cond);
4744 /* create gapless play thread */
4745 player->gapless_play_thread =
4746 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4747 if (!player->gapless_play_thread) {
4748 LOGE("failed to create gapless play thread");
4749 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4750 g_mutex_clear(&player->gapless_play_thread_mutex);
4751 g_cond_clear(&player->gapless_play_thread_cond);
4755 player->bus_msg_q = g_queue_new();
4756 if (!player->bus_msg_q) {
4757 LOGE("failed to create queue for bus_msg");
4758 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4762 ret = _mmplayer_initialize_video_capture(player);
4763 if (ret != MM_ERROR_NONE) {
4764 LOGW("video capture is not supported");
4765 /* do not handle as error for headless profile */
4768 /* initialize resource manager */
4769 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4770 __resource_release_cb, player, &player->resource_manager)
4771 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4772 LOGE("failed to create resource manager");
4773 ret = MM_ERROR_PLAYER_INTERNAL;
4777 /* create video bo lock and cond */
4778 g_mutex_init(&player->video_bo_mutex);
4779 g_cond_init(&player->video_bo_cond);
4781 /* create subtitle info lock and cond */
4782 g_mutex_init(&player->subtitle_info_mutex);
4783 g_cond_init(&player->subtitle_info_cond);
4785 player->streaming_type = STREAMING_SERVICE_NONE;
4787 /* give default value of audio effect setting */
4788 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4789 player->sound.rg_enable = false;
4790 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4792 player->play_subtitle = FALSE;
4793 player->has_closed_caption = FALSE;
4794 player->pending_resume = FALSE;
4795 if (player->ini.dump_element_keyword[0][0] == '\0')
4796 player->ini.set_dump_element_flag = FALSE;
4798 player->ini.set_dump_element_flag = TRUE;
4800 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4801 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4802 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4804 /* Set video360 settings to their defaults for just-created player.
4807 player->is_360_feature_enabled = FALSE;
4808 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4809 LOGI("spherical feature info: %d", enabled);
4811 player->is_360_feature_enabled = TRUE;
4813 LOGE("failed to get spherical feature info");
4816 player->is_content_spherical = FALSE;
4817 player->is_video360_enabled = TRUE;
4818 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4819 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4820 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4821 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4822 player->video360_zoom = 1.0f;
4823 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4824 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4826 __mmplayer_initialize_video_roi(player);
4828 /* set player state to null */
4829 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4830 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4834 return MM_ERROR_NONE;
4838 g_mutex_clear(&player->fsink_lock);
4839 /* free update tag lock */
4840 g_mutex_clear(&player->update_tag_lock);
4841 g_queue_free(player->bus_msg_q);
4842 player->bus_msg_q = NULL;
4843 /* free gapless play thread */
4844 if (player->gapless_play_thread) {
4845 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4846 player->gapless_play_thread_exit = TRUE;
4847 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4848 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4850 g_thread_join(player->gapless_play_thread);
4851 player->gapless_play_thread = NULL;
4853 g_mutex_clear(&player->gapless_play_thread_mutex);
4854 g_cond_clear(&player->gapless_play_thread_cond);
4857 /* release attributes */
4858 _mmplayer_deconstruct_attribute(handle);
4866 __mmplayer_init_gstreamer(mmplayer_t *player)
4868 static gboolean initialized = FALSE;
4869 static const int max_argc = 50;
4871 gchar **argv = NULL;
4872 gchar **argv2 = NULL;
4878 LOGD("gstreamer already initialized.");
4883 argc = malloc(sizeof(int));
4884 argv = malloc(sizeof(gchar *) * max_argc);
4885 argv2 = malloc(sizeof(gchar *) * max_argc);
4887 if (!argc || !argv || !argv2)
4890 memset(argv, 0, sizeof(gchar *) * max_argc);
4891 memset(argv2, 0, sizeof(gchar *) * max_argc);
4895 argv[0] = g_strdup("mmplayer");
4898 for (i = 0; i < 5; i++) {
4899 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4900 if (strlen(player->ini.gst_param[i]) > 0) {
4901 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4906 /* we would not do fork for scanning plugins */
4907 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4910 /* check disable registry scan */
4911 if (player->ini.skip_rescan) {
4912 argv[*argc] = g_strdup("--gst-disable-registry-update");
4916 /* check disable segtrap */
4917 if (player->ini.disable_segtrap) {
4918 argv[*argc] = g_strdup("--gst-disable-segtrap");
4922 LOGD("initializing gstreamer with following parameter");
4923 LOGD("argc : %d", *argc);
4926 for (i = 0; i < arg_count; i++) {
4928 LOGD("argv[%d] : %s", i, argv2[i]);
4931 /* initializing gstreamer */
4932 if (!gst_init_check(argc, &argv, &err)) {
4933 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4940 for (i = 0; i < arg_count; i++) {
4942 LOGD("release - argv[%d] : %s", i, argv2[i]);
4944 MMPLAYER_FREEIF(argv2[i]);
4947 MMPLAYER_FREEIF(argv);
4948 MMPLAYER_FREEIF(argv2);
4949 MMPLAYER_FREEIF(argc);
4959 for (i = 0; i < arg_count; i++) {
4960 LOGD("free[%d] : %s", i, argv2[i]);
4961 MMPLAYER_FREEIF(argv2[i]);
4964 MMPLAYER_FREEIF(argv);
4965 MMPLAYER_FREEIF(argv2);
4966 MMPLAYER_FREEIF(argc);
4972 __mmplayer_check_async_state_transition(mmplayer_t *player)
4974 GstState element_state = GST_STATE_VOID_PENDING;
4975 GstState element_pending_state = GST_STATE_VOID_PENDING;
4976 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4977 GstElement *element = NULL;
4978 gboolean async = FALSE;
4980 /* check player handle */
4981 MMPLAYER_RETURN_IF_FAIL(player &&
4983 player->pipeline->mainbin &&
4984 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4987 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4989 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4990 LOGD("don't need to check the pipeline state");
4994 MMPLAYER_PRINT_STATE(player);
4996 /* wait for state transition */
4997 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4998 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5000 if (ret == GST_STATE_CHANGE_FAILURE) {
5001 LOGE(" [%s] state : %s pending : %s",
5002 GST_ELEMENT_NAME(element),
5003 gst_element_state_get_name(element_state),
5004 gst_element_state_get_name(element_pending_state));
5006 /* dump state of all element */
5007 _mmplayer_dump_pipeline_state(player);
5012 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5017 _mmplayer_destroy(MMHandleType handle)
5019 mmplayer_t *player = MM_PLAYER_CAST(handle);
5023 /* check player handle */
5024 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5026 /* destroy can called at anytime */
5027 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5029 /* check async state transition */
5030 __mmplayer_check_async_state_transition(player);
5032 /* release gapless play thread */
5033 if (player->gapless_play_thread) {
5034 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5035 player->gapless_play_thread_exit = TRUE;
5036 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5037 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5039 LOGD("waiting for gapless play thread exit");
5040 g_thread_join(player->gapless_play_thread);
5041 g_mutex_clear(&player->gapless_play_thread_mutex);
5042 g_cond_clear(&player->gapless_play_thread_cond);
5043 LOGD("gapless play thread released");
5046 _mmplayer_release_video_capture(player);
5048 /* release miscellaneous information */
5049 __mmplayer_release_misc(player);
5051 /* release pipeline */
5052 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5053 LOGE("failed to destroy pipeline");
5054 return MM_ERROR_PLAYER_INTERNAL;
5057 __mmplayer_destroy_hw_resource(player);
5059 g_queue_free(player->bus_msg_q);
5061 /* release subtitle info lock and cond */
5062 g_mutex_clear(&player->subtitle_info_mutex);
5063 g_cond_clear(&player->subtitle_info_cond);
5065 __mmplayer_release_dump_list(player->dump_list);
5067 /* release miscellaneous information.
5068 these info needs to be released after pipeline is destroyed. */
5069 __mmplayer_release_misc_post(player);
5071 /* release attributes */
5072 _mmplayer_deconstruct_attribute(handle);
5074 if (player->uri_info.uri_list) {
5075 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5076 player->uri_info.uri_list = NULL;
5080 g_mutex_clear(&player->fsink_lock);
5083 g_mutex_clear(&player->update_tag_lock);
5085 /* release video bo lock and cond */
5086 g_mutex_clear(&player->video_bo_mutex);
5087 g_cond_clear(&player->video_bo_cond);
5091 return MM_ERROR_NONE;
5095 _mmplayer_realize(MMHandleType hplayer)
5097 mmplayer_t *player = (mmplayer_t *)hplayer;
5098 int ret = MM_ERROR_NONE;
5101 MMHandleType attrs = 0;
5105 /* check player handle */
5106 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5108 /* check current state */
5109 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5111 attrs = MMPLAYER_GET_ATTRS(player);
5113 LOGE("fail to get attributes.");
5114 return MM_ERROR_PLAYER_INTERNAL;
5116 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5117 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5119 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5120 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5122 if (ret != MM_ERROR_NONE) {
5123 LOGE("failed to parse profile");
5128 if (uri && (strstr(uri, "es_buff://"))) {
5129 if (strstr(uri, "es_buff://push_mode"))
5130 player->es_player_push_mode = TRUE;
5132 player->es_player_push_mode = FALSE;
5135 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5136 LOGW("mms protocol is not supported format.");
5137 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5140 if (MMPLAYER_IS_STREAMING(player))
5141 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5143 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5145 player->smooth_streaming = FALSE;
5146 player->videodec_linked = 0;
5147 player->audiodec_linked = 0;
5148 player->textsink_linked = 0;
5149 player->is_external_subtitle_present = FALSE;
5150 player->is_external_subtitle_added_now = FALSE;
5151 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5152 player->video360_metadata.is_spherical = -1;
5153 player->is_openal_plugin_used = FALSE;
5154 player->subtitle_language_list = NULL;
5155 player->is_subtitle_force_drop = FALSE;
5157 _mmplayer_track_initialize(player);
5158 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5160 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5161 gint prebuffer_ms = 0, rebuffer_ms = 0;
5163 player->streamer = _mm_player_streaming_create();
5164 _mm_player_streaming_initialize(player->streamer, TRUE);
5166 mm_attrs_multiple_get(player->attrs, NULL,
5167 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5168 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5170 if (prebuffer_ms > 0) {
5171 prebuffer_ms = MAX(prebuffer_ms, 1000);
5172 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5175 if (rebuffer_ms > 0) {
5176 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5177 rebuffer_ms = MAX(rebuffer_ms, 1000);
5178 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5181 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5182 player->streamer->buffering_req.rebuffer_time);
5185 /* realize pipeline */
5186 ret = __mmplayer_gst_realize(player);
5187 if (ret != MM_ERROR_NONE)
5188 LOGE("fail to realize the player.");
5190 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5198 _mmplayer_unrealize(MMHandleType hplayer)
5200 mmplayer_t *player = (mmplayer_t *)hplayer;
5201 int ret = MM_ERROR_NONE;
5202 int rm_ret = MM_ERROR_NONE;
5203 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5207 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5209 MMPLAYER_CMD_UNLOCK(player);
5210 _mmplayer_bus_watcher_remove(player);
5211 /* destroy the gst bus msg thread which is created during realize.
5212 this funct have to be called before getting cmd lock. */
5213 _mmplayer_bus_msg_thread_destroy(player);
5214 MMPLAYER_CMD_LOCK(player);
5216 /* check current state */
5217 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5219 /* check async state transition */
5220 __mmplayer_check_async_state_transition(player);
5222 /* unrealize pipeline */
5223 ret = __mmplayer_gst_unrealize(player);
5225 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5226 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5227 if (rm_ret != MM_ERROR_NONE)
5228 LOGE("failed to release [%d] resources", res_idx);
5231 player->interrupted_by_resource = FALSE;
5238 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5240 mmplayer_t *player = (mmplayer_t *)hplayer;
5242 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5244 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5248 _mmplayer_get_state(MMHandleType hplayer, int *state)
5250 mmplayer_t *player = (mmplayer_t *)hplayer;
5252 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5254 *state = MMPLAYER_CURRENT_STATE(player);
5256 return MM_ERROR_NONE;
5260 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5262 GstElement *vol_element = NULL;
5263 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5266 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5267 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5269 /* check pipeline handle */
5270 if (!player->pipeline || !player->pipeline->audiobin) {
5271 LOGD("'%s' will be applied when audiobin is created", prop_name);
5273 /* NOTE : stored value will be used in create_audiobin
5274 * returning MM_ERROR_NONE here makes application to able to
5275 * set audio volume or mute at anytime.
5277 return MM_ERROR_NONE;
5280 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5281 volume_elem_id = MMPLAYER_A_SINK;
5283 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5285 LOGE("failed to get vol element %d", volume_elem_id);
5286 return MM_ERROR_PLAYER_INTERNAL;
5289 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5291 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5292 LOGE("there is no '%s' property", prop_name);
5293 return MM_ERROR_PLAYER_INTERNAL;
5296 if (!strcmp(prop_name, "volume")) {
5297 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5298 } else if (!strcmp(prop_name, "mute")) {
5299 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5301 LOGE("invalid property %s", prop_name);
5302 return MM_ERROR_PLAYER_INTERNAL;
5305 return MM_ERROR_NONE;
5309 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5311 int ret = MM_ERROR_NONE;
5312 mmplayer_t *player = (mmplayer_t *)hplayer;
5315 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5317 LOGD("volume = %f", volume);
5319 /* invalid factor range or not */
5320 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5321 LOGE("Invalid volume value");
5322 return MM_ERROR_INVALID_ARGUMENT;
5325 player->sound.volume = volume;
5327 ret = __mmplayer_gst_set_volume_property(player, "volume");
5334 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5336 mmplayer_t *player = (mmplayer_t *)hplayer;
5340 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5341 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5343 *volume = player->sound.volume;
5345 LOGD("current vol = %f", *volume);
5348 return MM_ERROR_NONE;
5352 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5354 int ret = MM_ERROR_NONE;
5355 mmplayer_t *player = (mmplayer_t *)hplayer;
5358 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5360 LOGD("mute = %d", mute);
5362 player->sound.mute = mute;
5364 ret = __mmplayer_gst_set_volume_property(player, "mute");
5371 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5373 mmplayer_t *player = (mmplayer_t *)hplayer;
5377 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5378 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5380 *mute = player->sound.mute;
5382 LOGD("current mute = %d", *mute);
5386 return MM_ERROR_NONE;
5390 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5392 mmplayer_t *player = (mmplayer_t *)hplayer;
5396 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5398 player->audio_stream_changed_cb = callback;
5399 player->audio_stream_changed_cb_user_param = user_param;
5400 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5404 return MM_ERROR_NONE;
5408 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5410 mmplayer_t *player = (mmplayer_t *)hplayer;
5414 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5416 player->audio_decoded_cb = callback;
5417 player->audio_decoded_cb_user_param = user_param;
5418 player->audio_extract_opt = opt;
5419 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5423 return MM_ERROR_NONE;
5427 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5429 mmplayer_t *player = (mmplayer_t *)hplayer;
5433 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5435 if (callback && !player->bufmgr)
5436 player->bufmgr = tbm_bufmgr_init(-1);
5438 player->set_mode.video_export = (callback) ? true : false;
5439 player->video_decoded_cb = callback;
5440 player->video_decoded_cb_user_param = user_param;
5442 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5446 return MM_ERROR_NONE;
5450 _mmplayer_start(MMHandleType hplayer)
5452 mmplayer_t *player = (mmplayer_t *)hplayer;
5453 gint ret = MM_ERROR_NONE;
5457 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5459 /* check current state */
5460 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5462 /* start pipeline */
5463 ret = _mmplayer_gst_start(player);
5464 if (ret != MM_ERROR_NONE)
5465 LOGE("failed to start player.");
5467 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5468 LOGD("force playing start even during buffering");
5469 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5477 /* NOTE: post "not supported codec message" to application
5478 * when one codec is not found during AUTOPLUGGING in MSL.
5479 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5480 * And, if any codec is not found, don't send message here.
5481 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5484 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5486 MMMessageParamType msg_param;
5487 memset(&msg_param, 0, sizeof(MMMessageParamType));
5488 gboolean post_msg_direct = FALSE;
5492 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5494 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5495 player->not_supported_codec, player->can_support_codec);
5497 if (player->not_found_demuxer) {
5498 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5499 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5501 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5502 MMPLAYER_FREEIF(msg_param.data);
5504 return MM_ERROR_NONE;
5507 if (player->not_supported_codec) {
5508 if (player->can_support_codec) {
5509 // There is one codec to play
5510 post_msg_direct = TRUE;
5512 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5513 post_msg_direct = TRUE;
5516 if (post_msg_direct) {
5517 MMMessageParamType msg_param;
5518 memset(&msg_param, 0, sizeof(MMMessageParamType));
5520 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5521 LOGW("not found AUDIO codec, posting error code to application.");
5523 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5524 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5525 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5526 LOGW("not found VIDEO codec, posting error code to application.");
5528 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5529 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5532 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5534 MMPLAYER_FREEIF(msg_param.data);
5536 return MM_ERROR_NONE;
5538 // no any supported codec case
5539 LOGW("not found any codec, posting error code to application.");
5541 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5542 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5543 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5545 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5546 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5549 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5551 MMPLAYER_FREEIF(msg_param.data);
5557 return MM_ERROR_NONE;
5560 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5562 GstState element_state = GST_STATE_VOID_PENDING;
5563 GstState element_pending_state = GST_STATE_VOID_PENDING;
5564 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5565 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5567 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5569 MMPLAYER_RECONFIGURE_LOCK(player);
5570 if (!player->gapless.reconfigure) {
5571 MMPLAYER_RECONFIGURE_UNLOCK(player);
5575 LOGI("reconfigure is under process");
5576 MMPLAYER_RECONFIGURE_WAIT(player);
5577 MMPLAYER_RECONFIGURE_UNLOCK(player);
5578 LOGI("reconfigure is completed.");
5580 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5581 &element_state, &element_pending_state, timeout * GST_SECOND);
5582 if (result == GST_STATE_CHANGE_FAILURE)
5583 LOGW("failed to get pipeline state in %d sec", timeout);
5588 /* NOTE : it should be able to call 'stop' anytime*/
5590 _mmplayer_stop(MMHandleType hplayer)
5592 mmplayer_t *player = (mmplayer_t *)hplayer;
5593 int ret = MM_ERROR_NONE;
5597 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5599 /* check current state */
5600 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5602 /* need to wait till the rebuilding pipeline is completed */
5603 __mmplayer_check_pipeline_reconfigure_state(player);
5604 MMPLAYER_RECONFIGURE_LOCK(player);
5605 __mmplayer_reset_gapless_state(player);
5606 MMPLAYER_RECONFIGURE_UNLOCK(player);
5608 /* NOTE : application should not wait for EOS after calling STOP */
5609 _mmplayer_cancel_eos_timer(player);
5612 player->seek_state = MMPLAYER_SEEK_NONE;
5615 ret = _mmplayer_gst_stop(player);
5617 if (ret != MM_ERROR_NONE)
5618 LOGE("failed to stop player.");
5626 _mmplayer_pause(MMHandleType hplayer)
5628 mmplayer_t *player = (mmplayer_t *)hplayer;
5629 gint64 pos_nsec = 0;
5630 gboolean async = FALSE;
5631 gint ret = MM_ERROR_NONE;
5635 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5637 /* check current state */
5638 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5640 /* check pipeline reconfigure state */
5641 __mmplayer_check_pipeline_reconfigure_state(player);
5643 switch (MMPLAYER_CURRENT_STATE(player)) {
5644 case MM_PLAYER_STATE_READY:
5646 /* check prepare async or not.
5647 * In the case of streaming playback, it's recommended to avoid blocking wait.
5649 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5650 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5652 /* Changing back sync of rtspsrc to async */
5653 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5654 LOGD("async prepare working mode for rtsp");
5660 case MM_PLAYER_STATE_PLAYING:
5662 /* NOTE : store current point to overcome some bad operation
5663 *(returning zero when getting current position in paused state) of some
5666 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5667 LOGW("getting current position failed in paused");
5669 player->last_position = pos_nsec;
5671 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5672 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5673 This causes problem is position calculation during normal pause resume scenarios also.
5674 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5675 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5676 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5677 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5683 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5684 LOGD("doing async pause in case of ms buff src");
5688 /* pause pipeline */
5689 ret = _mmplayer_gst_pause(player, async);
5690 if (ret != MM_ERROR_NONE) {
5691 LOGE("failed to pause player. ret : 0x%x", ret);
5692 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5696 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5697 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5698 LOGE("failed to update display_rotation");
5702 return MM_ERROR_NONE;
5705 /* in case of streaming, pause could take long time.*/
5707 _mmplayer_abort_pause(MMHandleType hplayer)
5709 mmplayer_t *player = (mmplayer_t *)hplayer;
5710 int ret = MM_ERROR_NONE;
5714 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5716 player->pipeline->mainbin,
5717 MM_ERROR_PLAYER_NOT_INITIALIZED);
5719 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5720 LOGD("set the videobin state to READY");
5721 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5722 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5726 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5727 LOGD("set the audiobin state to READY");
5728 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5729 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5733 LOGD("set the pipeline state to READY");
5734 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5735 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5737 if (ret != MM_ERROR_NONE) {
5738 LOGE("fail to change state to READY");
5739 return MM_ERROR_PLAYER_INTERNAL;
5742 LOGD("succeeded in changing state to READY");
5747 _mmplayer_resume(MMHandleType hplayer)
5749 mmplayer_t *player = (mmplayer_t *)hplayer;
5750 int ret = MM_ERROR_NONE;
5751 gboolean async = FALSE;
5755 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5757 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5758 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5759 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5763 /* Changing back sync mode rtspsrc to async */
5764 LOGD("async resume for rtsp case");
5768 /* check current state */
5769 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5771 ret = _mmplayer_gst_resume(player, async);
5772 if (ret != MM_ERROR_NONE)
5773 LOGE("failed to resume player.");
5775 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5776 LOGD("force resume even during buffering");
5777 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5786 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5788 mmplayer_t *player = (mmplayer_t *)hplayer;
5789 gint64 pos_nsec = 0;
5790 int ret = MM_ERROR_NONE;
5792 signed long long start = 0, stop = 0;
5793 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5796 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5797 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5799 /* The sound of video is not supported under 0.0 and over 2.0. */
5800 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5801 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5804 _mmplayer_set_mute(hplayer, mute);
5806 if (player->playback_rate == rate)
5807 return MM_ERROR_NONE;
5809 /* If the position is reached at start potion during fast backward, EOS is posted.
5810 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5812 player->playback_rate = rate;
5814 current_state = MMPLAYER_CURRENT_STATE(player);
5816 if (current_state != MM_PLAYER_STATE_PAUSED)
5817 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5819 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5821 if ((current_state == MM_PLAYER_STATE_PAUSED)
5822 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5823 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5824 pos_nsec = player->last_position;
5829 stop = GST_CLOCK_TIME_NONE;
5831 start = GST_CLOCK_TIME_NONE;
5835 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5836 player->playback_rate,
5838 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5839 GST_SEEK_TYPE_SET, start,
5840 GST_SEEK_TYPE_SET, stop)) {
5841 LOGE("failed to set speed playback");
5842 return MM_ERROR_PLAYER_SEEK;
5845 LOGD("succeeded to set speed playback as %0.1f", rate);
5849 return MM_ERROR_NONE;;
5853 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5855 mmplayer_t *player = (mmplayer_t *)hplayer;
5856 int ret = MM_ERROR_NONE;
5860 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5862 /* check pipeline reconfigure state */
5863 __mmplayer_check_pipeline_reconfigure_state(player);
5865 ret = _mmplayer_gst_set_position(player, position, FALSE);
5873 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5875 mmplayer_t *player = (mmplayer_t *)hplayer;
5876 int ret = MM_ERROR_NONE;
5878 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5879 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5881 if (g_strrstr(player->type, "video/mpegts"))
5882 __mmplayer_update_duration_value(player);
5884 *duration = player->duration;
5889 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5891 mmplayer_t *player = (mmplayer_t *)hplayer;
5892 int ret = MM_ERROR_NONE;
5894 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5896 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5902 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5904 mmplayer_t *player = (mmplayer_t *)hplayer;
5905 int ret = MM_ERROR_NONE;
5909 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5911 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5919 __mmplayer_is_midi_type(gchar *str_caps)
5921 if ((g_strrstr(str_caps, "audio/midi")) ||
5922 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5923 (g_strrstr(str_caps, "application/x-smaf")) ||
5924 (g_strrstr(str_caps, "audio/x-imelody")) ||
5925 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5926 (g_strrstr(str_caps, "audio/xmf")) ||
5927 (g_strrstr(str_caps, "audio/mxmf"))) {
5936 __mmplayer_is_only_mp3_type(gchar *str_caps)
5938 if (g_strrstr(str_caps, "application/x-id3") ||
5939 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5945 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5947 GstStructure *caps_structure = NULL;
5948 gint samplerate = 0;
5952 MMPLAYER_RETURN_IF_FAIL(player && caps);
5954 caps_structure = gst_caps_get_structure(caps, 0);
5956 /* set stream information */
5957 gst_structure_get_int(caps_structure, "rate", &samplerate);
5958 gst_structure_get_int(caps_structure, "channels", &channels);
5960 mm_player_set_attribute((MMHandleType)player, NULL,
5961 "content_audio_samplerate", samplerate,
5962 "content_audio_channels", channels, NULL);
5964 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5968 __mmplayer_update_content_type_info(mmplayer_t *player)
5971 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5973 if (__mmplayer_is_midi_type(player->type)) {
5974 player->bypass_audio_effect = TRUE;
5978 if (!player->streamer) {
5979 LOGD("no need to check streaming type");
5983 if (g_strrstr(player->type, "application/x-hls")) {
5984 /* If it can't know exact type when it parses uri because of redirection case,
5985 * it will be fixed by typefinder or when doing autoplugging.
5987 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5988 player->streamer->is_adaptive_streaming = TRUE;
5989 } else if (g_strrstr(player->type, "application/dash+xml")) {
5990 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5991 player->streamer->is_adaptive_streaming = TRUE;
5994 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5995 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5996 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5998 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5999 if (player->streamer->is_adaptive_streaming)
6000 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6002 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6006 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6011 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6012 GstCaps *caps, gpointer data)
6014 mmplayer_t *player = (mmplayer_t *)data;
6018 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6020 /* store type string */
6021 if (player->type_caps) {
6022 gst_caps_unref(player->type_caps);
6023 player->type_caps = NULL;
6026 player->type_caps = gst_caps_copy(caps);
6027 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
6029 MMPLAYER_FREEIF(player->type);
6030 player->type = gst_caps_to_string(caps);
6032 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6033 player, player->type, probability, gst_caps_get_size(caps));
6035 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6036 (g_strrstr(player->type, "audio/x-raw-int"))) {
6037 LOGE("not support media format");
6039 if (player->msg_posted == FALSE) {
6040 MMMessageParamType msg_param;
6041 memset(&msg_param, 0, sizeof(MMMessageParamType));
6043 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6044 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6046 /* don't post more if one was sent already */
6047 player->msg_posted = TRUE;
6052 __mmplayer_update_content_type_info(player);
6054 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6057 pad = gst_element_get_static_pad(tf, "src");
6059 LOGE("fail to get typefind src pad.");
6063 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6064 gboolean async = FALSE;
6065 LOGE("failed to autoplug %s", player->type);
6067 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6069 if (async && player->msg_posted == FALSE)
6070 __mmplayer_handle_missed_plugin(player);
6072 gst_object_unref(GST_OBJECT(pad));
6079 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6081 GstElement *decodebin = NULL;
6085 /* create decodebin */
6086 decodebin = gst_element_factory_make("decodebin", NULL);
6089 LOGE("fail to create decodebin");
6093 /* raw pad handling signal */
6094 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6095 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6097 /* no-more-pad pad handling signal */
6098 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6099 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6101 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6102 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6104 /* This signal is emitted when a pad for which there is no further possible
6105 decoding is added to the decodebin.*/
6106 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6107 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6109 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6110 before looking for any elements that can handle that stream.*/
6111 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6112 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6114 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6115 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6116 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6118 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6119 before looking for any elements that can handle that stream.*/
6120 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6121 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6123 /* This signal is emitted once decodebin has finished decoding all the data.*/
6124 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6125 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6127 /* This signal is emitted when a element is added to the bin.*/
6128 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6129 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6136 __mmplayer_gst_make_queue2(mmplayer_t *player)
6138 GstElement *queue2 = NULL;
6139 gint64 dur_bytes = 0L;
6140 mmplayer_gst_element_t *mainbin = NULL;
6141 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6144 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6146 mainbin = player->pipeline->mainbin;
6148 queue2 = gst_element_factory_make("queue2", "queue2");
6150 LOGE("failed to create buffering queue element");
6154 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6155 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6157 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6159 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6160 * skip the pull mode(file or ring buffering) setting. */
6161 if (dur_bytes > 0) {
6162 if (!g_strrstr(player->type, "video/mpegts")) {
6163 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6164 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6170 _mm_player_streaming_set_queue2(player->streamer,
6174 (guint64)dur_bytes); /* no meaning at the moment */
6180 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6182 mmplayer_gst_element_t *mainbin = NULL;
6183 GstElement *decodebin = NULL;
6184 GstElement *queue2 = NULL;
6185 GstPad *sinkpad = NULL;
6186 GstPad *qsrcpad = NULL;
6189 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6191 mainbin = player->pipeline->mainbin;
6193 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6195 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6196 LOGW("need to check: muxed buffer is not null");
6199 queue2 = __mmplayer_gst_make_queue2(player);
6201 LOGE("failed to make queue2");
6205 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6206 LOGE("failed to add buffering queue");
6210 sinkpad = gst_element_get_static_pad(queue2, "sink");
6211 qsrcpad = gst_element_get_static_pad(queue2, "src");
6213 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6214 LOGE("failed to link [%s:%s]-[%s:%s]",
6215 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6219 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6220 LOGE("failed to sync queue2 state with parent");
6224 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6225 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6229 gst_object_unref(GST_OBJECT(sinkpad));
6233 /* create decodebin */
6234 decodebin = _mmplayer_gst_make_decodebin(player);
6236 LOGE("failed to make decodebin");
6240 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6241 LOGE("failed to add decodebin");
6245 /* to force caps on the decodebin element and avoid reparsing stuff by
6246 * typefind. It also avoids a deadlock in the way typefind activates pads in
6247 * the state change */
6248 g_object_set(decodebin, "sink-caps", caps, NULL);
6250 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6252 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6253 LOGE("failed to link [%s:%s]-[%s:%s]",
6254 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6258 gst_object_unref(GST_OBJECT(sinkpad));
6260 gst_object_unref(GST_OBJECT(qsrcpad));
6263 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6264 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6266 /* set decodebin property about buffer in streaming playback. *
6267 * in case of HLS/DASH, it does not need to have big buffer *
6268 * because it is kind of adaptive streaming. */
6269 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6270 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6271 gint high_percent = 0;
6273 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6274 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6276 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6278 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6280 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6281 "high-percent", high_percent,
6282 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6283 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6284 "max-size-buffers", 0, NULL); // disable or automatic
6287 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6288 LOGE("failed to sync decodebin state with parent");
6299 gst_object_unref(GST_OBJECT(sinkpad));
6302 gst_object_unref(GST_OBJECT(qsrcpad));
6305 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6306 * You need to explicitly set elements to the NULL state before
6307 * dropping the final reference, to allow them to clean up.
6309 gst_element_set_state(queue2, GST_STATE_NULL);
6311 /* And, it still has a parent "player".
6312 * You need to let the parent manage the object instead of unreffing the object directly.
6314 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6315 gst_object_unref(queue2);
6320 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6321 * You need to explicitly set elements to the NULL state before
6322 * dropping the final reference, to allow them to clean up.
6324 gst_element_set_state(decodebin, GST_STATE_NULL);
6326 /* And, it still has a parent "player".
6327 * You need to let the parent manage the object instead of unreffing the object directly.
6330 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6331 gst_object_unref(decodebin);
6339 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6343 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6344 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6346 LOGD("class : %s, mime : %s", factory_class, mime);
6348 /* add missing plugin */
6349 /* NOTE : msl should check missing plugin for image mime type.
6350 * Some motion jpeg clips can have playable audio track.
6351 * So, msl have to play audio after displaying popup written video format not supported.
6353 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6354 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6355 LOGD("not found demuxer");
6356 player->not_found_demuxer = TRUE;
6357 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6363 if (!g_strrstr(factory_class, "Demuxer")) {
6364 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6365 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6366 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6368 /* check that clip have multi tracks or not */
6369 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6370 LOGD("video plugin is already linked");
6372 LOGW("add VIDEO to missing plugin");
6373 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6374 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6376 } else if (g_str_has_prefix(mime, "audio")) {
6377 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6378 LOGD("audio plugin is already linked");
6380 LOGW("add AUDIO to missing plugin");
6381 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6382 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6390 return MM_ERROR_NONE;
6394 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6396 mmplayer_t *player = (mmplayer_t *)data;
6400 MMPLAYER_RETURN_IF_FAIL(player);
6402 /* remove fakesink. */
6403 if (!_mmplayer_gst_remove_fakesink(player,
6404 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6405 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6406 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6407 * source element are not same. To overcome this situation, this function will called
6408 * several places and several times. Therefore, this is not an error case.
6413 LOGD("[handle: %p] pipeline has completely constructed", player);
6415 if ((player->msg_posted == FALSE) &&
6416 (player->cmd >= MMPLAYER_COMMAND_START))
6417 __mmplayer_handle_missed_plugin(player);
6419 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6423 __mmplayer_check_profile(void)
6426 static int profile_tv = -1;
6428 if (__builtin_expect(profile_tv != -1, 1))
6431 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6432 switch (*profileName) {
6447 __mmplayer_get_next_uri(mmplayer_t *player)
6449 mmplayer_parse_profile_t profile;
6451 guint num_of_list = 0;
6454 num_of_list = g_list_length(player->uri_info.uri_list);
6455 uri_idx = player->uri_info.uri_idx;
6457 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6458 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6459 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6461 LOGW("next uri does not exist");
6465 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6466 LOGE("failed to parse profile");
6470 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6471 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6472 LOGW("uri type is not supported(%d)", profile.uri_type);
6476 LOGD("success to find next uri %d", uri_idx);
6480 if (!uri || uri_idx == num_of_list) {
6481 LOGE("failed to find next uri");
6485 player->uri_info.uri_idx = uri_idx;
6486 if (mm_player_set_attribute((MMHandleType)player, NULL,
6487 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6488 LOGE("failed to set attribute");
6492 SECURE_LOGD("next playback uri: %s", uri);
6497 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6499 #define REPEAT_COUNT_INFINITE -1
6500 #define REPEAT_COUNT_MIN 2
6501 #define ORIGINAL_URI_ONLY 1
6503 MMHandleType attrs = 0;
6507 guint num_of_uri = 0;
6508 int profile_tv = -1;
6512 LOGD("checking for gapless play option");
6514 if (player->build_audio_offload) {
6515 LOGE("offload path is not supportable.");
6519 if (player->pipeline->textbin) {
6520 LOGE("subtitle path is enabled. gapless play is not supported.");
6524 attrs = MMPLAYER_GET_ATTRS(player);
6526 LOGE("fail to get attributes.");
6530 mm_attrs_multiple_get(player->attrs, NULL,
6531 "content_video_found", &video,
6532 "profile_play_count", &count,
6533 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6535 /* gapless playback is not supported in case of video at TV profile. */
6536 profile_tv = __mmplayer_check_profile();
6537 if (profile_tv && video) {
6538 LOGW("not support video gapless playback");
6542 /* check repeat count in case of audio */
6544 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6545 LOGW("gapless is disabled");
6549 num_of_uri = g_list_length(player->uri_info.uri_list);
6551 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6553 if (num_of_uri == ORIGINAL_URI_ONLY) {
6554 /* audio looping path */
6555 if (count >= REPEAT_COUNT_MIN) {
6556 /* decrease play count */
6557 /* we succeeded to rewind. update play count and then wait for next EOS */
6559 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6560 } else if (count != REPEAT_COUNT_INFINITE) {
6561 LOGD("there is no next uri and no repeat");
6564 LOGD("looping cnt %d", count);
6566 /* gapless playback path */
6567 if (!__mmplayer_get_next_uri(player)) {
6568 LOGE("failed to get next uri");
6575 LOGE("unable to play gapless path. EOS will be posted soon");
6580 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6582 GstPad *sinkpad = g_value_get_object (item);
6583 GstElement *element = GST_ELEMENT(user_data);
6584 if (!sinkpad || !element) {
6585 LOGE("invalid parameter");
6589 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6590 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6594 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6596 mmplayer_gst_element_t *sinkbin = NULL;
6597 main_element_id_e concatId = MMPLAYER_M_NUM;
6598 main_element_id_e sinkId = MMPLAYER_M_NUM;
6599 gboolean send_notice = FALSE;
6600 GstElement *element;
6604 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6606 LOGD("type %d", type);
6609 case MM_PLAYER_TRACK_TYPE_AUDIO:
6610 concatId = MMPLAYER_M_A_CONCAT;
6611 sinkId = MMPLAYER_A_BIN;
6612 sinkbin = player->pipeline->audiobin;
6614 case MM_PLAYER_TRACK_TYPE_VIDEO:
6615 concatId = MMPLAYER_M_V_CONCAT;
6616 sinkId = MMPLAYER_V_BIN;
6617 sinkbin = player->pipeline->videobin;
6620 case MM_PLAYER_TRACK_TYPE_TEXT:
6621 concatId = MMPLAYER_M_T_CONCAT;
6622 sinkId = MMPLAYER_T_BIN;
6623 sinkbin = player->pipeline->textbin;
6626 LOGE("requested type is not supportable");
6631 element = player->pipeline->mainbin[concatId].gst;
6635 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6636 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6637 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6638 if (srcpad && sinkpad) {
6639 /* after getting drained signal there is no data flows, so no need to do pad_block */
6640 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6641 gst_pad_unlink(srcpad, sinkpad);
6643 /* send custom event to sink pad to handle it at video sink */
6645 LOGD("send custom event to sinkpad");
6646 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6647 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6648 gst_pad_send_event(sinkpad, event);
6651 gst_object_unref(srcpad);
6652 gst_object_unref(sinkpad);
6655 LOGD("release concat request pad");
6656 /* release and unref requests pad from the selector */
6657 iter = gst_element_iterate_sink_pads(element);
6658 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6659 gst_iterator_resync(iter);
6660 gst_iterator_free(iter);
6666 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6668 mmplayer_track_t *selector = &player->track[type];
6669 mmplayer_gst_element_t *sinkbin = NULL;
6670 main_element_id_e selectorId = MMPLAYER_M_NUM;
6671 main_element_id_e sinkId = MMPLAYER_M_NUM;
6672 GstPad *srcpad = NULL;
6673 GstPad *sinkpad = NULL;
6674 gboolean send_notice = FALSE;
6677 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6679 LOGD("type %d", type);
6682 case MM_PLAYER_TRACK_TYPE_AUDIO:
6683 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6684 sinkId = MMPLAYER_A_BIN;
6685 sinkbin = player->pipeline->audiobin;
6687 case MM_PLAYER_TRACK_TYPE_VIDEO:
6688 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6689 sinkId = MMPLAYER_V_BIN;
6690 sinkbin = player->pipeline->videobin;
6693 case MM_PLAYER_TRACK_TYPE_TEXT:
6694 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6695 sinkId = MMPLAYER_T_BIN;
6696 sinkbin = player->pipeline->textbin;
6699 LOGE("requested type is not supportable");
6704 if (player->pipeline->mainbin[selectorId].gst) {
6707 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6709 if (selector->event_probe_id != 0)
6710 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6711 selector->event_probe_id = 0;
6713 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6714 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6716 if (srcpad && sinkpad) {
6717 /* after getting drained signal there is no data flows, so no need to do pad_block */
6718 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6719 gst_pad_unlink(srcpad, sinkpad);
6721 /* send custom event to sink pad to handle it at video sink */
6723 LOGD("send custom event to sinkpad");
6724 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6725 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6726 gst_pad_send_event(sinkpad, event);
6730 gst_object_unref(sinkpad);
6733 gst_object_unref(srcpad);
6736 LOGD("selector release");
6738 /* release and unref requests pad from the selector */
6739 for (n = 0; n < selector->streams->len; n++) {
6740 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6741 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6744 g_ptr_array_set_size(selector->streams, 0);
6746 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6747 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6749 player->pipeline->mainbin[selectorId].gst = NULL;
6757 __mmplayer_deactivate_old_path(mmplayer_t *player)
6760 MMPLAYER_RETURN_IF_FAIL(player);
6762 if (MMPLAYER_USE_DECODEBIN(player)) {
6763 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6764 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6765 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6766 LOGE("deactivate selector error");
6770 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6771 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6772 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6773 LOGE("deactivate concat error");
6778 _mmplayer_track_destroy(player);
6779 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6781 if (player->streamer) {
6782 _mm_player_streaming_initialize(player->streamer, FALSE);
6783 _mm_player_streaming_destroy(player->streamer);
6784 player->streamer = NULL;
6787 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6793 if (!player->msg_posted) {
6794 MMMessageParamType msg = {0,};
6797 msg.code = MM_ERROR_PLAYER_INTERNAL;
6798 LOGE("gapless_uri_play> deactivate error");
6800 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6801 player->msg_posted = TRUE;
6807 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6809 int result = MM_ERROR_NONE;
6810 mmplayer_t *player = (mmplayer_t *)hplayer;
6813 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6814 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6816 if (mm_player_set_attribute(hplayer, NULL,
6817 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6818 LOGE("failed to set attribute");
6819 result = MM_ERROR_PLAYER_INTERNAL;
6821 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6822 LOGE("failed to add the original uri in the uri list.");
6830 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6832 mmplayer_t *player = (mmplayer_t *)hplayer;
6833 guint num_of_list = 0;
6837 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6838 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6840 if (player->pipeline && player->pipeline->textbin) {
6841 LOGE("subtitle path is enabled.");
6842 return MM_ERROR_PLAYER_INVALID_STATE;
6845 num_of_list = g_list_length(player->uri_info.uri_list);
6847 if (is_first_path) {
6848 if (num_of_list == 0) {
6849 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6850 SECURE_LOGD("add original path : %s", uri);
6852 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6853 player->uri_info.uri_list = g_list_prepend(
6854 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6855 SECURE_LOGD("change original path : %s", uri);
6858 MMHandleType attrs = 0;
6859 attrs = MMPLAYER_GET_ATTRS(player);
6861 if (num_of_list == 0) {
6862 char *original_uri = NULL;
6865 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6867 if (!original_uri) {
6868 LOGE("there is no original uri.");
6869 return MM_ERROR_PLAYER_INVALID_STATE;
6872 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6873 player->uri_info.uri_idx = 0;
6875 SECURE_LOGD("add original path at first : %s", original_uri);
6879 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6880 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6884 return MM_ERROR_NONE;
6888 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6890 mmplayer_t *player = (mmplayer_t *)hplayer;
6891 char *next_uri = NULL;
6892 guint num_of_list = 0;
6895 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6897 num_of_list = g_list_length(player->uri_info.uri_list);
6899 if (num_of_list > 0) {
6900 gint uri_idx = player->uri_info.uri_idx;
6902 if (uri_idx < num_of_list - 1)
6907 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6908 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6910 *uri = g_strdup(next_uri);
6914 return MM_ERROR_NONE;
6918 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6919 GstCaps *caps, gpointer data)
6921 mmplayer_t *player = (mmplayer_t *)data;
6922 const gchar *klass = NULL;
6923 const gchar *mime = NULL;
6924 gchar *caps_str = NULL;
6926 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6927 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6928 caps_str = gst_caps_to_string(caps);
6930 LOGW("unknown type of caps : %s from %s",
6931 caps_str, GST_ELEMENT_NAME(elem));
6933 MMPLAYER_FREEIF(caps_str);
6935 /* There is no available codec. */
6936 __mmplayer_check_not_supported_codec(player, klass, mime);
6940 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6941 GstCaps *caps, gpointer data)
6943 mmplayer_t *player = (mmplayer_t *)data;
6944 const char *mime = NULL;
6945 gboolean ret = TRUE;
6947 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6948 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6950 if (g_str_has_prefix(mime, "audio")) {
6951 GstStructure *caps_structure = NULL;
6952 gint samplerate = 0;
6954 gchar *caps_str = NULL;
6956 caps_structure = gst_caps_get_structure(caps, 0);
6957 gst_structure_get_int(caps_structure, "rate", &samplerate);
6958 gst_structure_get_int(caps_structure, "channels", &channels);
6960 if ((channels > 0 && samplerate == 0)) {
6961 LOGD("exclude audio...");
6965 caps_str = gst_caps_to_string(caps);
6966 /* set it directly because not sent by TAG */
6967 if (g_strrstr(caps_str, "mobile-xmf"))
6968 mm_player_set_attribute((MMHandleType)player, NULL,
6969 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6971 MMPLAYER_FREEIF(caps_str);
6972 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6973 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
6974 LOGD("video is already linked, allow the stream switch");
6977 LOGD("video is already linked");
6981 LOGD("found new stream");
6988 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6990 gboolean ret = FALSE;
6991 GDBusConnection *conn = NULL;
6993 GVariant *result = NULL;
6994 const gchar *dbus_device_type = NULL;
6995 const gchar *dbus_ret = NULL;
6998 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7000 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7005 result = g_dbus_connection_call_sync(conn,
7006 "org.pulseaudio.Server",
7007 "/org/pulseaudio/StreamManager",
7008 "org.pulseaudio.StreamManager",
7009 "GetCurrentMediaRoutingPath",
7010 g_variant_new("(s)", "out"),
7011 G_VARIANT_TYPE("(ss)"),
7012 G_DBUS_CALL_FLAGS_NONE,
7016 if (!result || err) {
7017 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7022 /* device type is listed in stream-map.json at mmfw-sysconf */
7023 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7025 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7026 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7029 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7030 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7031 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7032 LOGD("audio offload is supportable");
7038 LOGD("audio offload is not supportable");
7041 g_variant_unref(result);
7043 g_object_unref(conn);
7048 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7050 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7051 gint64 position = 0;
7053 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7054 player->pipeline && player->pipeline->mainbin);
7056 MMPLAYER_CMD_LOCK(player);
7057 current_state = MMPLAYER_CURRENT_STATE(player);
7059 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7060 LOGW("getting current position failed in paused");
7062 _mmplayer_unrealize((MMHandleType)player);
7063 _mmplayer_realize((MMHandleType)player);
7065 _mmplayer_set_position((MMHandleType)player, position);
7067 /* async not to be blocked in streaming case */
7068 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7070 _mmplayer_pause((MMHandleType)player);
7072 if (current_state == MM_PLAYER_STATE_PLAYING)
7073 _mmplayer_start((MMHandleType)player);
7074 MMPLAYER_CMD_UNLOCK(player);
7076 LOGD("rebuilding audio pipeline is completed.");
7079 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7081 mmplayer_t *player = (mmplayer_t *)user_data;
7082 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7083 gboolean is_supportable = FALSE;
7085 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7086 LOGW("failed to get device type");
7088 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7090 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7091 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7092 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7093 LOGD("ignore this dev connected info");
7097 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7098 if (player->build_audio_offload == is_supportable) {
7099 LOGD("keep current pipeline without re-building");
7103 /* rebuild pipeline */
7104 LOGD("re-build pipeline - offload: %d", is_supportable);
7105 player->build_audio_offload = FALSE;
7106 __mmplayer_rebuild_audio_pipeline(player);
7112 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7114 unsigned int id = 0;
7116 if (player->audio_device_cb_id != 0) {
7117 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7121 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7122 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7123 LOGD("added device connected cb (%u)", id);
7124 player->audio_device_cb_id = id;
7126 LOGW("failed to add device connected cb");
7133 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7135 mmplayer_t *player = (mmplayer_t *)hplayer;
7138 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7139 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7141 *activated = player->build_audio_offload;
7143 LOGD("offload activated : %d", (int)*activated);
7146 return MM_ERROR_NONE;
7150 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7153 this function need to be updated according to the supported media format
7154 @see player->ini.audio_offload_media_format */
7156 if (__mmplayer_is_only_mp3_type(player->type)) {
7157 LOGD("offload supportable media format type");
7165 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7167 gboolean ret = FALSE;
7168 GstElementFactory *factory = NULL;
7171 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7173 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7174 if (!__mmplayer_is_offload_supported_type(player))
7177 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7178 LOGD("there is no audio offload sink");
7182 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7183 LOGW("there is no audio device type to support offload");
7187 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7189 LOGW("there is no installed audio offload sink element");
7192 gst_object_unref(factory);
7194 if (_mmplayer_acquire_hw_resource(player,
7195 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7196 LOGE("failed to acquire audio offload decoder resource");
7200 if (!__mmplayer_add_audio_device_connected_cb(player))
7203 if (!__mmplayer_is_audio_offload_device_type(player))
7206 LOGD("audio offload can be built");
7211 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7217 static GstAutoplugSelectResult
7218 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7220 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7221 int audio_offload = 0;
7223 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7224 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7226 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7227 LOGD("expose audio path to build offload output path");
7228 player->build_audio_offload = TRUE;
7229 /* update codec info */
7230 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7231 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7232 player->audiodec_linked = 1;
7234 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7238 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7239 And need to consider the multi-track audio content.
7240 There is no HW audio decoder in public. */
7242 /* set stream information */
7243 if (!player->audiodec_linked)
7244 _mmplayer_set_audio_attrs(player, caps);
7246 /* update codec info */
7247 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7248 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7249 player->audiodec_linked = 1;
7251 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7253 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7254 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7256 /* mark video decoder for acquire */
7257 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7258 LOGW("video decoder resource is already acquired, skip it.");
7259 ret = GST_AUTOPLUG_SELECT_SKIP;
7263 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7264 LOGE("failed to acquire video decoder resource");
7265 ret = GST_AUTOPLUG_SELECT_SKIP;
7268 player->interrupted_by_resource = FALSE;
7271 /* update codec info */
7272 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7273 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7274 player->videodec_linked = 1;
7282 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7283 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7285 #define DEFAULT_IDX 0xFFFF
7286 #define MIN_FACTORY_NUM 2
7287 mmplayer_t *player = (mmplayer_t *)data;
7288 GValueArray *new_factories = NULL;
7289 GValue val = { 0, };
7290 GstElementFactory *factory = NULL;
7291 const gchar *klass = NULL;
7292 gchar *factory_name = NULL;
7293 guint hw_dec_idx = DEFAULT_IDX;
7294 guint first_sw_dec_idx = DEFAULT_IDX;
7295 guint last_sw_dec_idx = DEFAULT_IDX;
7296 guint new_pos = DEFAULT_IDX;
7297 guint rm_pos = DEFAULT_IDX;
7298 int audio_codec_type;
7299 int video_codec_type;
7300 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7302 if (factories->n_values < MIN_FACTORY_NUM)
7305 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7306 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7309 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7311 for (int i = 0 ; i < factories->n_values ; i++) {
7312 gchar *hw_dec_info = NULL;
7313 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7315 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7317 LOGW("failed to get factory object");
7320 klass = gst_element_factory_get_klass(factory);
7321 factory_name = GST_OBJECT_NAME(factory);
7324 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7326 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7327 if (!player->need_audio_dec_sorting) {
7328 LOGD("sorting is not required");
7331 codec_type = audio_codec_type;
7332 hw_dec_info = player->ini.audiocodec_element_hw;
7333 sw_dec_info = player->ini.audiocodec_element_sw;
7334 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7335 if (!player->need_video_dec_sorting) {
7336 LOGD("sorting is not required");
7339 codec_type = video_codec_type;
7340 hw_dec_info = player->ini.videocodec_element_hw;
7341 sw_dec_info = player->ini.videocodec_element_sw;
7346 if (g_strrstr(factory_name, hw_dec_info)) {
7349 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7350 if (strstr(factory_name, sw_dec_info[j])) {
7351 last_sw_dec_idx = i;
7352 if (first_sw_dec_idx == DEFAULT_IDX) {
7353 first_sw_dec_idx = i;
7358 if (first_sw_dec_idx == DEFAULT_IDX)
7359 LOGW("unknown codec %s", factory_name);
7363 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7366 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7367 if (hw_dec_idx < first_sw_dec_idx)
7369 new_pos = first_sw_dec_idx;
7370 rm_pos = hw_dec_idx + 1;
7371 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7372 if (last_sw_dec_idx < hw_dec_idx)
7374 new_pos = last_sw_dec_idx + 1;
7375 rm_pos = hw_dec_idx;
7380 /* change position - insert H/W decoder according to the new position */
7381 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7383 LOGW("failed to get factory object");
7386 new_factories = g_value_array_copy(factories);
7387 g_value_init (&val, G_TYPE_OBJECT);
7388 g_value_set_object (&val, factory);
7389 g_value_array_insert(new_factories, new_pos, &val);
7390 g_value_unset (&val);
7391 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7393 for (int i = 0 ; i < new_factories->n_values ; i++) {
7394 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7396 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7397 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7399 LOGE("[Re-arranged] failed to get factory object");
7402 return new_factories;
7406 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7407 GstCaps *caps, GstElementFactory *factory, gpointer data)
7409 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7410 mmplayer_t *player = (mmplayer_t *)data;
7412 gchar *factory_name = NULL;
7413 gchar *caps_str = NULL;
7414 const gchar *klass = NULL;
7417 factory_name = GST_OBJECT_NAME(factory);
7418 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7419 caps_str = gst_caps_to_string(caps);
7421 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7423 /* store type string */
7424 if (player->type == NULL) {
7425 player->type = gst_caps_to_string(caps);
7426 __mmplayer_update_content_type_info(player);
7429 /* filtering exclude keyword */
7430 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7431 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7432 LOGW("skipping [%s] by exclude keyword [%s]",
7433 factory_name, player->ini.exclude_element_keyword[idx]);
7435 result = GST_AUTOPLUG_SELECT_SKIP;
7440 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7441 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7442 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7443 factory_name, player->ini.unsupported_codec_keyword[idx]);
7444 result = GST_AUTOPLUG_SELECT_SKIP;
7449 /* exclude webm format */
7450 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7451 * because webm format is not supportable.
7452 * If webm is disabled in "autoplug-continue", there is no state change
7453 * failure or error because the decodebin will expose the pad directly.
7454 * It make MSL invoke _prepare_async_callback.
7455 * So, we need to disable webm format in "autoplug-select" */
7456 if (caps_str && strstr(caps_str, "webm")) {
7457 LOGW("webm is not supported");
7458 result = GST_AUTOPLUG_SELECT_SKIP;
7462 /* check factory class for filtering */
7463 /* NOTE : msl don't need to use image plugins.
7464 * So, those plugins should be skipped for error handling.
7466 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7467 LOGD("skipping [%s] by not required", factory_name);
7468 result = GST_AUTOPLUG_SELECT_SKIP;
7472 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7473 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7474 // TO CHECK : subtitle if needed, add subparse exception.
7475 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7476 result = GST_AUTOPLUG_SELECT_SKIP;
7480 if (g_strrstr(factory_name, "mpegpsdemux")) {
7481 LOGD("skipping PS container - not support");
7482 result = GST_AUTOPLUG_SELECT_SKIP;
7486 if (g_strrstr(factory_name, "mssdemux"))
7487 player->smooth_streaming = TRUE;
7489 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7490 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7493 GstStructure *str = NULL;
7494 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7496 /* don't make video because of not required */
7497 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7498 (!player->set_mode.video_export)) {
7499 LOGD("no need video decoding, expose pad");
7500 result = GST_AUTOPLUG_SELECT_EXPOSE;
7504 /* get w/h for omx state-tune */
7505 /* FIXME: deprecated? */
7506 str = gst_caps_get_structure(caps, 0);
7507 gst_structure_get_int(str, "width", &width);
7510 if (player->v_stream_caps) {
7511 gst_caps_unref(player->v_stream_caps);
7512 player->v_stream_caps = NULL;
7515 player->v_stream_caps = gst_caps_copy(caps);
7516 LOGD("take caps for video state tune");
7517 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7521 if (g_strrstr(klass, "Codec/Decoder")) {
7522 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7523 if (result != GST_AUTOPLUG_SELECT_TRY) {
7524 LOGW("skip add decoder");
7530 MMPLAYER_FREEIF(caps_str);
7536 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7539 int ret = MM_ERROR_NONE;
7540 mmplayer_t *player = (mmplayer_t *)data;
7541 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7542 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7543 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7546 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7548 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7550 if (MMPLAYER_USE_DECODEBIN(player))
7553 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7556 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7558 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7559 LOGE("failed to remove videobin");
7562 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7563 LOGE("failed to remove video concat");
7566 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL, FALSE, timeout);
7567 if (ret != MM_ERROR_NONE) {
7568 LOGE("fail to change state to NULL");
7572 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst, GST_STATE_NULL, FALSE, timeout);
7573 if (ret != MM_ERROR_NONE) {
7574 LOGE("fail to change state to NULL");
7578 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7579 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7580 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7582 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7583 MMPLAYER_FREEIF(player->pipeline->videobin);
7585 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7586 if (ret != MM_ERROR_NONE)
7587 LOGE("failed to release overlay resources");
7589 player->videodec_linked = 0;
7591 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7596 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7598 mmplayer_t *player = (mmplayer_t *)data;
7601 MMPLAYER_RETURN_IF_FAIL(player);
7603 LOGD("got about to finish signal");
7605 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7606 LOGW("Fail to get cmd lock");
7610 if (!__mmplayer_verify_gapless_play_path(player)) {
7611 LOGD("decoding is finished.");
7612 MMPLAYER_CMD_UNLOCK(player);
7616 _mmplayer_set_reconfigure_state(player, TRUE);
7617 MMPLAYER_CMD_UNLOCK(player);
7619 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7620 __mmplayer_deactivate_old_path(player);
7626 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7628 mmplayer_t *player = (mmplayer_t *)data;
7629 GstIterator *iter = NULL;
7630 GValue item = { 0, };
7632 gboolean done = FALSE;
7633 gboolean is_all_drained = TRUE;
7636 MMPLAYER_RETURN_IF_FAIL(player);
7638 LOGD("got drained signal");
7640 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7641 LOGW("Fail to get cmd lock");
7645 if (!__mmplayer_verify_gapless_play_path(player)) {
7646 LOGD("decoding is finished.");
7647 MMPLAYER_CMD_UNLOCK(player);
7651 _mmplayer_set_reconfigure_state(player, TRUE);
7652 MMPLAYER_CMD_UNLOCK(player);
7654 /* check decodebin src pads whether they received EOS or not */
7655 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7658 switch (gst_iterator_next(iter, &item)) {
7659 case GST_ITERATOR_OK:
7660 pad = g_value_get_object(&item);
7661 if (pad && !GST_PAD_IS_EOS(pad)) {
7662 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7663 is_all_drained = FALSE;
7666 g_value_reset(&item);
7668 case GST_ITERATOR_RESYNC:
7669 gst_iterator_resync(iter);
7671 case GST_ITERATOR_ERROR:
7672 case GST_ITERATOR_DONE:
7677 g_value_unset(&item);
7678 gst_iterator_free(iter);
7680 if (!is_all_drained) {
7681 LOGD("Wait util the all pads get EOS.");
7686 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7687 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7689 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7690 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7691 __mmplayer_deactivate_old_path(player);
7697 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7699 mmplayer_t *player = (mmplayer_t *)data;
7700 const gchar *klass = NULL;
7701 gchar *factory_name = NULL;
7703 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7704 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7706 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7708 if (__mmplayer_add_dump_buffer_probe(player, element))
7709 LOGD("add buffer probe");
7711 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7712 gchar *selected = NULL;
7713 selected = g_strdup(GST_ELEMENT_NAME(element));
7714 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7716 /* update codec info */
7717 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7718 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7719 player->audiodec_linked = 1;
7720 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7721 /* update codec info */
7722 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7723 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7724 player->videodec_linked = 1;
7727 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7728 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7729 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7731 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7732 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7734 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7735 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7736 "max-video-width", player->adaptive_info.limit.width,
7737 "max-video-height", player->adaptive_info.limit.height, NULL);
7739 } else if (g_strrstr(klass, "Demuxer")) {
7741 LOGD("plugged element is demuxer. take it");
7743 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7744 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7745 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7746 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7747 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7750 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7751 int surface_type = 0;
7753 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7756 // to support trust-zone only
7757 if (g_strrstr(factory_name, "asfdemux")) {
7758 LOGD("set file-location %s", player->profile.uri);
7759 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7760 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7761 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7762 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7763 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7764 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7765 (__mmplayer_is_only_mp3_type(player->type))) {
7766 LOGD("[mpegaudioparse] set streaming pull mode.");
7767 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7769 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7770 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7771 } else if (g_strrstr(factory_name, "omxdec_h264")) {
7772 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7773 if (video_parse && (g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7774 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7775 LOGD("Send SPS and PPS Insertion every IDR frame");
7779 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7780 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7781 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7783 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7784 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7786 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7787 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7788 (MMPLAYER_IS_DASH_STREAMING(player))) {
7789 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7790 _mm_player_streaming_set_multiqueue(player->streamer, element);
7791 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7800 __mmplayer_release_misc(mmplayer_t *player)
7803 bool cur_mode = player->set_mode.rich_audio;
7806 MMPLAYER_RETURN_IF_FAIL(player);
7808 player->sent_bos = FALSE;
7809 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7811 player->seek_state = MMPLAYER_SEEK_NONE;
7813 player->total_bitrate = 0;
7814 player->total_maximum_bitrate = 0;
7816 player->not_found_demuxer = 0;
7818 player->last_position = 0;
7819 player->duration = 0;
7820 player->http_content_size = 0;
7821 player->not_supported_codec = MISSING_PLUGIN_NONE;
7822 player->can_support_codec = FOUND_PLUGIN_NONE;
7823 player->pending_seek.is_pending = false;
7824 player->pending_seek.pos = 0;
7825 player->msg_posted = FALSE;
7826 player->has_many_types = FALSE;
7827 player->is_subtitle_force_drop = FALSE;
7828 player->play_subtitle = FALSE;
7829 player->adjust_subtitle_pos = 0;
7830 player->has_closed_caption = FALSE;
7831 player->set_mode.video_export = false;
7832 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7833 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7835 player->set_mode.rich_audio = cur_mode;
7837 if (player->audio_device_cb_id > 0 &&
7838 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7839 LOGW("failed to remove audio device_connected_callback");
7840 player->audio_device_cb_id = 0;
7842 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7843 player->bitrate[i] = 0;
7844 player->maximum_bitrate[i] = 0;
7847 /* free memory related to audio effect */
7848 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7850 if (player->adaptive_info.var_list) {
7851 g_list_free_full(player->adaptive_info.var_list, g_free);
7852 player->adaptive_info.var_list = NULL;
7855 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7856 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7857 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7859 /* Reset video360 settings to their defaults in case if the pipeline is to be
7862 player->video360_metadata.is_spherical = -1;
7863 player->is_openal_plugin_used = FALSE;
7865 player->is_content_spherical = FALSE;
7866 player->is_video360_enabled = TRUE;
7867 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7868 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7869 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7870 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7871 player->video360_zoom = 1.0f;
7872 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7873 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7875 player->sound.rg_enable = false;
7877 __mmplayer_initialize_video_roi(player);
7882 __mmplayer_release_misc_post(mmplayer_t *player)
7884 gchar *original_uri = NULL;
7887 /* player->pipeline is already released before. */
7888 MMPLAYER_RETURN_IF_FAIL(player);
7890 player->video_decoded_cb = NULL;
7891 player->video_decoded_cb_user_param = NULL;
7892 player->video_stream_prerolled = false;
7894 player->audio_decoded_cb = NULL;
7895 player->audio_decoded_cb_user_param = NULL;
7896 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7898 player->audio_stream_changed_cb = NULL;
7899 player->audio_stream_changed_cb_user_param = NULL;
7901 mm_player_set_attribute((MMHandleType)player, NULL,
7902 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7904 /* clean found audio decoders */
7905 if (player->audio_decoders) {
7906 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7907 player->audio_decoders = NULL;
7910 /* clean the uri list except original uri */
7911 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7913 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7914 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7915 g_list_free_full(tmp, (GDestroyNotify)g_free);
7918 LOGW("failed to get original uri info");
7920 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7921 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7922 MMPLAYER_FREEIF(original_uri);
7925 /* clear the audio stream buffer list */
7926 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7928 /* clear the video stream bo list */
7929 __mmplayer_video_stream_destroy_bo_list(player);
7930 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7932 if (player->profile.input_mem.buf) {
7933 free(player->profile.input_mem.buf);
7934 player->profile.input_mem.buf = NULL;
7936 player->profile.input_mem.len = 0;
7937 player->profile.input_mem.offset = 0;
7939 player->uri_info.uri_idx = 0;
7944 __mmplayer_check_subtitle(mmplayer_t *player)
7946 MMHandleType attrs = 0;
7947 char *subtitle_uri = NULL;
7951 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7953 /* get subtitle attribute */
7954 attrs = MMPLAYER_GET_ATTRS(player);
7958 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7959 if (!subtitle_uri || !strlen(subtitle_uri))
7962 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7963 player->is_external_subtitle_present = TRUE;
7971 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7973 MMPLAYER_RETURN_IF_FAIL(player);
7975 if (player->eos_timer) {
7976 LOGD("cancel eos timer");
7977 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7978 player->eos_timer = 0;
7985 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7989 MMPLAYER_RETURN_IF_FAIL(player);
7990 MMPLAYER_RETURN_IF_FAIL(sink);
7993 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7995 player->sink_elements = g_list_append(player->sink_elements, sink);
8001 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8005 MMPLAYER_RETURN_IF_FAIL(player);
8006 MMPLAYER_RETURN_IF_FAIL(sink);
8008 player->sink_elements = g_list_remove(player->sink_elements, sink);
8014 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8015 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8017 mmplayer_signal_item_t *item = NULL;
8020 MMPLAYER_RETURN_IF_FAIL(player);
8022 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8023 LOGE("invalid signal type [%d]", type);
8027 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8029 LOGE("cannot connect signal [%s]", signal);
8034 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8035 player->signals[type] = g_list_append(player->signals[type], item);
8041 /* NOTE : be careful with calling this api. please refer to below glib comment
8042 * glib comment : Note that there is a bug in GObject that makes this function much
8043 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8044 * will no longer be called, but, the signal handler is not currently disconnected.
8045 * If the instance is itself being freed at the same time than this doesn't matter,
8046 * since the signal will automatically be removed, but if instance persists,
8047 * then the signal handler will leak. You should not remove the signal yourself
8048 * because in a future versions of GObject, the handler will automatically be
8051 * It's possible to work around this problem in a way that will continue to work
8052 * with future versions of GObject by checking that the signal handler is still
8053 * connected before disconnected it:
8055 * if (g_signal_handler_is_connected(instance, id))
8056 * g_signal_handler_disconnect(instance, id);
8059 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8061 GList *sig_list = NULL;
8062 mmplayer_signal_item_t *item = NULL;
8066 MMPLAYER_RETURN_IF_FAIL(player);
8068 LOGD("release signals type : %d", type);
8070 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8071 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8072 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8073 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8074 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8075 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8079 sig_list = player->signals[type];
8081 for (; sig_list; sig_list = sig_list->next) {
8082 item = sig_list->data;
8084 if (item && item->obj) {
8085 if (g_signal_handler_is_connected(item->obj, item->sig))
8086 g_signal_handler_disconnect(item->obj, item->sig);
8089 MMPLAYER_FREEIF(item);
8092 g_list_free(player->signals[type]);
8093 player->signals[type] = NULL;
8101 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8103 mmplayer_t *player = 0;
8104 int prev_display_surface_type = 0;
8108 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8110 player = MM_PLAYER_CAST(handle);
8112 /* check video sinkbin is created */
8113 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8114 LOGW("Videosink is already created");
8115 return MM_ERROR_NONE;
8118 LOGD("videosink element is not yet ready");
8120 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8121 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8123 return MM_ERROR_INVALID_ARGUMENT;
8126 /* load previous attributes */
8127 if (player->attrs) {
8128 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8129 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8130 if (prev_display_surface_type == surface_type) {
8131 LOGD("incoming display surface type is same as previous one, do nothing..");
8133 return MM_ERROR_NONE;
8136 LOGE("failed to load attributes");
8138 return MM_ERROR_PLAYER_INTERNAL;
8141 /* videobin is not created yet, so we just set attributes related to display surface */
8142 LOGD("store display attribute for given surface type(%d)", surface_type);
8143 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8144 "display_overlay", wl_surface_id, NULL);
8147 return MM_ERROR_NONE;
8150 /* Note : if silent is true, then subtitle would not be displayed. :*/
8152 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8154 mmplayer_t *player = (mmplayer_t *)hplayer;
8158 /* check player handle */
8159 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8161 player->set_mode.subtitle_off = silent;
8163 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8167 return MM_ERROR_NONE;
8171 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8173 mmplayer_gst_element_t *mainbin = NULL;
8174 mmplayer_gst_element_t *textbin = NULL;
8175 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8176 GstState current_state = GST_STATE_VOID_PENDING;
8177 GstState element_state = GST_STATE_VOID_PENDING;
8178 GstState element_pending_state = GST_STATE_VOID_PENDING;
8180 GstEvent *event = NULL;
8181 int result = MM_ERROR_NONE;
8183 GstClock *curr_clock = NULL;
8184 GstClockTime base_time, start_time, curr_time;
8189 /* check player handle */
8190 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8192 player->pipeline->mainbin &&
8193 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8195 mainbin = player->pipeline->mainbin;
8196 textbin = player->pipeline->textbin;
8198 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8200 // sync clock with current pipeline
8201 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8202 curr_time = gst_clock_get_time(curr_clock);
8204 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8205 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8207 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8208 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8210 if (current_state > GST_STATE_READY) {
8211 // sync state with current pipeline
8212 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8213 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8214 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8216 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8217 if (GST_STATE_CHANGE_FAILURE == ret) {
8218 LOGE("fail to state change.");
8219 result = MM_ERROR_PLAYER_INTERNAL;
8223 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8224 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8227 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8228 gst_object_unref(curr_clock);
8231 // seek to current position
8232 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8233 result = MM_ERROR_PLAYER_INVALID_STATE;
8234 LOGE("gst_element_query_position failed, invalid state");
8238 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8239 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);
8241 _mmplayer_gst_send_event_to_sink(player, event);
8243 result = MM_ERROR_PLAYER_INTERNAL;
8244 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8248 /* sync state with current pipeline */
8249 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8250 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8251 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8253 return MM_ERROR_NONE;
8256 /* release text pipeline resource */
8257 player->textsink_linked = 0;
8259 /* release signal */
8260 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8262 /* release textbin with it's children */
8263 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8264 MMPLAYER_FREEIF(player->pipeline->textbin);
8265 player->pipeline->textbin = NULL;
8267 /* release subtitle elem */
8268 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8269 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8275 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8277 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8278 GstState current_state = GST_STATE_VOID_PENDING;
8280 MMHandleType attrs = 0;
8281 mmplayer_gst_element_t *mainbin = NULL;
8282 mmplayer_gst_element_t *textbin = NULL;
8284 gchar *subtitle_uri = NULL;
8285 int result = MM_ERROR_NONE;
8286 const gchar *charset = NULL;
8290 /* check player handle */
8291 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8293 player->pipeline->mainbin &&
8294 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8295 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8297 mainbin = player->pipeline->mainbin;
8298 textbin = player->pipeline->textbin;
8300 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8301 if (current_state < GST_STATE_READY) {
8302 result = MM_ERROR_PLAYER_INVALID_STATE;
8303 LOGE("Pipeline is not in proper state");
8307 attrs = MMPLAYER_GET_ATTRS(player);
8309 LOGE("cannot get content attribute");
8310 result = MM_ERROR_PLAYER_INTERNAL;
8314 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8315 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8316 LOGE("subtitle uri is not proper filepath");
8317 result = MM_ERROR_PLAYER_INVALID_URI;
8321 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8322 LOGE("failed to get storage info of subtitle path");
8323 result = MM_ERROR_PLAYER_INVALID_URI;
8327 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8328 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8330 if (!strcmp(filepath, subtitle_uri)) {
8331 LOGD("subtitle path is not changed");
8334 if (mm_player_set_attribute((MMHandleType)player, NULL,
8335 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8336 LOGE("failed to set attribute");
8341 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8342 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8343 player->subtitle_language_list = NULL;
8344 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8346 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8347 if (ret != GST_STATE_CHANGE_SUCCESS) {
8348 LOGE("failed to change state of textbin to READY");
8349 result = MM_ERROR_PLAYER_INTERNAL;
8353 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8354 if (ret != GST_STATE_CHANGE_SUCCESS) {
8355 LOGE("failed to change state of subparse to READY");
8356 result = MM_ERROR_PLAYER_INTERNAL;
8360 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8361 if (ret != GST_STATE_CHANGE_SUCCESS) {
8362 LOGE("failed to change state of filesrc to READY");
8363 result = MM_ERROR_PLAYER_INTERNAL;
8367 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8369 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8371 charset = _mmplayer_get_charset(filepath);
8373 LOGD("detected charset is %s", charset);
8374 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8377 result = _mmplayer_sync_subtitle_pipeline(player);
8384 /* API to switch between external subtitles */
8386 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8388 int result = MM_ERROR_NONE;
8389 mmplayer_t *player = (mmplayer_t *)hplayer;
8394 /* check player handle */
8395 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8397 /* filepath can be null in idle state */
8399 /* check file path */
8400 if ((path = strstr(filepath, "file://")))
8401 result = _mmplayer_exist_file_path(path + 7);
8403 result = _mmplayer_exist_file_path(filepath);
8405 if (result != MM_ERROR_NONE) {
8406 LOGE("invalid subtitle path 0x%X", result);
8407 return result; /* file not found or permission denied */
8411 if (!player->pipeline) {
8413 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8414 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8415 LOGE("failed to set attribute");
8416 return MM_ERROR_PLAYER_INTERNAL;
8419 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8420 /* check filepath */
8421 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8423 if (!__mmplayer_check_subtitle(player)) {
8424 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8425 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8426 LOGE("failed to set attribute");
8427 return MM_ERROR_PLAYER_INTERNAL;
8430 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8431 LOGE("fail to create text pipeline");
8432 return MM_ERROR_PLAYER_INTERNAL;
8435 result = _mmplayer_sync_subtitle_pipeline(player);
8437 result = __mmplayer_change_external_subtitle_language(player, filepath);
8440 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8441 player->is_external_subtitle_added_now = TRUE;
8443 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8444 if (!player->subtitle_language_list) {
8445 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8446 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8447 LOGW("subtitle language list is not updated yet");
8449 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8457 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8459 guint active_idx = 0;
8460 GstStream *stream = NULL;
8461 GList *streams = NULL;
8462 GstCaps *caps = NULL;
8465 LOGD("Switching Streams... type: %d, index: %d", type, index);
8467 player->track[type].active_track_index = index;
8469 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8470 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8471 LOGD("track type:%d, total: %d, active: %d", i,
8472 player->track[i].total_track_num, player->track[i].active_track_index);
8473 if (player->track[i].total_track_num > 0 &&
8474 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8475 active_idx = player->track[i].active_track_index;
8476 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8477 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8478 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8480 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8481 caps = gst_stream_get_caps(stream);
8483 _mmplayer_set_audio_attrs(player, caps);
8484 gst_caps_unref(caps);
8491 LOGD("send select stream event");
8492 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8493 gst_event_new_select_streams(streams));
8494 g_list_free(streams);
8498 return MM_ERROR_NONE;
8502 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8504 int result = MM_ERROR_NONE;
8505 gchar *change_pad_name = NULL;
8506 GstPad *sinkpad = NULL;
8507 mmplayer_gst_element_t *mainbin = NULL;
8508 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8509 GstCaps *caps = NULL;
8510 gint total_track_num = 0;
8514 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8515 MM_ERROR_PLAYER_NOT_INITIALIZED);
8517 LOGD("Change Track(%d) to %d", type, index);
8519 mainbin = player->pipeline->mainbin;
8521 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8522 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8523 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8524 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8526 /* Changing Video Track is not supported. */
8527 LOGE("Track Type Error");
8531 if (mainbin[elem_idx].gst == NULL) {
8532 result = MM_ERROR_PLAYER_NO_OP;
8533 LOGD("Req track doesn't exist");
8537 total_track_num = player->track[type].total_track_num;
8538 if (total_track_num <= 0) {
8539 result = MM_ERROR_PLAYER_NO_OP;
8540 LOGD("Language list is not available");
8544 if ((index < 0) || (index >= total_track_num)) {
8545 result = MM_ERROR_INVALID_ARGUMENT;
8546 LOGD("Not a proper index : %d", index);
8550 /*To get the new pad from the selector*/
8551 change_pad_name = g_strdup_printf("sink_%u", index);
8552 if (change_pad_name == NULL) {
8553 result = MM_ERROR_PLAYER_INTERNAL;
8554 LOGD("Pad does not exists");
8558 LOGD("new active pad name: %s", change_pad_name);
8560 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8561 if (sinkpad == NULL) {
8562 LOGD("sinkpad is NULL");
8563 result = MM_ERROR_PLAYER_INTERNAL;
8567 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8568 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8570 caps = gst_pad_get_current_caps(sinkpad);
8571 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8574 gst_object_unref(sinkpad);
8576 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8577 _mmplayer_set_audio_attrs(player, caps);
8580 gst_caps_unref(caps);
8583 MMPLAYER_FREEIF(change_pad_name);
8588 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8590 int result = MM_ERROR_NONE;
8591 mmplayer_t *player = NULL;
8592 mmplayer_gst_element_t *mainbin = NULL;
8594 gint current_active_index = 0;
8596 GstState current_state = GST_STATE_VOID_PENDING;
8601 player = (mmplayer_t *)hplayer;
8602 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8604 if (!player->pipeline) {
8605 LOGE("Track %d pre setting -> %d", type, index);
8607 player->track[type].active_track_index = index;
8611 mainbin = player->pipeline->mainbin;
8613 current_active_index = player->track[type].active_track_index;
8615 /*If index is same as running index no need to change the pad*/
8616 if (current_active_index == index)
8619 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8620 result = MM_ERROR_PLAYER_INVALID_STATE;
8624 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8625 if (current_state < GST_STATE_PAUSED) {
8626 result = MM_ERROR_PLAYER_INVALID_STATE;
8627 LOGW("Pipeline not in proper state");
8631 if (MMPLAYER_USE_DECODEBIN(player))
8632 result = __mmplayer_change_selector_pad(player, type, index);
8634 result = __mmplayer_switch_stream(player, type, index);
8636 if (result != MM_ERROR_NONE) {
8637 LOGE("failed to change track");
8641 player->track[type].active_track_index = index;
8643 if (MMPLAYER_USE_DECODEBIN(player)) {
8644 GstEvent *event = NULL;
8645 if (current_state == GST_STATE_PLAYING) {
8646 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8647 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8648 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8650 _mmplayer_gst_send_event_to_sink(player, event);
8652 result = MM_ERROR_PLAYER_INTERNAL;
8663 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8665 mmplayer_t *player = (mmplayer_t *)hplayer;
8669 /* check player handle */
8670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8672 *silent = player->set_mode.subtitle_off;
8674 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8678 return MM_ERROR_NONE;
8682 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8684 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8685 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8687 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8688 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8692 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8693 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8694 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8695 mmplayer_dump_t *dump_s;
8696 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8697 if (dump_s == NULL) {
8698 LOGE("malloc fail");
8702 dump_s->dump_element_file = NULL;
8703 dump_s->dump_pad = NULL;
8704 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8706 if (dump_s->dump_pad) {
8707 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8708 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]);
8709 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8710 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);
8711 /* add list for removed buffer probe and close FILE */
8712 player->dump_list = g_list_append(player->dump_list, dump_s);
8713 LOGD("%s sink pad added buffer probe for dump", factory_name);
8716 MMPLAYER_FREEIF(dump_s);
8717 LOGE("failed to get %s sink pad added", factory_name);
8724 static GstPadProbeReturn
8725 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8727 FILE *dump_data = (FILE *)u_data;
8729 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8730 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8732 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8734 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8736 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8738 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8740 gst_buffer_unmap(buffer, &probe_info);
8742 return GST_PAD_PROBE_OK;
8746 __mmplayer_release_dump_list(GList *dump_list)
8748 GList *d_list = dump_list;
8753 for (; d_list; d_list = g_list_next(d_list)) {
8754 mmplayer_dump_t *dump_s = d_list->data;
8755 if (dump_s->dump_pad) {
8756 if (dump_s->probe_handle_id)
8757 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8758 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8760 if (dump_s->dump_element_file) {
8761 fclose(dump_s->dump_element_file);
8762 dump_s->dump_element_file = NULL;
8764 MMPLAYER_FREEIF(dump_s);
8766 g_list_free(dump_list);
8771 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8773 mmplayer_t *player = (mmplayer_t *)hplayer;
8777 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8778 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8780 *exist = (bool)player->has_closed_caption;
8784 return MM_ERROR_NONE;
8788 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8793 LOGD("unref internal gst buffer %p", buffer);
8795 gst_buffer_unref((GstBuffer *)buffer);
8802 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8804 mmplayer_t *player = (mmplayer_t *)hplayer;
8808 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8809 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8811 if (MMPLAYER_IS_STREAMING(player))
8812 *timeout = (int)player->ini.live_state_change_timeout;
8814 *timeout = (int)player->ini.localplayback_state_change_timeout;
8816 LOGD("timeout = %d", *timeout);
8819 return MM_ERROR_NONE;
8823 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8827 MMPLAYER_RETURN_IF_FAIL(player);
8829 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8831 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8832 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8833 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8834 player->storage_info[i].id = -1;
8835 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8837 if (path_type != MMPLAYER_PATH_MAX)
8846 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8848 int ret = MM_ERROR_NONE;
8849 mmplayer_t *player = (mmplayer_t *)hplayer;
8850 MMMessageParamType msg_param = {0, };
8853 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8855 LOGW("state changed storage %d:%d", id, state);
8857 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8858 return MM_ERROR_NONE;
8860 /* FIXME: text path should be handled separately. */
8861 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8862 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8863 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8864 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8865 LOGW("external storage is removed");
8867 if (player->msg_posted == FALSE) {
8868 memset(&msg_param, 0, sizeof(MMMessageParamType));
8869 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8870 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8871 player->msg_posted = TRUE;
8874 /* unrealize the player */
8875 ret = _mmplayer_unrealize(hplayer);
8876 if (ret != MM_ERROR_NONE)
8877 LOGE("failed to unrealize");
8885 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8887 int ret = MM_ERROR_NONE;
8888 mmplayer_t *player = (mmplayer_t *)hplayer;
8889 int idx = 0, total = 0;
8890 gchar *result = NULL, *tmp = NULL;
8893 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8894 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8896 total = *num = g_list_length(player->adaptive_info.var_list);
8898 LOGW("There is no stream variant info.");
8902 result = g_strdup("");
8903 for (idx = 0 ; idx < total ; idx++) {
8904 stream_variant_t *v_data = NULL;
8905 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8908 gchar data[64] = {0};
8909 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8911 tmp = g_strconcat(result, data, NULL);
8915 LOGW("There is no variant data in %d", idx);
8920 *var_info = (char *)result;
8922 LOGD("variant info %d:%s", *num, *var_info);
8928 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8930 int ret = MM_ERROR_NONE;
8931 mmplayer_t *player = (mmplayer_t *)hplayer;
8934 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8936 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8938 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8939 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8940 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8942 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8943 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8944 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8945 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8947 /* FIXME: seek to current position for applying new variant limitation */
8956 _mmplayer_get_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);
8963 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8965 *bandwidth = player->adaptive_info.limit.bandwidth;
8966 *width = player->adaptive_info.limit.width;
8967 *height = player->adaptive_info.limit.height;
8969 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8976 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8978 int ret = MM_ERROR_NONE;
8979 mmplayer_t *player = (mmplayer_t *)hplayer;
8982 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8983 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8984 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8986 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8988 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8989 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8990 else /* live case */
8991 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8993 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9000 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9002 #define IDX_FIRST_SW_CODEC 0
9003 mmplayer_t *player = (mmplayer_t *)hplayer;
9004 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9005 const char *attr_name = NULL;
9006 const char *default_type = NULL;
9007 const char *element_hw = NULL;
9008 const char *element_sw = NULL;
9011 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9013 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9015 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9016 switch (stream_type) {
9017 case MM_PLAYER_STREAM_TYPE_AUDIO:
9018 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9019 default_type = player->ini.audiocodec_default_type;
9020 element_hw = player->ini.audiocodec_element_hw;
9021 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9023 case MM_PLAYER_STREAM_TYPE_VIDEO:
9024 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9025 default_type = player->ini.videocodec_default_type;
9026 element_hw = player->ini.videocodec_element_hw;
9027 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9030 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9031 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9035 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9037 if (!strcmp(default_type, "sw"))
9038 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9040 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9042 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9043 codec_type = default_codec_type;
9045 /* to support codec selection, codec info have to be added in ini file.
9046 in case of hw codec is selected, filter elements should be applied
9047 depending on the hw capabilities. */
9048 if (codec_type != default_codec_type) {
9049 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9050 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9051 LOGE("There is no codec for type %d", codec_type);
9052 return MM_ERROR_PLAYER_NO_OP;
9055 LOGD("sorting is required");
9056 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9057 player->need_audio_dec_sorting = TRUE;
9059 player->need_video_dec_sorting = TRUE;
9062 LOGD("update %s codec_type to %d", attr_name, codec_type);
9063 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9066 return MM_ERROR_NONE;
9070 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9072 mmplayer_t *player = (mmplayer_t *)hplayer;
9073 GstElement *rg_vol_element = NULL;
9077 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9079 player->sound.rg_enable = enabled;
9081 /* just hold rgvolume enable value if pipeline is not ready */
9082 if (!player->pipeline || !player->pipeline->audiobin) {
9083 LOGD("pipeline is not ready. holding rgvolume enable value");
9084 return MM_ERROR_NONE;
9087 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9089 if (!rg_vol_element) {
9090 LOGD("rgvolume element is not created");
9091 return MM_ERROR_PLAYER_INTERNAL;
9095 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9097 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9101 return MM_ERROR_NONE;
9105 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9107 mmplayer_t *player = (mmplayer_t *)hplayer;
9108 GstElement *rg_vol_element = NULL;
9109 gboolean enable = FALSE;
9113 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9114 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9116 /* just hold enable_rg value if pipeline is not ready */
9117 if (!player->pipeline || !player->pipeline->audiobin) {
9118 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9119 *enabled = player->sound.rg_enable;
9120 return MM_ERROR_NONE;
9123 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9125 if (!rg_vol_element) {
9126 LOGD("rgvolume element is not created");
9127 return MM_ERROR_PLAYER_INTERNAL;
9130 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9131 *enabled = (bool)enable;
9135 return MM_ERROR_NONE;
9139 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9141 mmplayer_t *player = (mmplayer_t *)hplayer;
9142 MMHandleType attrs = 0;
9144 int ret = MM_ERROR_NONE;
9148 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9150 attrs = MMPLAYER_GET_ATTRS(player);
9151 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9153 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9155 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9156 return MM_ERROR_PLAYER_INTERNAL;
9159 player->video_roi.scale_x = scale_x;
9160 player->video_roi.scale_y = scale_y;
9161 player->video_roi.scale_width = scale_width;
9162 player->video_roi.scale_height = scale_height;
9164 /* check video sinkbin is created */
9165 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9166 return MM_ERROR_NONE;
9168 if (!gst_video_overlay_set_video_roi_area(
9169 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9170 scale_x, scale_y, scale_width, scale_height))
9171 ret = MM_ERROR_PLAYER_INTERNAL;
9173 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9174 scale_x, scale_y, scale_width, scale_height);
9182 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9184 mmplayer_t *player = (mmplayer_t *)hplayer;
9185 int ret = MM_ERROR_NONE;
9189 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9190 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9192 *scale_x = player->video_roi.scale_x;
9193 *scale_y = player->video_roi.scale_y;
9194 *scale_width = player->video_roi.scale_width;
9195 *scale_height = player->video_roi.scale_height;
9197 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9198 *scale_x, *scale_y, *scale_width, *scale_height);
9204 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9206 mmplayer_t *player = (mmplayer_t *)hplayer;
9210 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9212 player->client_pid = pid;
9214 LOGD("client pid[%d] %p", pid, player);
9218 return MM_ERROR_NONE;
9222 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9224 mmplayer_t *player = (mmplayer_t *)hplayer;
9225 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9226 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9230 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9231 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9234 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9236 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9238 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9239 return MM_ERROR_NONE;
9241 /* in case of audio codec default type is HW */
9243 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9244 if (player->ini.support_audio_effect)
9245 return MM_ERROR_NONE;
9246 elem_id = MMPLAYER_A_FILTER;
9248 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9249 if (player->ini.support_replaygain_control)
9250 return MM_ERROR_NONE;
9251 elem_id = MMPLAYER_A_RGVOL;
9253 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9254 if (player->ini.support_pitch_control)
9255 return MM_ERROR_NONE;
9256 elem_id = MMPLAYER_A_PITCH;
9258 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9259 if (player->ini.support_audio_effect)
9260 return MM_ERROR_NONE;
9262 /* default case handling is not required */
9265 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9266 LOGW("audio control option [%d] is not available", opt);
9269 /* setting pcm exporting option is allowed before READY state */
9270 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9271 return MM_ERROR_PLAYER_INVALID_STATE;
9273 /* check whether the audio filter exist or not after READY state,
9274 because the sw codec could be added during auto-plugging in some cases */
9275 if (!player->pipeline ||
9276 !player->pipeline->audiobin ||
9277 !player->pipeline->audiobin[elem_id].gst) {
9278 LOGW("there is no audio elem [%d]", elem_id);
9283 LOGD("audio control opt %d, available %d", opt, *available);
9287 return MM_ERROR_NONE;
9291 __mmplayer_update_duration_value(mmplayer_t *player)
9293 gboolean ret = FALSE;
9294 gint64 dur_nsec = 0;
9295 LOGD("try to update duration");
9297 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9298 player->duration = dur_nsec;
9299 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9303 if (player->duration < 0) {
9304 LOGW("duration is Non-Initialized !!!");
9305 player->duration = 0;
9308 /* update streaming service type */
9309 player->streaming_type = _mmplayer_get_stream_service_type(player);
9311 /* check duration is OK */
9312 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9313 /* FIXIT : find another way to get duration here. */
9314 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9320 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9322 /* update audio params
9323 NOTE : We need original audio params and it can be only obtained from src pad of audio
9324 decoder. Below code only valid when we are not using 'resampler' just before
9325 'audioconverter'. */
9326 GstCaps *caps_a = NULL;
9328 gint samplerate = 0, channels = 0;
9329 GstStructure *p = NULL;
9330 GstElement *aconv = NULL;
9332 LOGD("try to update audio attrs");
9334 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9336 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9337 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9338 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9339 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9341 LOGE("there is no audio converter");
9345 pad = gst_element_get_static_pad(aconv, "sink");
9348 LOGW("failed to get pad from audio converter");
9352 caps_a = gst_pad_get_current_caps(pad);
9354 LOGW("not ready to get audio caps");
9355 gst_object_unref(pad);
9359 p = gst_caps_get_structure(caps_a, 0);
9360 gst_structure_get_int(p, "rate", &samplerate);
9361 gst_structure_get_int(p, "channels", &channels);
9363 mm_player_set_attribute((MMHandleType)player, NULL,
9364 "content_audio_samplerate", samplerate,
9365 "content_audio_channels", channels, NULL);
9367 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9369 gst_caps_unref(caps_a);
9370 gst_object_unref(pad);
9376 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9378 LOGD("try to update video attrs");
9380 GstCaps *caps_v = NULL;
9384 GstStructure *p = NULL;
9386 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9387 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9389 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9391 LOGD("no videosink sink pad");
9395 caps_v = gst_pad_get_current_caps(pad);
9396 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9397 if (!caps_v && player->v_stream_caps) {
9398 caps_v = player->v_stream_caps;
9399 gst_caps_ref(caps_v);
9403 LOGD("no negotiated caps from videosink");
9404 gst_object_unref(pad);
9408 p = gst_caps_get_structure(caps_v, 0);
9409 gst_structure_get_int(p, "width", &width);
9410 gst_structure_get_int(p, "height", &height);
9412 mm_player_set_attribute((MMHandleType)player, NULL,
9413 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9415 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9417 SECURE_LOGD("width : %d height : %d", width, height);
9419 gst_caps_unref(caps_v);
9420 gst_object_unref(pad);
9423 mm_player_set_attribute((MMHandleType)player, NULL,
9424 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9425 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9432 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9434 gboolean ret = FALSE;
9435 guint64 data_size = 0;
9439 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9440 if (!player->duration)
9443 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9444 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9445 if (stat(path, &sb) == 0)
9446 data_size = (guint64)sb.st_size;
9448 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9449 data_size = player->http_content_size;
9452 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9455 guint64 bitrate = 0;
9456 guint64 msec_dur = 0;
9458 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9460 bitrate = data_size * 8 * 1000 / msec_dur;
9461 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9462 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9463 mm_player_set_attribute((MMHandleType)player, NULL,
9464 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9467 LOGD("player duration is less than 0");
9471 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9472 if (player->total_bitrate) {
9473 mm_player_set_attribute((MMHandleType)player, NULL,
9474 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9483 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9485 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9486 data->uri_type = uri_type;
9490 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9492 int ret = MM_ERROR_PLAYER_INVALID_URI;
9494 char *buffer = NULL;
9495 char *seperator = strchr(path, ',');
9496 char ext[100] = {0,}, size[100] = {0,};
9499 if ((buffer = strstr(path, "ext="))) {
9500 buffer += strlen("ext=");
9502 if (strlen(buffer)) {
9503 strncpy(ext, buffer, 99);
9505 if ((seperator = strchr(ext, ','))
9506 || (seperator = strchr(ext, ' '))
9507 || (seperator = strchr(ext, '\0'))) {
9508 seperator[0] = '\0';
9513 if ((buffer = strstr(path, "size="))) {
9514 buffer += strlen("size=");
9516 if (strlen(buffer) > 0) {
9517 strncpy(size, buffer, 99);
9519 if ((seperator = strchr(size, ','))
9520 || (seperator = strchr(size, ' '))
9521 || (seperator = strchr(size, '\0'))) {
9522 seperator[0] = '\0';
9525 mem_size = atoi(size);
9530 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9532 if (mem_size && param) {
9533 if (data->input_mem.buf)
9534 free(data->input_mem.buf);
9535 data->input_mem.buf = malloc(mem_size);
9537 if (data->input_mem.buf) {
9538 memcpy(data->input_mem.buf, param, mem_size);
9539 data->input_mem.len = mem_size;
9540 ret = MM_ERROR_NONE;
9542 LOGE("failed to alloc mem %d", mem_size);
9543 ret = MM_ERROR_PLAYER_INTERNAL;
9546 data->input_mem.offset = 0;
9547 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9554 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9556 gchar *location = NULL;
9559 int ret = MM_ERROR_NONE;
9561 if ((path = strstr(uri, "file://"))) {
9562 location = g_filename_from_uri(uri, NULL, &err);
9563 if (!location || (err != NULL)) {
9564 LOGE("Invalid URI '%s' for filesrc: %s", path,
9565 (err != NULL) ? err->message : "unknown error");
9569 MMPLAYER_FREEIF(location);
9571 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9572 return MM_ERROR_PLAYER_INVALID_URI;
9574 LOGD("path from uri: %s", location);
9577 path = (location != NULL) ? (location) : ((char *)uri);
9580 ret = _mmplayer_exist_file_path(path);
9582 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9583 if (ret == MM_ERROR_NONE) {
9584 if (_mmplayer_is_sdp_file(path)) {
9585 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9586 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9587 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9589 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9590 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9592 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9593 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9595 LOGE("invalid uri, could not play..");
9596 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9599 MMPLAYER_FREEIF(location);
9604 static mmplayer_video_decoded_data_info_t *
9605 __mmplayer_create_stream_from_pad(GstPad *pad)
9607 GstCaps *caps = NULL;
9608 GstStructure *structure = NULL;
9609 unsigned int fourcc = 0;
9610 const gchar *string_format = NULL;
9611 mmplayer_video_decoded_data_info_t *stream = NULL;
9613 MMPixelFormatType format;
9616 caps = gst_pad_get_current_caps(pad);
9618 LOGE("Caps is NULL.");
9623 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9625 structure = gst_caps_get_structure(caps, 0);
9626 gst_structure_get_int(structure, "width", &width);
9627 gst_structure_get_int(structure, "height", &height);
9628 string_format = gst_structure_get_string(structure, "format");
9631 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9632 format = _mmplayer_get_pixtype(fourcc);
9633 gst_video_info_from_caps(&info, caps);
9634 gst_caps_unref(caps);
9637 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9638 LOGE("Wrong condition!!");
9642 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9644 LOGE("failed to alloc mem for video data");
9648 stream->width = width;
9649 stream->height = height;
9650 stream->format = format;
9651 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9657 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9659 unsigned int pitch = 0;
9660 unsigned int size = 0;
9662 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9665 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9666 bo = gst_tizen_memory_get_bos(mem, index);
9668 stream->bo[index] = tbm_bo_ref(bo);
9670 LOGE("failed to get bo for index %d", index);
9673 for (index = 0; index < stream->plane_num; index++) {
9674 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9675 stream->stride[index] = pitch;
9677 stream->elevation[index] = size / pitch;
9679 stream->elevation[index] = stream->height;
9684 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9686 if (stream->format == MM_PIXEL_FORMAT_I420) {
9687 int ret = TBM_SURFACE_ERROR_NONE;
9688 tbm_surface_h surface;
9689 tbm_surface_info_s info;
9691 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9693 ret = tbm_surface_get_info(surface, &info);
9694 if (ret != TBM_SURFACE_ERROR_NONE) {
9695 tbm_surface_destroy(surface);
9699 tbm_surface_destroy(surface);
9700 stream->stride[0] = info.planes[0].stride;
9701 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9702 stream->stride[1] = info.planes[1].stride;
9703 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9704 stream->stride[2] = info.planes[2].stride;
9705 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9706 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9707 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9708 stream->stride[0] = stream->width * 4;
9709 stream->elevation[0] = stream->height;
9710 stream->bo_size = stream->stride[0] * stream->height;
9712 LOGE("Not support format %d", stream->format);
9720 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9722 tbm_bo_handle thandle;
9724 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9725 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9726 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9730 unsigned char *src = NULL;
9731 unsigned char *dest = NULL;
9732 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9734 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9736 LOGE("fail to gst_memory_map");
9740 if (!mapinfo.data) {
9741 LOGE("data pointer is wrong");
9745 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9746 if (!stream->bo[0]) {
9747 LOGE("Fail to tbm_bo_alloc!!");
9751 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9753 LOGE("thandle pointer is wrong");
9757 if (stream->format == MM_PIXEL_FORMAT_I420) {
9758 src_stride[0] = GST_ROUND_UP_4(stream->width);
9759 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9760 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9761 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9764 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9765 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9767 for (i = 0; i < 3; i++) {
9768 src = mapinfo.data + src_offset[i];
9769 dest = thandle.ptr + dest_offset[i];
9774 for (j = 0; j < stream->height >> k; j++) {
9775 memcpy(dest, src, stream->width>>k);
9776 src += src_stride[i];
9777 dest += stream->stride[i];
9780 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9781 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9783 LOGE("Not support format %d", stream->format);
9787 tbm_bo_unmap(stream->bo[0]);
9788 gst_memory_unmap(mem, &mapinfo);
9794 tbm_bo_unmap(stream->bo[0]);
9797 gst_memory_unmap(mem, &mapinfo);
9803 __mmplayer_set_pause_state(mmplayer_t *player)
9805 if (player->sent_bos)
9808 /* rtsp case, get content attrs by GstMessage */
9809 if (MMPLAYER_IS_RTSP_STREAMING(player))
9812 /* it's first time to update all content attrs. */
9813 _mmplayer_update_content_attrs(player, ATTR_ALL);
9817 __mmplayer_set_playing_state(mmplayer_t *player)
9819 gchar *audio_codec = NULL;
9821 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9822 /* initialize because auto resume is done well. */
9823 player->resumed_by_rewind = FALSE;
9824 player->playback_rate = 1.0;
9827 if (player->sent_bos)
9830 /* try to get content metadata */
9832 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9833 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9834 * legacy mmfw-player api
9836 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9838 if ((player->cmd == MMPLAYER_COMMAND_START)
9839 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9840 __mmplayer_handle_missed_plugin(player);
9843 /* check audio codec field is set or not
9844 * we can get it from typefinder or codec's caps.
9846 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9848 /* The codec format can't be sent for audio only case like amr, mid etc.
9849 * Because, parser don't make related TAG.
9850 * So, if it's not set yet, fill it with found data.
9853 if (g_strrstr(player->type, "audio/midi"))
9854 audio_codec = "MIDI";
9855 else if (g_strrstr(player->type, "audio/x-amr"))
9856 audio_codec = "AMR";
9857 else if (g_strrstr(player->type, "audio/mpeg")
9858 && !g_strrstr(player->type, "mpegversion=(int)1"))
9859 audio_codec = "AAC";
9861 audio_codec = "unknown";
9863 if (mm_player_set_attribute((MMHandleType)player, NULL,
9864 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9865 LOGE("failed to set attribute");
9867 LOGD("set audio codec type with caps");