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);
2089 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "exported-shell-handle", handle, NULL);
2090 LOGD("set video param: exported_shell_handle (%s)", handle);
2093 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2095 MMHandleType attrs = 0;
2098 /* check video sinkbin is created */
2099 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2102 attrs = MMPLAYER_GET_ATTRS(player);
2103 MMPLAYER_RETURN_IF_FAIL(attrs);
2105 /* common case if using overlay surface */
2106 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2107 MMPLAYER_RETURN_IF_FAIL(handle);
2109 /* default is using wl_surface_id */
2110 LOGD("set video param : wl_surface_id %d", handle);
2111 gst_video_overlay_set_wl_window_wl_surface_id(
2112 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2117 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2119 gboolean update_all_param = FALSE;
2120 int curr_type = MM_DISPLAY_SURFACE_NUM;
2124 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2125 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2126 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2127 LOGW("videosink is not ready yet");
2128 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2131 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2133 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2134 LOGE("current type(%d) is wrong", curr_type);
2135 return MM_ERROR_PLAYER_INTERNAL;
2138 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2139 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2140 return MM_ERROR_PLAYER_INTERNAL;
2143 LOGD("param_name : %s", param_name);
2144 if (!g_strcmp0(param_name, "update_all_param"))
2145 update_all_param = TRUE;
2147 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2148 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2150 return MM_ERROR_NONE;
2152 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2153 __mmplayer_video_param_set_display_overlay(player);
2154 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2155 __mmplayer_video_param_set_display_method(player);
2156 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2157 __mmplayer_video_param_set_display_visible(player);
2158 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2159 __mmplayer_video_param_set_display_rotation(player);
2160 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2161 __mmplayer_video_param_set_roi_area(player);
2162 if (update_all_param)
2163 __mmplayer_video_param_set_video_roi_area(player);
2166 return MM_ERROR_NONE;
2169 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2171 gboolean disable_overlay = FALSE;
2174 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2175 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2176 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2178 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2179 LOGW("Display control is not supported");
2180 return MM_ERROR_PLAYER_INTERNAL;
2183 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2185 if (disable == (bool)disable_overlay) {
2186 LOGE("It's the same with current setting: (%d)", disable);
2187 return MM_ERROR_NONE;
2191 LOGE("disable overlay");
2192 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2194 /* release overlay resource */
2195 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2196 LOGE("failed to release overlay resource");
2197 return MM_ERROR_PLAYER_INTERNAL;
2200 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2201 LOGE("failed to acquire video overlay resource");
2202 return MM_ERROR_PLAYER_INTERNAL;
2204 player->interrupted_by_resource = FALSE;
2206 LOGD("enable overlay");
2207 __mmplayer_video_param_set_display_overlay(player);
2208 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2209 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2213 return MM_ERROR_NONE;
2217 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2219 int ret = MM_ERROR_NONE;
2220 mmplayer_t *player = (mmplayer_t *)hplayer;
2223 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2225 if (MMPLAYER_USE_DECODEBIN(player)) {
2226 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2231 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2232 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2233 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2235 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2237 /* release decoder resource */
2238 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2239 LOGE("failed to release video decoder resources");
2240 return MM_ERROR_PLAYER_INTERNAL;
2242 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2244 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2248 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2255 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2257 GList *bucket = element_bucket;
2258 mmplayer_gst_element_t *element = NULL;
2259 mmplayer_gst_element_t *prv_element = NULL;
2260 GstElement *tee_element = NULL;
2261 gint successful_link_count = 0;
2265 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2267 prv_element = (mmplayer_gst_element_t *)bucket->data;
2268 bucket = bucket->next;
2270 for (; bucket; bucket = bucket->next) {
2271 element = (mmplayer_gst_element_t *)bucket->data;
2273 if (element && element->gst) {
2274 if (prv_element && prv_element->gst) {
2275 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2277 prv_element->gst = tee_element;
2279 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2280 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2281 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2285 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2286 LOGD("linking [%s] to [%s] success",
2287 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2288 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2289 successful_link_count++;
2290 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2291 LOGD("keep audio-tee element for next audio pipeline branch");
2292 tee_element = prv_element->gst;
2295 LOGD("linking [%s] to [%s] failed",
2296 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2297 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2303 prv_element = element;
2308 return successful_link_count;
2312 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2314 GList *bucket = element_bucket;
2315 mmplayer_gst_element_t *element = NULL;
2316 int successful_add_count = 0;
2320 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2321 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2323 for (; bucket; bucket = bucket->next) {
2324 element = (mmplayer_gst_element_t *)bucket->data;
2326 if (element && element->gst) {
2327 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2328 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2329 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2330 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2333 successful_add_count++;
2339 return successful_add_count;
2343 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2345 mmplayer_t *player = (mmplayer_t *)data;
2346 GstCaps *caps = NULL;
2347 GstStructure *str = NULL;
2349 gboolean caps_ret = TRUE;
2353 MMPLAYER_RETURN_IF_FAIL(pad);
2354 MMPLAYER_RETURN_IF_FAIL(unused);
2355 MMPLAYER_RETURN_IF_FAIL(data);
2357 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2361 LOGD("name = %s", name);
2363 if (strstr(name, "audio")) {
2364 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2366 if (player->audio_stream_changed_cb) {
2367 LOGE("call the audio stream changed cb");
2368 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2370 } else if (strstr(name, "video")) {
2371 if ((name = gst_structure_get_string(str, "format")))
2372 player->set_mode.video_zc = name[0] == 'S';
2374 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2375 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2377 LOGW("invalid caps info");
2382 gst_caps_unref(caps);
2390 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2395 MMPLAYER_RETURN_IF_FAIL(player);
2397 if (player->audio_stream_buff_list) {
2398 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2399 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2402 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2403 __mmplayer_audio_stream_send_data(player, tmp);
2405 MMPLAYER_FREEIF(tmp->pcm_data);
2406 MMPLAYER_FREEIF(tmp);
2409 g_list_free(player->audio_stream_buff_list);
2410 player->audio_stream_buff_list = NULL;
2417 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2419 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2422 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2424 audio_stream.bitrate = a_buffer->bitrate;
2425 audio_stream.channel = a_buffer->channel;
2426 audio_stream.channel_mask = a_buffer->channel_mask;
2427 audio_stream.data_size = a_buffer->data_size;
2428 audio_stream.data = a_buffer->pcm_data;
2429 audio_stream.pcm_format = a_buffer->pcm_format;
2431 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2433 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2439 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2441 mmplayer_t *player = (mmplayer_t *)data;
2442 const gchar *pcm_format = NULL;
2445 guint64 channel_mask = 0;
2446 void *a_data = NULL;
2448 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2449 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2453 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2455 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2456 a_data = mapinfo.data;
2457 a_size = mapinfo.size;
2459 GstCaps *caps = gst_pad_get_current_caps(pad);
2460 GstStructure *structure = gst_caps_get_structure(caps, 0);
2462 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2464 pcm_format = gst_structure_get_string(structure, "format");
2465 gst_structure_get_int(structure, "rate", &rate);
2466 gst_structure_get_int(structure, "channels", &channel);
2467 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2468 gst_caps_unref(GST_CAPS(caps));
2470 /* In case of the sync is false, use buffer list. *
2471 * The num of buffer list depends on the num of audio channels */
2472 if (player->audio_stream_buff_list) {
2473 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2474 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2476 if (channel_mask == tmp->channel_mask) {
2478 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2480 if (tmp->data_size + a_size < tmp->buff_size) {
2481 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2482 tmp->data_size += a_size;
2484 /* send data to client */
2485 __mmplayer_audio_stream_send_data(player, tmp);
2487 if (a_size > tmp->buff_size) {
2488 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2489 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2490 if (tmp->pcm_data == NULL) {
2491 LOGE("failed to realloc data.");
2494 tmp->buff_size = a_size;
2496 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2497 memcpy(tmp->pcm_data, a_data, a_size);
2498 tmp->data_size = a_size;
2503 LOGE("data is empty in list.");
2509 /* create new audio stream data for newly found audio channel */
2510 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2511 if (a_buffer == NULL) {
2512 LOGE("failed to alloc data.");
2515 a_buffer->bitrate = rate;
2516 a_buffer->channel = channel;
2517 a_buffer->channel_mask = channel_mask;
2518 a_buffer->data_size = a_size;
2519 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2521 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2522 /* If sync is FALSE, use buffer list to reduce the IPC. */
2523 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2524 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2525 if (a_buffer->pcm_data == NULL) {
2526 LOGE("failed to alloc data.");
2527 MMPLAYER_FREEIF(a_buffer);
2530 memcpy(a_buffer->pcm_data, a_data, a_size);
2532 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2534 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2536 /* If sync is TRUE, send data directly. */
2537 a_buffer->pcm_data = a_data;
2538 __mmplayer_audio_stream_send_data(player, a_buffer);
2539 MMPLAYER_FREEIF(a_buffer);
2543 gst_buffer_unmap(buffer, &mapinfo);
2548 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2550 mmplayer_t *player = (mmplayer_t *)data;
2551 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2552 GstPad *sinkpad = NULL;
2553 GstElement *queue = NULL, *sink = NULL;
2556 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2558 queue = gst_element_factory_make("queue", NULL);
2559 if (queue == NULL) {
2560 LOGD("fail make queue");
2564 sink = gst_element_factory_make("fakesink", NULL);
2566 LOGD("fail make fakesink");
2570 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2572 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2573 LOGW("failed to link queue & sink");
2577 sinkpad = gst_element_get_static_pad(queue, "sink");
2579 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2580 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2584 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2586 gst_object_unref(sinkpad);
2587 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2588 g_object_set(sink, "sync", TRUE, NULL);
2589 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2591 /* keep the first sink reference only */
2592 if (!audiobin[MMPLAYER_A_SINK].gst) {
2593 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2594 audiobin[MMPLAYER_A_SINK].gst = sink;
2598 _mmplayer_add_signal_connection(player,
2600 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2602 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2605 __mmplayer_add_sink(player, sink, FALSE);
2607 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2608 LOGE("failed to sync state");
2612 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2613 LOGE("failed to sync state");
2621 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2623 gst_object_unref(GST_OBJECT(queue));
2627 gst_object_unref(GST_OBJECT(sink));
2631 gst_object_unref(GST_OBJECT(sinkpad));
2639 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2641 mmplayer_t *player = (mmplayer_t *)data;
2644 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2646 player->no_more_pad = TRUE;
2647 _mmplayer_pipeline_complete(NULL, player);
2654 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2656 #define MAX_PROPS_LEN 128
2657 mmplayer_gst_element_t *audiobin = NULL;
2658 gint latency_mode = 0;
2659 gchar *stream_type = NULL;
2660 gchar *latency = NULL;
2662 gchar stream_props[MAX_PROPS_LEN] = {0,};
2663 GstStructure *props = NULL;
2666 * It should be set after player creation through attribute.
2667 * But, it can not be changed during playing.
2670 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2672 audiobin = player->pipeline->audiobin;
2674 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2675 if (player->sound.mute) {
2676 LOGD("mute enabled");
2677 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2680 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2681 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2684 snprintf(stream_props, sizeof(stream_props) - 1,
2685 "props,application.process.id.origin=%d", player->client_pid);
2687 snprintf(stream_props, sizeof(stream_props) - 1,
2688 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2689 stream_type, stream_id, player->client_pid);
2691 props = gst_structure_from_string(stream_props, NULL);
2692 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2693 LOGI("props result[%s].", stream_props);
2694 gst_structure_free(props);
2696 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2698 switch (latency_mode) {
2699 case AUDIO_LATENCY_MODE_LOW:
2700 latency = g_strdup("low");
2702 case AUDIO_LATENCY_MODE_MID:
2703 latency = g_strdup("mid");
2705 case AUDIO_LATENCY_MODE_HIGH:
2706 latency = g_strdup("high");
2709 latency = g_strdup("mid");
2713 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2715 LOGD("audiosink property - latency=%s", latency);
2717 MMPLAYER_FREEIF(latency);
2723 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2725 mmplayer_gst_element_t *audiobin = NULL;
2728 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2729 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2731 audiobin = player->pipeline->audiobin;
2733 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2734 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2735 LOGE("failed to create media stream info");
2736 return MM_ERROR_PLAYER_INTERNAL;
2739 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2741 if (player->video360_yaw_radians <= M_PI &&
2742 player->video360_yaw_radians >= -M_PI &&
2743 player->video360_pitch_radians <= M_PI_2 &&
2744 player->video360_pitch_radians >= -M_PI_2) {
2745 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2746 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2747 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2748 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2749 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2750 "source-orientation-y", player->video360_metadata.init_view_heading,
2751 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2755 return MM_ERROR_NONE;
2759 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2761 mmplayer_gst_element_t *audiobin = NULL;
2762 GstPad *sink_pad = NULL;
2763 GstCaps *acaps = NULL;
2765 int pitch_control = 0;
2766 double pitch_value = 1.0;
2769 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2770 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2772 audiobin = player->pipeline->audiobin;
2774 LOGD("make element for normal audio playback");
2776 /* audio bin structure for playback. {} means optional.
2777 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2779 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2780 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2783 /* for pitch control */
2784 mm_attrs_multiple_get(player->attrs, NULL,
2785 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2786 MM_PLAYER_PITCH_VALUE, &pitch_value,
2789 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2790 if (pitch_control && (player->videodec_linked == 0)) {
2791 GstElementFactory *factory;
2793 factory = gst_element_factory_find("pitch");
2795 gst_object_unref(factory);
2798 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2801 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2802 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2804 LOGW("there is no pitch element");
2809 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2811 /* replaygain volume */
2812 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2813 if (player->sound.rg_enable)
2814 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2816 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2819 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2821 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2822 /* currently, only openalsink uses volume element */
2823 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2824 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2826 if (player->sound.mute) {
2827 LOGD("mute enabled");
2828 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2832 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2834 /* audio effect element. if audio effect is enabled */
2835 if ((strcmp(player->ini.audioeffect_element, ""))
2837 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2838 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2840 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2842 if ((!player->bypass_audio_effect)
2843 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2844 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2845 if (!_mmplayer_audio_effect_custom_apply(player))
2846 LOGI("apply audio effect(custom) setting success");
2850 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2851 && (player->set_mode.rich_audio)) {
2852 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2856 /* create audio sink */
2857 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2858 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2859 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2861 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2862 if (player->is_360_feature_enabled &&
2863 player->is_content_spherical &&
2865 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2866 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2867 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2869 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2871 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2873 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2874 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2875 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2876 gst_caps_unref(acaps);
2878 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2880 player->is_openal_plugin_used = TRUE;
2882 if (player->is_360_feature_enabled && player->is_content_spherical)
2883 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2884 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2887 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2888 (player->videodec_linked && player->ini.use_system_clock)) {
2889 LOGD("system clock will be used.");
2890 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2893 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2894 __mmplayer_gst_set_pulsesink_property(player);
2895 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2896 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2901 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2902 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2904 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2905 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2906 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2907 gst_object_unref(GST_OBJECT(sink_pad));
2909 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2912 return MM_ERROR_NONE;
2914 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2916 return MM_ERROR_PLAYER_INTERNAL;
2920 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2922 mmplayer_gst_element_t *audiobin = NULL;
2923 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2925 gchar *dst_format = NULL;
2927 int dst_samplerate = 0;
2928 int dst_channels = 0;
2929 GstCaps *caps = NULL;
2930 char *caps_str = NULL;
2933 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2934 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2936 audiobin = player->pipeline->audiobin;
2938 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2940 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2942 [case 1] extract interleave audio pcm without playback
2943 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2944 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2946 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2948 [case 2] deinterleave for each channel without playback
2949 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2950 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2952 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2953 - fakesink (sync or not)
2956 [case 3] [case 1(sync only)] + playback
2957 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2959 * src - ... - tee - queue1 - playback path
2960 - queue2 - [case1 pipeline with sync]
2962 [case 4] [case 2(sync only)] + playback
2963 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2965 * src - ... - tee - queue1 - playback path
2966 - queue2 - [case2 pipeline with sync]
2970 /* 1. create tee and playback path
2971 'tee' should be added at first to copy the decoded stream
2973 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2974 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2975 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2977 /* tee - path 1 : for playback path */
2978 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2979 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2981 /* tee - path 2 : for extract path */
2982 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2983 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2986 /* if there is tee, 'tee - path 2' is linked here */
2988 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2991 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2993 /* 2. decide the extract pcm format */
2994 mm_attrs_multiple_get(player->attrs, NULL,
2995 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2996 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2997 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3000 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3001 dst_format, dst_len, dst_samplerate, dst_channels);
3003 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3004 mm_attrs_multiple_get(player->attrs, NULL,
3005 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3006 "content_audio_samplerate", &dst_samplerate,
3007 "content_audio_channels", &dst_channels,
3010 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3011 dst_format, dst_len, dst_samplerate, dst_channels);
3013 /* If there is no enough information, set it to platform default value. */
3014 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3015 LOGD("set platform default format");
3016 dst_format = DEFAULT_PCM_OUT_FORMAT;
3018 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3019 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3022 /* 3. create capsfilter */
3023 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3024 caps = gst_caps_new_simple("audio/x-raw",
3025 "format", G_TYPE_STRING, dst_format,
3026 "rate", G_TYPE_INT, dst_samplerate,
3027 "channels", G_TYPE_INT, dst_channels,
3030 caps_str = gst_caps_to_string(caps);
3031 LOGD("new caps : %s", caps_str);
3033 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3036 gst_caps_unref(caps);
3037 MMPLAYER_FREEIF(caps_str);
3039 /* 4-1. create deinterleave to extract pcm for each channel */
3040 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3041 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3042 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3044 /* audiosink will be added after getting signal for each channel */
3045 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3046 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3047 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3048 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3049 player->no_more_pad = FALSE;
3051 /* 4-2. create fakesink to extract interleaved pcm */
3052 LOGD("add audio fakesink for interleaved audio");
3053 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3054 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3055 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3056 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3058 _mmplayer_add_signal_connection(player,
3059 G_OBJECT(audiobin[extract_sink_id].gst),
3060 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3062 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3065 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3069 return MM_ERROR_NONE;
3071 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3073 return MM_ERROR_PLAYER_INTERNAL;
3077 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3079 int ret = MM_ERROR_NONE;
3080 mmplayer_gst_element_t *audiobin = NULL;
3081 GList *element_bucket = NULL;
3084 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3085 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3087 audiobin = player->pipeline->audiobin;
3089 if (player->build_audio_offload) { /* skip all the audio filters */
3090 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3092 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3093 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3094 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3096 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3100 /* FIXME: need to mention the supportable condition at API reference */
3101 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3102 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3104 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3106 if (ret != MM_ERROR_NONE)
3109 LOGD("success to make audio bin element");
3110 *bucket = element_bucket;
3113 return MM_ERROR_NONE;
3116 LOGE("failed to make audio bin element");
3117 g_list_free(element_bucket);
3121 return MM_ERROR_PLAYER_INTERNAL;
3125 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3127 mmplayer_gst_element_t *first_element = NULL;
3128 mmplayer_gst_element_t *audiobin = NULL;
3130 GstPad *ghostpad = NULL;
3131 GList *element_bucket = NULL;
3135 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3138 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3140 LOGE("failed to allocate memory for audiobin");
3141 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3145 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3146 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3147 if (!audiobin[MMPLAYER_A_BIN].gst) {
3148 LOGE("failed to create audiobin");
3153 player->pipeline->audiobin = audiobin;
3155 /* create audio filters and audiosink */
3156 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3159 /* adding created elements to bin */
3160 LOGD("adding created elements to bin");
3161 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3164 /* linking elements in the bucket by added order. */
3165 LOGD("Linking elements in the bucket by added order.");
3166 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3169 /* get first element's sinkpad for creating ghostpad */
3170 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3171 if (!first_element) {
3172 LOGE("failed to get first elem");
3176 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3178 LOGE("failed to get pad from first element of audiobin");
3182 ghostpad = gst_ghost_pad_new("sink", pad);
3184 LOGE("failed to create ghostpad");
3188 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3189 LOGE("failed to add ghostpad to audiobin");
3193 gst_object_unref(pad);
3195 g_list_free(element_bucket);
3198 return MM_ERROR_NONE;
3201 LOGD("ERROR : releasing audiobin");
3204 gst_object_unref(GST_OBJECT(pad));
3207 gst_object_unref(GST_OBJECT(ghostpad));
3210 g_list_free(element_bucket);
3212 /* release element which are not added to bin */
3213 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3214 /* NOTE : skip bin */
3215 if (audiobin[i].gst) {
3216 GstObject *parent = NULL;
3217 parent = gst_element_get_parent(audiobin[i].gst);
3220 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3221 audiobin[i].gst = NULL;
3223 gst_object_unref(GST_OBJECT(parent));
3227 /* release audiobin with it's children */
3228 if (audiobin[MMPLAYER_A_BIN].gst)
3229 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3231 MMPLAYER_FREEIF(audiobin);
3233 player->pipeline->audiobin = NULL;
3235 return MM_ERROR_PLAYER_INTERNAL;
3239 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3241 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3245 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3247 int ret = MM_ERROR_NONE;
3249 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3250 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3252 MMPLAYER_VIDEO_BO_LOCK(player);
3254 if (player->video_bo_list) {
3255 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3256 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3257 if (tmp && tmp->bo == bo) {
3259 LOGD("release bo %p", bo);
3260 tbm_bo_unref(tmp->bo);
3261 MMPLAYER_VIDEO_BO_UNLOCK(player);
3262 MMPLAYER_VIDEO_BO_SIGNAL(player);
3267 /* hw codec is running or the list was reset for DRC. */
3268 LOGW("there is no bo list.");
3270 MMPLAYER_VIDEO_BO_UNLOCK(player);
3272 LOGW("failed to find bo %p", bo);
3276 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3282 tbm_bo_unref(tmp->bo);
3287 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3290 MMPLAYER_RETURN_IF_FAIL(player);
3292 MMPLAYER_VIDEO_BO_LOCK(player);
3293 if (player->video_bo_list) {
3294 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3295 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3296 player->video_bo_list = NULL;
3298 player->video_bo_size = 0;
3299 MMPLAYER_VIDEO_BO_UNLOCK(player);
3306 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3309 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3310 gboolean ret = TRUE;
3311 gint64 end_time = 0;
3313 /* check DRC, if it is, destroy the prev bo list to create again */
3314 if (player->video_bo_size != size) {
3315 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3316 __mmplayer_video_stream_destroy_bo_list(player);
3317 player->video_bo_size = size;
3320 MMPLAYER_VIDEO_BO_LOCK(player);
3322 if ((!player->video_bo_list) ||
3323 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3325 /* create bo list */
3327 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3329 if (player->video_bo_list) {
3330 /* if bo list did not created all, try it again. */
3331 idx = g_list_length(player->video_bo_list);
3332 LOGD("bo list exist(len: %d)", idx);
3335 for (; idx < player->ini.num_of_video_bo; idx++) {
3336 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3338 LOGE("Fail to alloc bo_info.");
3341 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3343 LOGE("Fail to tbm_bo_alloc.");
3344 MMPLAYER_FREEIF(bo_info);
3347 bo_info->used = FALSE;
3348 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3351 /* update video num buffers */
3352 LOGD("video_num_buffers : %d", idx);
3353 mm_player_set_attribute((MMHandleType)player, NULL,
3354 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3355 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3359 MMPLAYER_VIDEO_BO_UNLOCK(player);
3364 if (player->ini.video_bo_timeout > 0)
3365 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3368 /* get bo from list*/
3369 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3370 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3371 if (tmp && (tmp->used == FALSE)) {
3372 LOGD("found bo %p to use", tmp->bo);
3374 MMPLAYER_VIDEO_BO_UNLOCK(player);
3375 return tbm_bo_ref(tmp->bo);
3379 if (player->ini.video_bo_timeout <= 0) {
3380 MMPLAYER_VIDEO_BO_WAIT(player);
3382 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3384 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3390 MMPLAYER_VIDEO_BO_UNLOCK(player);
3395 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3397 mmplayer_t *player = (mmplayer_t *)data;
3399 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3401 /* send prerolled pkt */
3402 player->video_stream_prerolled = false;
3404 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3406 /* not to send prerolled pkt again */
3407 player->video_stream_prerolled = true;
3411 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3413 mmplayer_t *player = (mmplayer_t *)data;
3414 mmplayer_video_decoded_data_info_t *stream = NULL;
3415 GstMemory *mem = NULL;
3418 MMPLAYER_RETURN_IF_FAIL(player);
3419 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3421 if (player->video_stream_prerolled) {
3422 player->video_stream_prerolled = false;
3423 LOGD("skip the prerolled pkt not to send it again");
3427 /* clear stream data structure */
3428 stream = __mmplayer_create_stream_from_pad(pad);
3430 LOGE("failed to alloc stream");
3434 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3436 /* set size and timestamp */
3437 mem = gst_buffer_peek_memory(buffer, 0);
3438 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3439 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3441 /* check zero-copy */
3442 if (player->set_mode.video_zc &&
3443 player->set_mode.video_export &&
3444 gst_is_tizen_memory(mem)) {
3445 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3446 stream->internal_buffer = gst_buffer_ref(buffer);
3447 } else { /* sw codec */
3448 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3451 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3455 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3456 LOGE("failed to send video decoded data.");
3463 LOGE("release video stream resource.");
3464 if (gst_is_tizen_memory(mem)) {
3466 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3468 tbm_bo_unref(stream->bo[i]);
3471 /* unref gst buffer */
3472 if (stream->internal_buffer)
3473 gst_buffer_unref(stream->internal_buffer);
3476 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3478 MMPLAYER_FREEIF(stream);
3483 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3485 mmplayer_gst_element_t *videobin = NULL;
3488 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3490 videobin = player->pipeline->videobin;
3492 /* Set spatial media metadata and/or user settings to the element.
3494 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3495 "projection-type", player->video360_metadata.projection_type, NULL);
3497 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3498 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3500 if (player->video360_metadata.full_pano_width_pixels &&
3501 player->video360_metadata.full_pano_height_pixels &&
3502 player->video360_metadata.cropped_area_image_width &&
3503 player->video360_metadata.cropped_area_image_height) {
3504 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3505 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3506 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3507 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3508 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3509 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3510 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3514 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3515 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3516 "horizontal-fov", player->video360_horizontal_fov,
3517 "vertical-fov", player->video360_vertical_fov, NULL);
3520 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3521 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3522 "zoom", 1.0f / player->video360_zoom, NULL);
3525 if (player->video360_yaw_radians <= M_PI &&
3526 player->video360_yaw_radians >= -M_PI &&
3527 player->video360_pitch_radians <= M_PI_2 &&
3528 player->video360_pitch_radians >= -M_PI_2) {
3529 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3530 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3531 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3532 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3533 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3534 "pose-yaw", player->video360_metadata.init_view_heading,
3535 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3538 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3539 "passthrough", !player->is_video360_enabled, NULL);
3546 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3548 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3549 GList *element_bucket = NULL;
3552 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3554 /* create video360 filter */
3555 if (player->is_360_feature_enabled && player->is_content_spherical) {
3556 LOGD("create video360 element");
3557 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3558 __mmplayer_gst_set_video360_property(player);
3562 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3563 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3564 player->set_mode.video_zc) {
3565 LOGD("skip creating the videoconv and rotator");
3566 return MM_ERROR_NONE;
3569 /* in case of sw codec & overlay surface type, except 360 playback.
3570 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3571 LOGD("create video converter: %s", video_csc);
3572 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3575 *bucket = element_bucket;
3577 return MM_ERROR_NONE;
3579 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3580 g_list_free(element_bucket);
3584 return MM_ERROR_PLAYER_INTERNAL;
3588 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3590 gchar *factory_name = NULL;
3592 switch (surface_type) {
3593 case MM_DISPLAY_SURFACE_OVERLAY:
3595 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3596 if (strlen(player->ini.videosink_element_overlay) > 0)
3597 factory_name = player->ini.videosink_element_overlay;
3599 case MM_DISPLAY_SURFACE_REMOTE:
3601 case MM_DISPLAY_SURFACE_NULL:
3602 if (strlen(player->ini.videosink_element_fake) > 0)
3603 factory_name = player->ini.videosink_element_fake;
3606 LOGE("unidentified surface type");
3610 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3611 return factory_name;
3615 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3617 gchar *factory_name = NULL;
3618 mmplayer_gst_element_t *videobin = NULL;
3623 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3625 videobin = player->pipeline->videobin;
3626 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3628 attrs = MMPLAYER_GET_ATTRS(player);
3630 LOGE("cannot get content attribute");
3631 return MM_ERROR_PLAYER_INTERNAL;
3634 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3635 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3636 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3637 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3638 "use-tbm", use_tbm, NULL);
3641 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3642 return MM_ERROR_PLAYER_INTERNAL;
3644 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3647 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3648 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3651 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3653 LOGD("disable last-sample");
3654 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3657 if (player->set_mode.video_export) {
3659 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3660 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3661 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3663 _mmplayer_add_signal_connection(player,
3664 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3665 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3667 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3670 _mmplayer_add_signal_connection(player,
3671 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3672 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3674 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3678 if (videobin[MMPLAYER_V_SINK].gst) {
3679 GstPad *sink_pad = NULL;
3680 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3682 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3683 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3684 gst_object_unref(GST_OBJECT(sink_pad));
3686 LOGE("failed to get sink pad from videosink");
3690 return MM_ERROR_NONE;
3695 * - video overlay surface(arm/x86) : tizenwlsink
3698 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3701 GList *element_bucket = NULL;
3702 mmplayer_gst_element_t *first_element = NULL;
3703 mmplayer_gst_element_t *videobin = NULL;
3704 gchar *videosink_factory_name = NULL;
3707 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3710 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3712 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3714 player->pipeline->videobin = videobin;
3717 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3718 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3719 if (!videobin[MMPLAYER_V_BIN].gst) {
3720 LOGE("failed to create videobin");
3724 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3727 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3728 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3730 /* additional setting for sink plug-in */
3731 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3732 LOGE("failed to set video property");
3736 /* store it as it's sink element */
3737 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3739 /* adding created elements to bin */
3740 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3741 LOGE("failed to add elements");
3745 /* Linking elements in the bucket by added order */
3746 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3747 LOGE("failed to link elements");
3751 /* get first element's sinkpad for creating ghostpad */
3752 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3753 if (!first_element) {
3754 LOGE("failed to get first element from bucket");
3758 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3760 LOGE("failed to get pad from first element");
3764 /* create ghostpad */
3765 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3766 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3767 LOGE("failed to add ghostpad to videobin");
3770 gst_object_unref(pad);
3772 /* done. free allocated variables */
3773 g_list_free(element_bucket);
3777 return MM_ERROR_NONE;
3780 LOGE("ERROR : releasing videobin");
3781 g_list_free(element_bucket);
3784 gst_object_unref(GST_OBJECT(pad));
3786 /* release videobin with it's children */
3787 if (videobin[MMPLAYER_V_BIN].gst)
3788 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3790 MMPLAYER_FREEIF(videobin);
3791 player->pipeline->videobin = NULL;
3793 return MM_ERROR_PLAYER_INTERNAL;
3797 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3799 GList *element_bucket = NULL;
3800 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3802 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3803 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3804 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3805 "signal-handoffs", FALSE,
3808 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3809 _mmplayer_add_signal_connection(player,
3810 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3811 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3813 G_CALLBACK(__mmplayer_update_subtitle),
3816 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3817 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3819 if (!player->play_subtitle) {
3820 LOGD("add textbin sink as sink element of whole pipeline.");
3821 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3824 /* adding created elements to bin */
3825 LOGD("adding created elements to bin");
3826 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3827 LOGE("failed to add elements");
3831 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3832 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3833 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3835 /* linking elements in the bucket by added order. */
3836 LOGD("Linking elements in the bucket by added order.");
3837 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3838 LOGE("failed to link elements");
3842 if (textbin[MMPLAYER_T_QUEUE].gst) {
3844 GstPad *ghostpad = NULL;
3846 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3848 LOGE("failed to get sink pad of text queue");
3852 ghostpad = gst_ghost_pad_new("text_sink", pad);
3853 gst_object_unref(pad);
3856 LOGE("failed to create ghostpad of textbin");
3860 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3861 LOGE("failed to add ghostpad to textbin");
3862 gst_object_unref(ghostpad);
3867 g_list_free(element_bucket);
3869 return MM_ERROR_NONE;
3873 g_list_free(element_bucket);
3875 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3876 LOGE("remove textbin sink from sink list");
3877 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3880 /* release element at __mmplayer_gst_create_text_sink_bin */
3881 return MM_ERROR_PLAYER_INTERNAL;
3885 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3887 mmplayer_gst_element_t *textbin = NULL;
3888 int surface_type = 0;
3893 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3896 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3898 LOGE("failed to allocate memory for textbin");
3899 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3903 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3904 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3905 if (!textbin[MMPLAYER_T_BIN].gst) {
3906 LOGE("failed to create textbin");
3911 player->pipeline->textbin = textbin;
3914 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3915 LOGD("surface type for subtitle : %d", surface_type);
3916 switch (surface_type) {
3917 case MM_DISPLAY_SURFACE_OVERLAY:
3918 case MM_DISPLAY_SURFACE_NULL:
3919 case MM_DISPLAY_SURFACE_REMOTE:
3920 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3921 LOGE("failed to make plain text elements");
3932 return MM_ERROR_NONE;
3936 LOGD("ERROR : releasing textbin");
3938 /* release signal */
3939 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3941 /* release element which are not added to bin */
3942 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3943 /* NOTE : skip bin */
3944 if (textbin[i].gst) {
3945 GstObject *parent = NULL;
3946 parent = gst_element_get_parent(textbin[i].gst);
3949 gst_object_unref(GST_OBJECT(textbin[i].gst));
3950 textbin[i].gst = NULL;
3952 gst_object_unref(GST_OBJECT(parent));
3957 /* release textbin with it's children */
3958 if (textbin[MMPLAYER_T_BIN].gst)
3959 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3961 MMPLAYER_FREEIF(textbin);
3962 player->pipeline->textbin = NULL;
3965 return MM_ERROR_PLAYER_INTERNAL;
3969 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3971 mmplayer_gst_element_t *mainbin = NULL;
3972 mmplayer_gst_element_t *textbin = NULL;
3973 MMHandleType attrs = 0;
3974 GstElement *subsrc = NULL;
3975 GstElement *subparse = NULL;
3976 gchar *subtitle_uri = NULL;
3977 const gchar *charset = NULL;
3983 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3985 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3987 mainbin = player->pipeline->mainbin;
3989 attrs = MMPLAYER_GET_ATTRS(player);
3991 LOGE("cannot get content attribute");
3992 return MM_ERROR_PLAYER_INTERNAL;
3995 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3996 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3997 LOGE("subtitle uri is not proper filepath.");
3998 return MM_ERROR_PLAYER_INVALID_URI;
4001 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4002 LOGE("failed to get storage info of subtitle path");
4003 return MM_ERROR_PLAYER_INVALID_URI;
4006 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4008 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4009 player->subtitle_language_list = NULL;
4010 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4012 /* create the subtitle source */
4013 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4015 LOGE("failed to create filesrc element");
4018 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4020 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4021 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4023 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4024 LOGW("failed to add queue");
4025 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4026 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4027 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4032 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4034 LOGE("failed to create subparse element");
4038 charset = _mmplayer_get_charset(subtitle_uri);
4040 LOGD("detected charset is %s", charset);
4041 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4044 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4045 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4047 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4048 LOGW("failed to add subparse");
4049 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4050 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4051 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4055 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4056 LOGW("failed to link subsrc and subparse");
4060 player->play_subtitle = TRUE;
4061 player->adjust_subtitle_pos = 0;
4063 LOGD("play subtitle using subtitle file");
4065 if (player->pipeline->textbin == NULL) {
4066 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4067 LOGE("failed to create text sink bin. continuing without text");
4071 textbin = player->pipeline->textbin;
4073 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4074 LOGW("failed to add textbin");
4076 /* release signal */
4077 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4079 /* release textbin with it's children */
4080 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4081 MMPLAYER_FREEIF(player->pipeline->textbin);
4082 player->pipeline->textbin = textbin = NULL;
4086 LOGD("link text input selector and textbin ghost pad");
4088 player->textsink_linked = 1;
4089 player->external_text_idx = 0;
4090 LOGI("textsink is linked");
4092 textbin = player->pipeline->textbin;
4093 LOGD("text bin has been created. reuse it.");
4094 player->external_text_idx = 1;
4097 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4098 LOGW("failed to link subparse and textbin");
4102 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4104 LOGE("failed to get sink pad from textsink to probe data");
4108 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4109 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4111 gst_object_unref(pad);
4114 /* create dot. for debugging */
4115 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4118 return MM_ERROR_NONE;
4121 /* release text pipeline resource */
4122 player->textsink_linked = 0;
4124 /* release signal */
4125 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4127 if (player->pipeline->textbin) {
4128 LOGE("remove textbin");
4130 /* release textbin with it's children */
4131 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4132 MMPLAYER_FREEIF(player->pipeline->textbin);
4133 player->pipeline->textbin = NULL;
4137 /* release subtitle elem */
4138 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4139 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4141 return MM_ERROR_PLAYER_INTERNAL;
4145 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4147 mmplayer_t *player = (mmplayer_t *)data;
4148 MMMessageParamType msg = {0, };
4149 GstClockTime duration = 0;
4150 gpointer text = NULL;
4151 guint text_size = 0;
4152 gboolean ret = TRUE;
4153 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4157 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4158 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4160 if (player->is_subtitle_force_drop) {
4161 LOGW("subtitle is dropped forcedly.");
4165 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4166 text = mapinfo.data;
4167 text_size = mapinfo.size;
4169 if (player->set_mode.subtitle_off) {
4170 LOGD("subtitle is OFF.");
4174 if (!text || (text_size == 0)) {
4175 LOGD("There is no subtitle to be displayed.");
4179 msg.data = (void *)text;
4181 duration = GST_BUFFER_DURATION(buffer);
4183 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4184 if (player->duration > GST_BUFFER_PTS(buffer))
4185 duration = player->duration - GST_BUFFER_PTS(buffer);
4188 LOGI("subtitle duration is invalid, subtitle duration change "
4189 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4191 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4193 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4195 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4196 gst_buffer_unmap(buffer, &mapinfo);
4203 static GstPadProbeReturn
4204 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4206 mmplayer_t *player = (mmplayer_t *)u_data;
4207 GstClockTime cur_timestamp = 0;
4208 gint64 adjusted_timestamp = 0;
4209 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4211 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4213 if (player->set_mode.subtitle_off) {
4214 LOGD("subtitle is OFF.");
4218 if (player->adjust_subtitle_pos == 0) {
4219 LOGD("nothing to do");
4223 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4224 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4226 if (adjusted_timestamp < 0) {
4227 LOGD("adjusted_timestamp under zero");
4232 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4233 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4234 GST_TIME_ARGS(cur_timestamp),
4235 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4237 return GST_PAD_PROBE_OK;
4241 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4245 /* check player and subtitlebin are created */
4246 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4247 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4249 if (position == 0) {
4250 LOGD("nothing to do");
4252 return MM_ERROR_NONE;
4255 /* check current position */
4256 player->adjust_subtitle_pos = position;
4258 LOGD("save adjust_subtitle_pos in player");
4262 return MM_ERROR_NONE;
4266 * This function is to create audio or video pipeline for playing.
4268 * @param player [in] handle of player
4270 * @return This function returns zero on success.
4275 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4277 int ret = MM_ERROR_NONE;
4278 mmplayer_gst_element_t *mainbin = NULL;
4279 MMHandleType attrs = 0;
4282 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4284 /* get profile attribute */
4285 attrs = MMPLAYER_GET_ATTRS(player);
4287 LOGE("failed to get content attribute");
4291 /* create pipeline handles */
4292 if (player->pipeline) {
4293 LOGE("pipeline should be released before create new one");
4297 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4299 /* create mainbin */
4300 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4301 if (mainbin == NULL)
4304 /* create pipeline */
4305 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4306 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4307 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4308 LOGE("failed to create pipeline");
4313 player->pipeline->mainbin = mainbin;
4315 /* create the source and decoder elements */
4316 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4317 ret = _mmplayer_gst_build_es_pipeline(player);
4319 if (MMPLAYER_USE_DECODEBIN(player))
4320 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4322 ret = _mmplayer_gst_build_pipeline_with_src(player);
4325 if (ret != MM_ERROR_NONE) {
4326 LOGE("failed to create some elements");
4330 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4331 if (__mmplayer_check_subtitle(player)
4332 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4333 LOGE("failed to create text pipeline");
4336 ret = _mmplayer_gst_add_bus_watch(player);
4337 if (ret != MM_ERROR_NONE) {
4338 LOGE("failed to add bus watch");
4343 return MM_ERROR_NONE;
4346 _mmplayer_bus_watcher_remove(player);
4347 __mmplayer_gst_destroy_pipeline(player);
4348 return MM_ERROR_PLAYER_INTERNAL;
4352 __mmplayer_reset_gapless_state(mmplayer_t *player)
4355 MMPLAYER_RETURN_IF_FAIL(player
4357 && player->pipeline->audiobin
4358 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4360 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4367 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4370 int ret = MM_ERROR_NONE;
4374 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4376 /* cleanup stuffs */
4377 MMPLAYER_FREEIF(player->type);
4378 player->no_more_pad = FALSE;
4379 player->num_dynamic_pad = 0;
4381 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4382 player->subtitle_language_list = NULL;
4383 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4385 MMPLAYER_RECONFIGURE_LOCK(player);
4386 __mmplayer_reset_gapless_state(player);
4387 MMPLAYER_RECONFIGURE_UNLOCK(player);
4389 if (player->streamer) {
4390 _mm_player_streaming_initialize(player->streamer, FALSE);
4391 _mm_player_streaming_destroy(player->streamer);
4392 player->streamer = NULL;
4395 /* cleanup unlinked mime type */
4396 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4397 MMPLAYER_FREEIF(player->unlinked_video_mime);
4398 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4400 /* cleanup running stuffs */
4401 _mmplayer_cancel_eos_timer(player);
4403 /* cleanup gst stuffs */
4404 if (player->pipeline) {
4405 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4406 GstTagList *tag_list = player->pipeline->tag_list;
4408 /* first we need to disconnect all signal hander */
4409 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4412 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4413 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4414 gst_object_unref(bus);
4416 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4417 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4418 if (ret != MM_ERROR_NONE) {
4419 LOGE("fail to change state to NULL");
4420 return MM_ERROR_PLAYER_INTERNAL;
4423 LOGW("succeeded in changing state to NULL");
4425 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4428 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4429 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4431 MMPLAYER_FREEIF(player->pipeline->audiobin);
4432 MMPLAYER_FREEIF(player->pipeline->videobin);
4433 MMPLAYER_FREEIF(player->pipeline->textbin);
4434 MMPLAYER_FREEIF(mainbin);
4438 gst_tag_list_unref(tag_list);
4440 MMPLAYER_FREEIF(player->pipeline);
4442 MMPLAYER_FREEIF(player->album_art);
4444 if (player->type_caps) {
4445 gst_caps_unref(player->type_caps);
4446 player->type_caps = NULL;
4449 if (player->v_stream_caps) {
4450 gst_caps_unref(player->v_stream_caps);
4451 player->v_stream_caps = NULL;
4454 if (player->a_stream_caps) {
4455 gst_caps_unref(player->a_stream_caps);
4456 player->a_stream_caps = NULL;
4459 if (player->s_stream_caps) {
4460 gst_caps_unref(player->s_stream_caps);
4461 player->s_stream_caps = NULL;
4463 _mmplayer_track_destroy(player);
4465 if (player->sink_elements)
4466 g_list_free(player->sink_elements);
4467 player->sink_elements = NULL;
4469 if (player->bufmgr) {
4470 tbm_bufmgr_deinit(player->bufmgr);
4471 player->bufmgr = NULL;
4474 LOGW("finished destroy pipeline");
4482 __mmplayer_gst_realize(mmplayer_t *player)
4485 int ret = MM_ERROR_NONE;
4489 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4491 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4493 ret = __mmplayer_gst_create_pipeline(player);
4495 LOGE("failed to create pipeline");
4499 /* set pipeline state to READY */
4500 /* NOTE : state change to READY must be performed sync. */
4501 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4502 ret = _mmplayer_gst_set_state(player,
4503 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4505 if (ret != MM_ERROR_NONE) {
4506 /* return error if failed to set state */
4507 LOGE("failed to set READY state");
4511 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4513 /* create dot before error-return. for debugging */
4514 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4522 __mmplayer_gst_unrealize(mmplayer_t *player)
4524 int ret = MM_ERROR_NONE;
4528 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4530 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4531 MMPLAYER_PRINT_STATE(player);
4533 /* release miscellaneous information */
4534 __mmplayer_release_misc(player);
4536 /* destroy pipeline */
4537 ret = __mmplayer_gst_destroy_pipeline(player);
4538 if (ret != MM_ERROR_NONE) {
4539 LOGE("failed to destroy pipeline");
4543 /* release miscellaneous information.
4544 these info needs to be released after pipeline is destroyed. */
4545 __mmplayer_release_misc_post(player);
4547 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4555 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4560 LOGW("set_message_callback is called with invalid player handle");
4561 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4564 player->msg_cb = callback;
4565 player->msg_cb_param = user_param;
4567 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4571 return MM_ERROR_NONE;
4575 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4577 int ret = MM_ERROR_NONE;
4582 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4583 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4584 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4586 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4588 if (strstr(uri, "es_buff://")) {
4589 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4590 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4591 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4592 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4594 tmp = g_ascii_strdown(uri, strlen(uri));
4595 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4596 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4598 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4600 } else if (strstr(uri, "mms://")) {
4601 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4602 } else if ((path = strstr(uri, "mem://"))) {
4603 ret = __mmplayer_set_mem_uri(data, path, param);
4605 ret = __mmplayer_set_file_uri(data, uri);
4608 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4609 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4610 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4611 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4613 /* dump parse result */
4614 SECURE_LOGW("incoming uri : %s", uri);
4615 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4616 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4624 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4627 mmplayer_t *player = NULL;
4628 MMMessageParamType msg = {0, };
4630 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4635 LOGE("user_data is null");
4639 player = (mmplayer_t *)user_data;
4641 if (!player->pipeline || !player->attrs) {
4642 LOGW("not initialized");
4646 LOGD("cmd lock player, cmd state : %d", player->cmd);
4647 MMPLAYER_CMD_LOCK(player);
4648 LOGD("cmd locked player");
4650 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4651 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4652 LOGW("player already destroyed");
4653 MMPLAYER_CMD_UNLOCK(player);
4657 player->interrupted_by_resource = TRUE;
4659 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4661 /* get last play position */
4662 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4663 msg.union_type = MM_MSG_UNION_TIME;
4664 msg.time.elapsed = pos;
4665 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4667 LOGW("failed to get play position.");
4670 LOGD("video resource conflict so, resource will be freed by unrealizing");
4671 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4672 LOGE("failed to unrealize");
4674 MMPLAYER_CMD_UNLOCK(player);
4676 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4677 player->hw_resource[res_idx] = NULL;
4681 return TRUE; /* release all the resources */
4685 __mmplayer_initialize_video_roi(mmplayer_t *player)
4687 player->video_roi.scale_x = 0.0;
4688 player->video_roi.scale_y = 0.0;
4689 player->video_roi.scale_width = 1.0;
4690 player->video_roi.scale_height = 1.0;
4694 _mmplayer_create_player(MMHandleType handle)
4696 int ret = MM_ERROR_PLAYER_INTERNAL;
4697 bool enabled = false;
4699 mmplayer_t *player = MM_PLAYER_CAST(handle);
4703 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4705 /* initialize player state */
4706 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4707 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4708 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4709 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4711 /* check current state */
4712 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4714 /* construct attributes */
4715 player->attrs = _mmplayer_construct_attribute(handle);
4717 if (!player->attrs) {
4718 LOGE("Failed to construct attributes");
4722 /* initialize gstreamer with configured parameter */
4723 if (!__mmplayer_init_gstreamer(player)) {
4724 LOGE("Initializing gstreamer failed");
4725 _mmplayer_deconstruct_attribute(handle);
4729 /* create lock. note that g_tread_init() has already called in gst_init() */
4730 g_mutex_init(&player->fsink_lock);
4732 /* create update tag lock */
4733 g_mutex_init(&player->update_tag_lock);
4735 /* create gapless play mutex */
4736 g_mutex_init(&player->gapless_play_thread_mutex);
4738 /* create gapless play cond */
4739 g_cond_init(&player->gapless_play_thread_cond);
4741 /* create gapless play thread */
4742 player->gapless_play_thread =
4743 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4744 if (!player->gapless_play_thread) {
4745 LOGE("failed to create gapless play thread");
4746 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4747 g_mutex_clear(&player->gapless_play_thread_mutex);
4748 g_cond_clear(&player->gapless_play_thread_cond);
4752 player->bus_msg_q = g_queue_new();
4753 if (!player->bus_msg_q) {
4754 LOGE("failed to create queue for bus_msg");
4755 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4759 ret = _mmplayer_initialize_video_capture(player);
4760 if (ret != MM_ERROR_NONE) {
4761 LOGW("video capture is not supported");
4762 /* do not handle as error for headless profile */
4765 /* initialize resource manager */
4766 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4767 __resource_release_cb, player, &player->resource_manager)
4768 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4769 LOGE("failed to create resource manager");
4770 ret = MM_ERROR_PLAYER_INTERNAL;
4774 /* create video bo lock and cond */
4775 g_mutex_init(&player->video_bo_mutex);
4776 g_cond_init(&player->video_bo_cond);
4778 /* create subtitle info lock and cond */
4779 g_mutex_init(&player->subtitle_info_mutex);
4780 g_cond_init(&player->subtitle_info_cond);
4782 player->streaming_type = STREAMING_SERVICE_NONE;
4784 /* give default value of audio effect setting */
4785 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4786 player->sound.rg_enable = false;
4787 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4789 player->play_subtitle = FALSE;
4790 player->has_closed_caption = FALSE;
4791 player->pending_resume = FALSE;
4792 if (player->ini.dump_element_keyword[0][0] == '\0')
4793 player->ini.set_dump_element_flag = FALSE;
4795 player->ini.set_dump_element_flag = TRUE;
4797 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4798 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4799 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4801 /* Set video360 settings to their defaults for just-created player.
4804 player->is_360_feature_enabled = FALSE;
4805 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4806 LOGI("spherical feature info: %d", enabled);
4808 player->is_360_feature_enabled = TRUE;
4810 LOGE("failed to get spherical feature info");
4813 player->is_content_spherical = FALSE;
4814 player->is_video360_enabled = TRUE;
4815 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4816 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4817 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4818 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4819 player->video360_zoom = 1.0f;
4820 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4821 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4823 __mmplayer_initialize_video_roi(player);
4825 /* set player state to null */
4826 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4827 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4831 return MM_ERROR_NONE;
4835 g_mutex_clear(&player->fsink_lock);
4836 /* free update tag lock */
4837 g_mutex_clear(&player->update_tag_lock);
4838 g_queue_free(player->bus_msg_q);
4839 player->bus_msg_q = NULL;
4840 /* free gapless play thread */
4841 if (player->gapless_play_thread) {
4842 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4843 player->gapless_play_thread_exit = TRUE;
4844 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4845 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4847 g_thread_join(player->gapless_play_thread);
4848 player->gapless_play_thread = NULL;
4850 g_mutex_clear(&player->gapless_play_thread_mutex);
4851 g_cond_clear(&player->gapless_play_thread_cond);
4854 /* release attributes */
4855 _mmplayer_deconstruct_attribute(handle);
4863 __mmplayer_init_gstreamer(mmplayer_t *player)
4865 static gboolean initialized = FALSE;
4866 static const int max_argc = 50;
4868 gchar **argv = NULL;
4869 gchar **argv2 = NULL;
4875 LOGD("gstreamer already initialized.");
4880 argc = malloc(sizeof(int));
4881 argv = malloc(sizeof(gchar *) * max_argc);
4882 argv2 = malloc(sizeof(gchar *) * max_argc);
4884 if (!argc || !argv || !argv2)
4887 memset(argv, 0, sizeof(gchar *) * max_argc);
4888 memset(argv2, 0, sizeof(gchar *) * max_argc);
4892 argv[0] = g_strdup("mmplayer");
4895 for (i = 0; i < 5; i++) {
4896 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4897 if (strlen(player->ini.gst_param[i]) > 0) {
4898 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4903 /* we would not do fork for scanning plugins */
4904 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4907 /* check disable registry scan */
4908 if (player->ini.skip_rescan) {
4909 argv[*argc] = g_strdup("--gst-disable-registry-update");
4913 /* check disable segtrap */
4914 if (player->ini.disable_segtrap) {
4915 argv[*argc] = g_strdup("--gst-disable-segtrap");
4919 LOGD("initializing gstreamer with following parameter");
4920 LOGD("argc : %d", *argc);
4923 for (i = 0; i < arg_count; i++) {
4925 LOGD("argv[%d] : %s", i, argv2[i]);
4928 /* initializing gstreamer */
4929 if (!gst_init_check(argc, &argv, &err)) {
4930 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4937 for (i = 0; i < arg_count; i++) {
4939 LOGD("release - argv[%d] : %s", i, argv2[i]);
4941 MMPLAYER_FREEIF(argv2[i]);
4944 MMPLAYER_FREEIF(argv);
4945 MMPLAYER_FREEIF(argv2);
4946 MMPLAYER_FREEIF(argc);
4956 for (i = 0; i < arg_count; i++) {
4957 LOGD("free[%d] : %s", i, argv2[i]);
4958 MMPLAYER_FREEIF(argv2[i]);
4961 MMPLAYER_FREEIF(argv);
4962 MMPLAYER_FREEIF(argv2);
4963 MMPLAYER_FREEIF(argc);
4969 __mmplayer_check_async_state_transition(mmplayer_t *player)
4971 GstState element_state = GST_STATE_VOID_PENDING;
4972 GstState element_pending_state = GST_STATE_VOID_PENDING;
4973 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4974 GstElement *element = NULL;
4975 gboolean async = FALSE;
4977 /* check player handle */
4978 MMPLAYER_RETURN_IF_FAIL(player &&
4980 player->pipeline->mainbin &&
4981 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4984 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4986 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4987 LOGD("don't need to check the pipeline state");
4991 MMPLAYER_PRINT_STATE(player);
4993 /* wait for state transition */
4994 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4995 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4997 if (ret == GST_STATE_CHANGE_FAILURE) {
4998 LOGE(" [%s] state : %s pending : %s",
4999 GST_ELEMENT_NAME(element),
5000 gst_element_state_get_name(element_state),
5001 gst_element_state_get_name(element_pending_state));
5003 /* dump state of all element */
5004 _mmplayer_dump_pipeline_state(player);
5009 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5014 _mmplayer_destroy(MMHandleType handle)
5016 mmplayer_t *player = MM_PLAYER_CAST(handle);
5020 /* check player handle */
5021 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5023 /* destroy can called at anytime */
5024 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5026 /* check async state transition */
5027 __mmplayer_check_async_state_transition(player);
5029 /* release gapless play thread */
5030 if (player->gapless_play_thread) {
5031 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5032 player->gapless_play_thread_exit = TRUE;
5033 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5034 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5036 LOGD("waiting for gapless play thread exit");
5037 g_thread_join(player->gapless_play_thread);
5038 g_mutex_clear(&player->gapless_play_thread_mutex);
5039 g_cond_clear(&player->gapless_play_thread_cond);
5040 LOGD("gapless play thread released");
5043 _mmplayer_release_video_capture(player);
5045 /* release miscellaneous information */
5046 __mmplayer_release_misc(player);
5048 /* release pipeline */
5049 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5050 LOGE("failed to destroy pipeline");
5051 return MM_ERROR_PLAYER_INTERNAL;
5054 __mmplayer_destroy_hw_resource(player);
5056 g_queue_free(player->bus_msg_q);
5058 /* release subtitle info lock and cond */
5059 g_mutex_clear(&player->subtitle_info_mutex);
5060 g_cond_clear(&player->subtitle_info_cond);
5062 __mmplayer_release_dump_list(player->dump_list);
5064 /* release miscellaneous information.
5065 these info needs to be released after pipeline is destroyed. */
5066 __mmplayer_release_misc_post(player);
5068 /* release attributes */
5069 _mmplayer_deconstruct_attribute(handle);
5071 if (player->uri_info.uri_list) {
5072 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5073 player->uri_info.uri_list = NULL;
5077 g_mutex_clear(&player->fsink_lock);
5080 g_mutex_clear(&player->update_tag_lock);
5082 /* release video bo lock and cond */
5083 g_mutex_clear(&player->video_bo_mutex);
5084 g_cond_clear(&player->video_bo_cond);
5088 return MM_ERROR_NONE;
5092 _mmplayer_realize(MMHandleType hplayer)
5094 mmplayer_t *player = (mmplayer_t *)hplayer;
5095 int ret = MM_ERROR_NONE;
5098 MMHandleType attrs = 0;
5102 /* check player handle */
5103 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5105 /* check current state */
5106 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5108 attrs = MMPLAYER_GET_ATTRS(player);
5110 LOGE("fail to get attributes.");
5111 return MM_ERROR_PLAYER_INTERNAL;
5113 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5114 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5116 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5117 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5119 if (ret != MM_ERROR_NONE) {
5120 LOGE("failed to parse profile");
5125 if (uri && (strstr(uri, "es_buff://"))) {
5126 if (strstr(uri, "es_buff://push_mode"))
5127 player->es_player_push_mode = TRUE;
5129 player->es_player_push_mode = FALSE;
5132 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5133 LOGW("mms protocol is not supported format.");
5134 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5137 if (MMPLAYER_IS_STREAMING(player))
5138 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5140 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5142 player->smooth_streaming = FALSE;
5143 player->videodec_linked = 0;
5144 player->audiodec_linked = 0;
5145 player->textsink_linked = 0;
5146 player->is_external_subtitle_present = FALSE;
5147 player->is_external_subtitle_added_now = FALSE;
5148 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5149 player->video360_metadata.is_spherical = -1;
5150 player->is_openal_plugin_used = FALSE;
5151 player->subtitle_language_list = NULL;
5152 player->is_subtitle_force_drop = FALSE;
5154 _mmplayer_track_initialize(player);
5155 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5157 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5158 gint prebuffer_ms = 0, rebuffer_ms = 0;
5160 player->streamer = _mm_player_streaming_create();
5161 _mm_player_streaming_initialize(player->streamer, TRUE);
5163 mm_attrs_multiple_get(player->attrs, NULL,
5164 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5165 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5167 if (prebuffer_ms > 0) {
5168 prebuffer_ms = MAX(prebuffer_ms, 1000);
5169 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5172 if (rebuffer_ms > 0) {
5173 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5174 rebuffer_ms = MAX(rebuffer_ms, 1000);
5175 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5178 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5179 player->streamer->buffering_req.rebuffer_time);
5182 /* realize pipeline */
5183 ret = __mmplayer_gst_realize(player);
5184 if (ret != MM_ERROR_NONE)
5185 LOGE("fail to realize the player.");
5187 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5195 _mmplayer_unrealize(MMHandleType hplayer)
5197 mmplayer_t *player = (mmplayer_t *)hplayer;
5198 int ret = MM_ERROR_NONE;
5199 int rm_ret = MM_ERROR_NONE;
5200 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5204 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5206 MMPLAYER_CMD_UNLOCK(player);
5207 _mmplayer_bus_watcher_remove(player);
5208 /* destroy the gst bus msg thread which is created during realize.
5209 this funct have to be called before getting cmd lock. */
5210 _mmplayer_bus_msg_thread_destroy(player);
5211 MMPLAYER_CMD_LOCK(player);
5213 /* check current state */
5214 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5216 /* check async state transition */
5217 __mmplayer_check_async_state_transition(player);
5219 /* unrealize pipeline */
5220 ret = __mmplayer_gst_unrealize(player);
5222 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5223 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5224 if (rm_ret != MM_ERROR_NONE)
5225 LOGE("failed to release [%d] resources", res_idx);
5228 player->interrupted_by_resource = FALSE;
5235 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5237 mmplayer_t *player = (mmplayer_t *)hplayer;
5239 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5241 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5245 _mmplayer_get_state(MMHandleType hplayer, int *state)
5247 mmplayer_t *player = (mmplayer_t *)hplayer;
5249 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5251 *state = MMPLAYER_CURRENT_STATE(player);
5253 return MM_ERROR_NONE;
5257 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5259 GstElement *vol_element = NULL;
5260 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5263 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5264 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5266 /* check pipeline handle */
5267 if (!player->pipeline || !player->pipeline->audiobin) {
5268 LOGD("'%s' will be applied when audiobin is created", prop_name);
5270 /* NOTE : stored value will be used in create_audiobin
5271 * returning MM_ERROR_NONE here makes application to able to
5272 * set audio volume or mute at anytime.
5274 return MM_ERROR_NONE;
5277 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5278 volume_elem_id = MMPLAYER_A_SINK;
5280 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5282 LOGE("failed to get vol element %d", volume_elem_id);
5283 return MM_ERROR_PLAYER_INTERNAL;
5286 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5288 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5289 LOGE("there is no '%s' property", prop_name);
5290 return MM_ERROR_PLAYER_INTERNAL;
5293 if (!strcmp(prop_name, "volume")) {
5294 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5295 } else if (!strcmp(prop_name, "mute")) {
5296 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5298 LOGE("invalid property %s", prop_name);
5299 return MM_ERROR_PLAYER_INTERNAL;
5302 return MM_ERROR_NONE;
5306 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5308 int ret = MM_ERROR_NONE;
5309 mmplayer_t *player = (mmplayer_t *)hplayer;
5312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5314 LOGD("volume = %f", volume);
5316 /* invalid factor range or not */
5317 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5318 LOGE("Invalid volume value");
5319 return MM_ERROR_INVALID_ARGUMENT;
5322 player->sound.volume = volume;
5324 ret = __mmplayer_gst_set_volume_property(player, "volume");
5331 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5333 mmplayer_t *player = (mmplayer_t *)hplayer;
5337 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5338 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5340 *volume = player->sound.volume;
5342 LOGD("current vol = %f", *volume);
5345 return MM_ERROR_NONE;
5349 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5351 int ret = MM_ERROR_NONE;
5352 mmplayer_t *player = (mmplayer_t *)hplayer;
5355 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5357 LOGD("mute = %d", mute);
5359 player->sound.mute = mute;
5361 ret = __mmplayer_gst_set_volume_property(player, "mute");
5368 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5370 mmplayer_t *player = (mmplayer_t *)hplayer;
5374 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5375 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5377 *mute = player->sound.mute;
5379 LOGD("current mute = %d", *mute);
5383 return MM_ERROR_NONE;
5387 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5389 mmplayer_t *player = (mmplayer_t *)hplayer;
5393 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5395 player->audio_stream_changed_cb = callback;
5396 player->audio_stream_changed_cb_user_param = user_param;
5397 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5401 return MM_ERROR_NONE;
5405 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5407 mmplayer_t *player = (mmplayer_t *)hplayer;
5411 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5413 player->audio_decoded_cb = callback;
5414 player->audio_decoded_cb_user_param = user_param;
5415 player->audio_extract_opt = opt;
5416 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5420 return MM_ERROR_NONE;
5424 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5426 mmplayer_t *player = (mmplayer_t *)hplayer;
5430 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5432 if (callback && !player->bufmgr)
5433 player->bufmgr = tbm_bufmgr_init(-1);
5435 player->set_mode.video_export = (callback) ? true : false;
5436 player->video_decoded_cb = callback;
5437 player->video_decoded_cb_user_param = user_param;
5439 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5443 return MM_ERROR_NONE;
5447 _mmplayer_start(MMHandleType hplayer)
5449 mmplayer_t *player = (mmplayer_t *)hplayer;
5450 gint ret = MM_ERROR_NONE;
5454 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5456 /* check current state */
5457 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5459 /* start pipeline */
5460 ret = _mmplayer_gst_start(player);
5461 if (ret != MM_ERROR_NONE)
5462 LOGE("failed to start player.");
5464 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5465 LOGD("force playing start even during buffering");
5466 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5474 /* NOTE: post "not supported codec message" to application
5475 * when one codec is not found during AUTOPLUGGING in MSL.
5476 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5477 * And, if any codec is not found, don't send message here.
5478 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5481 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5483 MMMessageParamType msg_param;
5484 memset(&msg_param, 0, sizeof(MMMessageParamType));
5485 gboolean post_msg_direct = FALSE;
5489 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5491 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5492 player->not_supported_codec, player->can_support_codec);
5494 if (player->not_found_demuxer) {
5495 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5496 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5498 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5499 MMPLAYER_FREEIF(msg_param.data);
5501 return MM_ERROR_NONE;
5504 if (player->not_supported_codec) {
5505 if (player->can_support_codec) {
5506 // There is one codec to play
5507 post_msg_direct = TRUE;
5509 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5510 post_msg_direct = TRUE;
5513 if (post_msg_direct) {
5514 MMMessageParamType msg_param;
5515 memset(&msg_param, 0, sizeof(MMMessageParamType));
5517 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5518 LOGW("not found AUDIO codec, posting error code to application.");
5520 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5521 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5522 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5523 LOGW("not found VIDEO codec, posting error code to application.");
5525 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5526 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5529 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5531 MMPLAYER_FREEIF(msg_param.data);
5533 return MM_ERROR_NONE;
5535 // no any supported codec case
5536 LOGW("not found any codec, posting error code to application.");
5538 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5539 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5540 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5542 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5543 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5546 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5548 MMPLAYER_FREEIF(msg_param.data);
5554 return MM_ERROR_NONE;
5557 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5559 GstState element_state = GST_STATE_VOID_PENDING;
5560 GstState element_pending_state = GST_STATE_VOID_PENDING;
5561 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5562 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5564 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5566 MMPLAYER_RECONFIGURE_LOCK(player);
5567 if (!player->gapless.reconfigure) {
5568 MMPLAYER_RECONFIGURE_UNLOCK(player);
5572 LOGI("reconfigure is under process");
5573 MMPLAYER_RECONFIGURE_WAIT(player);
5574 MMPLAYER_RECONFIGURE_UNLOCK(player);
5575 LOGI("reconfigure is completed.");
5577 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5578 &element_state, &element_pending_state, timeout * GST_SECOND);
5579 if (result == GST_STATE_CHANGE_FAILURE)
5580 LOGW("failed to get pipeline state in %d sec", timeout);
5585 /* NOTE : it should be able to call 'stop' anytime*/
5587 _mmplayer_stop(MMHandleType hplayer)
5589 mmplayer_t *player = (mmplayer_t *)hplayer;
5590 int ret = MM_ERROR_NONE;
5594 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5596 /* check current state */
5597 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5599 /* need to wait till the rebuilding pipeline is completed */
5600 __mmplayer_check_pipeline_reconfigure_state(player);
5601 MMPLAYER_RECONFIGURE_LOCK(player);
5602 __mmplayer_reset_gapless_state(player);
5603 MMPLAYER_RECONFIGURE_UNLOCK(player);
5605 /* NOTE : application should not wait for EOS after calling STOP */
5606 _mmplayer_cancel_eos_timer(player);
5609 player->seek_state = MMPLAYER_SEEK_NONE;
5612 ret = _mmplayer_gst_stop(player);
5614 if (ret != MM_ERROR_NONE)
5615 LOGE("failed to stop player.");
5623 _mmplayer_pause(MMHandleType hplayer)
5625 mmplayer_t *player = (mmplayer_t *)hplayer;
5626 gint64 pos_nsec = 0;
5627 gboolean async = FALSE;
5628 gint ret = MM_ERROR_NONE;
5632 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5634 /* check current state */
5635 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5637 /* check pipeline reconfigure state */
5638 __mmplayer_check_pipeline_reconfigure_state(player);
5640 switch (MMPLAYER_CURRENT_STATE(player)) {
5641 case MM_PLAYER_STATE_READY:
5643 /* check prepare async or not.
5644 * In the case of streaming playback, it's recommended to avoid blocking wait.
5646 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5647 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5649 /* Changing back sync of rtspsrc to async */
5650 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5651 LOGD("async prepare working mode for rtsp");
5657 case MM_PLAYER_STATE_PLAYING:
5659 /* NOTE : store current point to overcome some bad operation
5660 *(returning zero when getting current position in paused state) of some
5663 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5664 LOGW("getting current position failed in paused");
5666 player->last_position = pos_nsec;
5668 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5669 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5670 This causes problem is position calculation during normal pause resume scenarios also.
5671 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5672 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5673 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5674 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5680 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5681 LOGD("doing async pause in case of ms buff src");
5685 /* pause pipeline */
5686 ret = _mmplayer_gst_pause(player, async);
5687 if (ret != MM_ERROR_NONE) {
5688 LOGE("failed to pause player. ret : 0x%x", ret);
5689 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5693 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5694 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5695 LOGE("failed to update display_rotation");
5699 return MM_ERROR_NONE;
5702 /* in case of streaming, pause could take long time.*/
5704 _mmplayer_abort_pause(MMHandleType hplayer)
5706 mmplayer_t *player = (mmplayer_t *)hplayer;
5707 int ret = MM_ERROR_NONE;
5711 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5713 player->pipeline->mainbin,
5714 MM_ERROR_PLAYER_NOT_INITIALIZED);
5716 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5717 LOGD("set the videobin state to READY");
5718 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5719 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5723 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5724 LOGD("set the audiobin state to READY");
5725 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5726 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5730 LOGD("set the pipeline state to READY");
5731 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5732 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5734 if (ret != MM_ERROR_NONE) {
5735 LOGE("fail to change state to READY");
5736 return MM_ERROR_PLAYER_INTERNAL;
5739 LOGD("succeeded in changing state to READY");
5744 _mmplayer_resume(MMHandleType hplayer)
5746 mmplayer_t *player = (mmplayer_t *)hplayer;
5747 int ret = MM_ERROR_NONE;
5748 gboolean async = FALSE;
5752 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5754 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5755 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5756 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5760 /* Changing back sync mode rtspsrc to async */
5761 LOGD("async resume for rtsp case");
5765 /* check current state */
5766 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5768 ret = _mmplayer_gst_resume(player, async);
5769 if (ret != MM_ERROR_NONE)
5770 LOGE("failed to resume player.");
5772 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5773 LOGD("force resume even during buffering");
5774 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5783 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5785 mmplayer_t *player = (mmplayer_t *)hplayer;
5786 gint64 pos_nsec = 0;
5787 int ret = MM_ERROR_NONE;
5789 signed long long start = 0, stop = 0;
5790 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5793 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5794 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5796 /* The sound of video is not supported under 0.0 and over 2.0. */
5797 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5798 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5801 _mmplayer_set_mute(hplayer, mute);
5803 if (player->playback_rate == rate)
5804 return MM_ERROR_NONE;
5806 /* If the position is reached at start potion during fast backward, EOS is posted.
5807 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5809 player->playback_rate = rate;
5811 current_state = MMPLAYER_CURRENT_STATE(player);
5813 if (current_state != MM_PLAYER_STATE_PAUSED)
5814 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5816 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5818 if ((current_state == MM_PLAYER_STATE_PAUSED)
5819 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5820 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5821 pos_nsec = player->last_position;
5826 stop = GST_CLOCK_TIME_NONE;
5828 start = GST_CLOCK_TIME_NONE;
5832 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5833 player->playback_rate,
5835 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5836 GST_SEEK_TYPE_SET, start,
5837 GST_SEEK_TYPE_SET, stop)) {
5838 LOGE("failed to set speed playback");
5839 return MM_ERROR_PLAYER_SEEK;
5842 LOGD("succeeded to set speed playback as %0.1f", rate);
5846 return MM_ERROR_NONE;;
5850 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5852 mmplayer_t *player = (mmplayer_t *)hplayer;
5853 int ret = MM_ERROR_NONE;
5857 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5859 /* check pipeline reconfigure state */
5860 __mmplayer_check_pipeline_reconfigure_state(player);
5862 ret = _mmplayer_gst_set_position(player, position, FALSE);
5870 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5872 mmplayer_t *player = (mmplayer_t *)hplayer;
5873 int ret = MM_ERROR_NONE;
5875 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5876 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5878 if (g_strrstr(player->type, "video/mpegts"))
5879 __mmplayer_update_duration_value(player);
5881 *duration = player->duration;
5886 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5888 mmplayer_t *player = (mmplayer_t *)hplayer;
5889 int ret = MM_ERROR_NONE;
5891 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5893 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5899 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5901 mmplayer_t *player = (mmplayer_t *)hplayer;
5902 int ret = MM_ERROR_NONE;
5906 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5908 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5916 __mmplayer_is_midi_type(gchar *str_caps)
5918 if ((g_strrstr(str_caps, "audio/midi")) ||
5919 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5920 (g_strrstr(str_caps, "application/x-smaf")) ||
5921 (g_strrstr(str_caps, "audio/x-imelody")) ||
5922 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5923 (g_strrstr(str_caps, "audio/xmf")) ||
5924 (g_strrstr(str_caps, "audio/mxmf"))) {
5933 __mmplayer_is_only_mp3_type(gchar *str_caps)
5935 if (g_strrstr(str_caps, "application/x-id3") ||
5936 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5942 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5944 GstStructure *caps_structure = NULL;
5945 gint samplerate = 0;
5949 MMPLAYER_RETURN_IF_FAIL(player && caps);
5951 caps_structure = gst_caps_get_structure(caps, 0);
5953 /* set stream information */
5954 gst_structure_get_int(caps_structure, "rate", &samplerate);
5955 gst_structure_get_int(caps_structure, "channels", &channels);
5957 mm_player_set_attribute((MMHandleType)player, NULL,
5958 "content_audio_samplerate", samplerate,
5959 "content_audio_channels", channels, NULL);
5961 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5965 __mmplayer_update_content_type_info(mmplayer_t *player)
5968 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5970 if (__mmplayer_is_midi_type(player->type)) {
5971 player->bypass_audio_effect = TRUE;
5975 if (!player->streamer) {
5976 LOGD("no need to check streaming type");
5980 if (g_strrstr(player->type, "application/x-hls")) {
5981 /* If it can't know exact type when it parses uri because of redirection case,
5982 * it will be fixed by typefinder or when doing autoplugging.
5984 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5985 player->streamer->is_adaptive_streaming = TRUE;
5986 } else if (g_strrstr(player->type, "application/dash+xml")) {
5987 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5988 player->streamer->is_adaptive_streaming = TRUE;
5991 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5992 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5993 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5995 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5996 if (player->streamer->is_adaptive_streaming)
5997 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5999 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6003 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6008 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6009 GstCaps *caps, gpointer data)
6011 mmplayer_t *player = (mmplayer_t *)data;
6015 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6017 /* store type string */
6018 if (player->type_caps) {
6019 gst_caps_unref(player->type_caps);
6020 player->type_caps = NULL;
6023 player->type_caps = gst_caps_copy(caps);
6024 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
6026 MMPLAYER_FREEIF(player->type);
6027 player->type = gst_caps_to_string(caps);
6029 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6030 player, player->type, probability, gst_caps_get_size(caps));
6032 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6033 (g_strrstr(player->type, "audio/x-raw-int"))) {
6034 LOGE("not support media format");
6036 if (player->msg_posted == FALSE) {
6037 MMMessageParamType msg_param;
6038 memset(&msg_param, 0, sizeof(MMMessageParamType));
6040 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6041 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6043 /* don't post more if one was sent already */
6044 player->msg_posted = TRUE;
6049 __mmplayer_update_content_type_info(player);
6051 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6054 pad = gst_element_get_static_pad(tf, "src");
6056 LOGE("fail to get typefind src pad.");
6060 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6061 gboolean async = FALSE;
6062 LOGE("failed to autoplug %s", player->type);
6064 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6066 if (async && player->msg_posted == FALSE)
6067 __mmplayer_handle_missed_plugin(player);
6069 gst_object_unref(GST_OBJECT(pad));
6076 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6078 GstElement *decodebin = NULL;
6082 /* create decodebin */
6083 decodebin = gst_element_factory_make("decodebin", NULL);
6086 LOGE("fail to create decodebin");
6090 /* raw pad handling signal */
6091 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6092 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6094 /* no-more-pad pad handling signal */
6095 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6096 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6098 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6099 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6101 /* This signal is emitted when a pad for which there is no further possible
6102 decoding is added to the decodebin.*/
6103 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6104 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6106 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6107 before looking for any elements that can handle that stream.*/
6108 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6109 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6111 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6112 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6113 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6115 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6116 before looking for any elements that can handle that stream.*/
6117 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6118 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6120 /* This signal is emitted once decodebin has finished decoding all the data.*/
6121 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6122 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6124 /* This signal is emitted when a element is added to the bin.*/
6125 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6126 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6133 __mmplayer_gst_make_queue2(mmplayer_t *player)
6135 GstElement *queue2 = NULL;
6136 gint64 dur_bytes = 0L;
6137 mmplayer_gst_element_t *mainbin = NULL;
6138 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6141 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6143 mainbin = player->pipeline->mainbin;
6145 queue2 = gst_element_factory_make("queue2", "queue2");
6147 LOGE("failed to create buffering queue element");
6151 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6152 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6154 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6156 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6157 * skip the pull mode(file or ring buffering) setting. */
6158 if (dur_bytes > 0) {
6159 if (!g_strrstr(player->type, "video/mpegts")) {
6160 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6161 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6167 _mm_player_streaming_set_queue2(player->streamer,
6171 (guint64)dur_bytes); /* no meaning at the moment */
6177 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6179 mmplayer_gst_element_t *mainbin = NULL;
6180 GstElement *decodebin = NULL;
6181 GstElement *queue2 = NULL;
6182 GstPad *sinkpad = NULL;
6183 GstPad *qsrcpad = NULL;
6186 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6188 mainbin = player->pipeline->mainbin;
6190 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6192 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6193 LOGW("need to check: muxed buffer is not null");
6196 queue2 = __mmplayer_gst_make_queue2(player);
6198 LOGE("failed to make queue2");
6202 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6203 LOGE("failed to add buffering queue");
6207 sinkpad = gst_element_get_static_pad(queue2, "sink");
6208 qsrcpad = gst_element_get_static_pad(queue2, "src");
6210 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6211 LOGE("failed to link [%s:%s]-[%s:%s]",
6212 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6216 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6217 LOGE("failed to sync queue2 state with parent");
6221 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6222 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6226 gst_object_unref(GST_OBJECT(sinkpad));
6230 /* create decodebin */
6231 decodebin = _mmplayer_gst_make_decodebin(player);
6233 LOGE("failed to make decodebin");
6237 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6238 LOGE("failed to add decodebin");
6242 /* to force caps on the decodebin element and avoid reparsing stuff by
6243 * typefind. It also avoids a deadlock in the way typefind activates pads in
6244 * the state change */
6245 g_object_set(decodebin, "sink-caps", caps, NULL);
6247 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6249 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6250 LOGE("failed to link [%s:%s]-[%s:%s]",
6251 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6255 gst_object_unref(GST_OBJECT(sinkpad));
6257 gst_object_unref(GST_OBJECT(qsrcpad));
6260 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6261 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6263 /* set decodebin property about buffer in streaming playback. *
6264 * in case of HLS/DASH, it does not need to have big buffer *
6265 * because it is kind of adaptive streaming. */
6266 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6267 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6268 gint high_percent = 0;
6270 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6271 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6273 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6275 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6277 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6278 "high-percent", high_percent,
6279 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6280 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6281 "max-size-buffers", 0, NULL); // disable or automatic
6284 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6285 LOGE("failed to sync decodebin state with parent");
6296 gst_object_unref(GST_OBJECT(sinkpad));
6299 gst_object_unref(GST_OBJECT(qsrcpad));
6302 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6303 * You need to explicitly set elements to the NULL state before
6304 * dropping the final reference, to allow them to clean up.
6306 gst_element_set_state(queue2, GST_STATE_NULL);
6308 /* And, it still has a parent "player".
6309 * You need to let the parent manage the object instead of unreffing the object directly.
6311 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6312 gst_object_unref(queue2);
6317 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6318 * You need to explicitly set elements to the NULL state before
6319 * dropping the final reference, to allow them to clean up.
6321 gst_element_set_state(decodebin, GST_STATE_NULL);
6323 /* And, it still has a parent "player".
6324 * You need to let the parent manage the object instead of unreffing the object directly.
6327 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6328 gst_object_unref(decodebin);
6336 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6340 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6341 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6343 LOGD("class : %s, mime : %s", factory_class, mime);
6345 /* add missing plugin */
6346 /* NOTE : msl should check missing plugin for image mime type.
6347 * Some motion jpeg clips can have playable audio track.
6348 * So, msl have to play audio after displaying popup written video format not supported.
6350 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6351 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6352 LOGD("not found demuxer");
6353 player->not_found_demuxer = TRUE;
6354 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6360 if (!g_strrstr(factory_class, "Demuxer")) {
6361 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6362 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6363 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6365 /* check that clip have multi tracks or not */
6366 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6367 LOGD("video plugin is already linked");
6369 LOGW("add VIDEO to missing plugin");
6370 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6371 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6373 } else if (g_str_has_prefix(mime, "audio")) {
6374 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6375 LOGD("audio plugin is already linked");
6377 LOGW("add AUDIO to missing plugin");
6378 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6379 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6387 return MM_ERROR_NONE;
6391 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6393 mmplayer_t *player = (mmplayer_t *)data;
6397 MMPLAYER_RETURN_IF_FAIL(player);
6399 /* remove fakesink. */
6400 if (!_mmplayer_gst_remove_fakesink(player,
6401 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6402 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6403 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6404 * source element are not same. To overcome this situation, this function will called
6405 * several places and several times. Therefore, this is not an error case.
6410 LOGD("[handle: %p] pipeline has completely constructed", player);
6412 if ((player->msg_posted == FALSE) &&
6413 (player->cmd >= MMPLAYER_COMMAND_START))
6414 __mmplayer_handle_missed_plugin(player);
6416 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6420 __mmplayer_check_profile(void)
6423 static int profile_tv = -1;
6425 if (__builtin_expect(profile_tv != -1, 1))
6428 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6429 switch (*profileName) {
6444 __mmplayer_get_next_uri(mmplayer_t *player)
6446 mmplayer_parse_profile_t profile;
6448 guint num_of_list = 0;
6451 num_of_list = g_list_length(player->uri_info.uri_list);
6452 uri_idx = player->uri_info.uri_idx;
6454 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6455 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6456 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6458 LOGW("next uri does not exist");
6462 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6463 LOGE("failed to parse profile");
6467 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6468 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6469 LOGW("uri type is not supported(%d)", profile.uri_type);
6473 LOGD("success to find next uri %d", uri_idx);
6477 if (!uri || uri_idx == num_of_list) {
6478 LOGE("failed to find next uri");
6482 player->uri_info.uri_idx = uri_idx;
6483 if (mm_player_set_attribute((MMHandleType)player, NULL,
6484 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6485 LOGE("failed to set attribute");
6489 SECURE_LOGD("next playback uri: %s", uri);
6494 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6496 #define REPEAT_COUNT_INFINITE -1
6497 #define REPEAT_COUNT_MIN 2
6498 #define ORIGINAL_URI_ONLY 1
6500 MMHandleType attrs = 0;
6504 guint num_of_uri = 0;
6505 int profile_tv = -1;
6509 LOGD("checking for gapless play option");
6511 if (player->build_audio_offload) {
6512 LOGE("offload path is not supportable.");
6516 if (player->pipeline->textbin) {
6517 LOGE("subtitle path is enabled. gapless play is not supported.");
6521 attrs = MMPLAYER_GET_ATTRS(player);
6523 LOGE("fail to get attributes.");
6527 mm_attrs_multiple_get(player->attrs, NULL,
6528 "content_video_found", &video,
6529 "profile_play_count", &count,
6530 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6532 /* gapless playback is not supported in case of video at TV profile. */
6533 profile_tv = __mmplayer_check_profile();
6534 if (profile_tv && video) {
6535 LOGW("not support video gapless playback");
6539 /* check repeat count in case of audio */
6541 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6542 LOGW("gapless is disabled");
6546 num_of_uri = g_list_length(player->uri_info.uri_list);
6548 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6550 if (num_of_uri == ORIGINAL_URI_ONLY) {
6551 /* audio looping path */
6552 if (count >= REPEAT_COUNT_MIN) {
6553 /* decrease play count */
6554 /* we succeeded to rewind. update play count and then wait for next EOS */
6556 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6557 } else if (count != REPEAT_COUNT_INFINITE) {
6558 LOGD("there is no next uri and no repeat");
6561 LOGD("looping cnt %d", count);
6563 /* gapless playback path */
6564 if (!__mmplayer_get_next_uri(player)) {
6565 LOGE("failed to get next uri");
6572 LOGE("unable to play gapless path. EOS will be posted soon");
6577 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6579 GstPad *sinkpad = g_value_get_object (item);
6580 GstElement *element = GST_ELEMENT(user_data);
6581 if (!sinkpad || !element) {
6582 LOGE("invalid parameter");
6586 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6587 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6591 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6593 mmplayer_gst_element_t *sinkbin = NULL;
6594 main_element_id_e concatId = MMPLAYER_M_NUM;
6595 main_element_id_e sinkId = MMPLAYER_M_NUM;
6596 gboolean send_notice = FALSE;
6597 GstElement *element;
6601 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6603 LOGD("type %d", type);
6606 case MM_PLAYER_TRACK_TYPE_AUDIO:
6607 concatId = MMPLAYER_M_A_CONCAT;
6608 sinkId = MMPLAYER_A_BIN;
6609 sinkbin = player->pipeline->audiobin;
6611 case MM_PLAYER_TRACK_TYPE_VIDEO:
6612 concatId = MMPLAYER_M_V_CONCAT;
6613 sinkId = MMPLAYER_V_BIN;
6614 sinkbin = player->pipeline->videobin;
6617 case MM_PLAYER_TRACK_TYPE_TEXT:
6618 concatId = MMPLAYER_M_T_CONCAT;
6619 sinkId = MMPLAYER_T_BIN;
6620 sinkbin = player->pipeline->textbin;
6623 LOGE("requested type is not supportable");
6628 element = player->pipeline->mainbin[concatId].gst;
6632 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6633 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6634 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6635 if (srcpad && sinkpad) {
6636 /* after getting drained signal there is no data flows, so no need to do pad_block */
6637 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6638 gst_pad_unlink(srcpad, sinkpad);
6640 /* send custom event to sink pad to handle it at video sink */
6642 LOGD("send custom event to sinkpad");
6643 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6644 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6645 gst_pad_send_event(sinkpad, event);
6648 gst_object_unref(srcpad);
6649 gst_object_unref(sinkpad);
6652 LOGD("release concat request pad");
6653 /* release and unref requests pad from the selector */
6654 iter = gst_element_iterate_sink_pads(element);
6655 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6656 gst_iterator_resync(iter);
6657 gst_iterator_free(iter);
6663 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6665 mmplayer_track_t *selector = &player->track[type];
6666 mmplayer_gst_element_t *sinkbin = NULL;
6667 main_element_id_e selectorId = MMPLAYER_M_NUM;
6668 main_element_id_e sinkId = MMPLAYER_M_NUM;
6669 GstPad *srcpad = NULL;
6670 GstPad *sinkpad = NULL;
6671 gboolean send_notice = FALSE;
6674 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6676 LOGD("type %d", type);
6679 case MM_PLAYER_TRACK_TYPE_AUDIO:
6680 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6681 sinkId = MMPLAYER_A_BIN;
6682 sinkbin = player->pipeline->audiobin;
6684 case MM_PLAYER_TRACK_TYPE_VIDEO:
6685 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6686 sinkId = MMPLAYER_V_BIN;
6687 sinkbin = player->pipeline->videobin;
6690 case MM_PLAYER_TRACK_TYPE_TEXT:
6691 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6692 sinkId = MMPLAYER_T_BIN;
6693 sinkbin = player->pipeline->textbin;
6696 LOGE("requested type is not supportable");
6701 if (player->pipeline->mainbin[selectorId].gst) {
6704 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6706 if (selector->event_probe_id != 0)
6707 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6708 selector->event_probe_id = 0;
6710 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6711 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6713 if (srcpad && sinkpad) {
6714 /* after getting drained signal there is no data flows, so no need to do pad_block */
6715 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6716 gst_pad_unlink(srcpad, sinkpad);
6718 /* send custom event to sink pad to handle it at video sink */
6720 LOGD("send custom event to sinkpad");
6721 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6722 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6723 gst_pad_send_event(sinkpad, event);
6727 gst_object_unref(sinkpad);
6730 gst_object_unref(srcpad);
6733 LOGD("selector release");
6735 /* release and unref requests pad from the selector */
6736 for (n = 0; n < selector->streams->len; n++) {
6737 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6738 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6741 g_ptr_array_set_size(selector->streams, 0);
6743 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6744 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6746 player->pipeline->mainbin[selectorId].gst = NULL;
6754 __mmplayer_deactivate_old_path(mmplayer_t *player)
6757 MMPLAYER_RETURN_IF_FAIL(player);
6759 if (MMPLAYER_USE_DECODEBIN(player)) {
6760 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6761 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6762 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6763 LOGE("deactivate selector error");
6767 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6768 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6769 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6770 LOGE("deactivate concat error");
6775 _mmplayer_track_destroy(player);
6776 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6778 if (player->streamer) {
6779 _mm_player_streaming_initialize(player->streamer, FALSE);
6780 _mm_player_streaming_destroy(player->streamer);
6781 player->streamer = NULL;
6784 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6790 if (!player->msg_posted) {
6791 MMMessageParamType msg = {0,};
6794 msg.code = MM_ERROR_PLAYER_INTERNAL;
6795 LOGE("gapless_uri_play> deactivate error");
6797 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6798 player->msg_posted = TRUE;
6804 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6806 int result = MM_ERROR_NONE;
6807 mmplayer_t *player = (mmplayer_t *)hplayer;
6810 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6811 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6813 if (mm_player_set_attribute(hplayer, NULL,
6814 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6815 LOGE("failed to set attribute");
6816 result = MM_ERROR_PLAYER_INTERNAL;
6818 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6819 LOGE("failed to add the original uri in the uri list.");
6827 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6829 mmplayer_t *player = (mmplayer_t *)hplayer;
6830 guint num_of_list = 0;
6834 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6835 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6837 if (player->pipeline && player->pipeline->textbin) {
6838 LOGE("subtitle path is enabled.");
6839 return MM_ERROR_PLAYER_INVALID_STATE;
6842 num_of_list = g_list_length(player->uri_info.uri_list);
6844 if (is_first_path) {
6845 if (num_of_list == 0) {
6846 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6847 SECURE_LOGD("add original path : %s", uri);
6849 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6850 player->uri_info.uri_list = g_list_prepend(
6851 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6852 SECURE_LOGD("change original path : %s", uri);
6855 MMHandleType attrs = 0;
6856 attrs = MMPLAYER_GET_ATTRS(player);
6858 if (num_of_list == 0) {
6859 char *original_uri = NULL;
6862 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6864 if (!original_uri) {
6865 LOGE("there is no original uri.");
6866 return MM_ERROR_PLAYER_INVALID_STATE;
6869 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6870 player->uri_info.uri_idx = 0;
6872 SECURE_LOGD("add original path at first : %s", original_uri);
6876 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6877 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6881 return MM_ERROR_NONE;
6885 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6887 mmplayer_t *player = (mmplayer_t *)hplayer;
6888 char *next_uri = NULL;
6889 guint num_of_list = 0;
6892 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6894 num_of_list = g_list_length(player->uri_info.uri_list);
6896 if (num_of_list > 0) {
6897 gint uri_idx = player->uri_info.uri_idx;
6899 if (uri_idx < num_of_list - 1)
6904 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6905 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6907 *uri = g_strdup(next_uri);
6911 return MM_ERROR_NONE;
6915 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6916 GstCaps *caps, gpointer data)
6918 mmplayer_t *player = (mmplayer_t *)data;
6919 const gchar *klass = NULL;
6920 const gchar *mime = NULL;
6921 gchar *caps_str = NULL;
6923 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6924 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6925 caps_str = gst_caps_to_string(caps);
6927 LOGW("unknown type of caps : %s from %s",
6928 caps_str, GST_ELEMENT_NAME(elem));
6930 MMPLAYER_FREEIF(caps_str);
6932 /* There is no available codec. */
6933 __mmplayer_check_not_supported_codec(player, klass, mime);
6937 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6938 GstCaps *caps, gpointer data)
6940 mmplayer_t *player = (mmplayer_t *)data;
6941 const char *mime = NULL;
6942 gboolean ret = TRUE;
6944 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6945 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6947 if (g_str_has_prefix(mime, "audio")) {
6948 GstStructure *caps_structure = NULL;
6949 gint samplerate = 0;
6951 gchar *caps_str = NULL;
6953 caps_structure = gst_caps_get_structure(caps, 0);
6954 gst_structure_get_int(caps_structure, "rate", &samplerate);
6955 gst_structure_get_int(caps_structure, "channels", &channels);
6957 if ((channels > 0 && samplerate == 0)) {
6958 LOGD("exclude audio...");
6962 caps_str = gst_caps_to_string(caps);
6963 /* set it directly because not sent by TAG */
6964 if (g_strrstr(caps_str, "mobile-xmf"))
6965 mm_player_set_attribute((MMHandleType)player, NULL,
6966 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6968 MMPLAYER_FREEIF(caps_str);
6969 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6970 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
6971 LOGD("video is already linked, allow the stream switch");
6974 LOGD("video is already linked");
6978 LOGD("found new stream");
6985 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6987 gboolean ret = FALSE;
6988 GDBusConnection *conn = NULL;
6990 GVariant *result = NULL;
6991 const gchar *dbus_device_type = NULL;
6992 const gchar *dbus_ret = NULL;
6995 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6997 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7002 result = g_dbus_connection_call_sync(conn,
7003 "org.pulseaudio.Server",
7004 "/org/pulseaudio/StreamManager",
7005 "org.pulseaudio.StreamManager",
7006 "GetCurrentMediaRoutingPath",
7007 g_variant_new("(s)", "out"),
7008 G_VARIANT_TYPE("(ss)"),
7009 G_DBUS_CALL_FLAGS_NONE,
7013 if (!result || err) {
7014 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7019 /* device type is listed in stream-map.json at mmfw-sysconf */
7020 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7022 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7023 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7026 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7027 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7028 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7029 LOGD("audio offload is supportable");
7035 LOGD("audio offload is not supportable");
7038 g_variant_unref(result);
7040 g_object_unref(conn);
7045 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7047 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7048 gint64 position = 0;
7050 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7051 player->pipeline && player->pipeline->mainbin);
7053 MMPLAYER_CMD_LOCK(player);
7054 current_state = MMPLAYER_CURRENT_STATE(player);
7056 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7057 LOGW("getting current position failed in paused");
7059 _mmplayer_unrealize((MMHandleType)player);
7060 _mmplayer_realize((MMHandleType)player);
7062 _mmplayer_set_position((MMHandleType)player, position);
7064 /* async not to be blocked in streaming case */
7065 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7067 _mmplayer_pause((MMHandleType)player);
7069 if (current_state == MM_PLAYER_STATE_PLAYING)
7070 _mmplayer_start((MMHandleType)player);
7071 MMPLAYER_CMD_UNLOCK(player);
7073 LOGD("rebuilding audio pipeline is completed.");
7076 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7078 mmplayer_t *player = (mmplayer_t *)user_data;
7079 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7080 gboolean is_supportable = FALSE;
7082 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7083 LOGW("failed to get device type");
7085 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7087 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7088 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7089 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7090 LOGD("ignore this dev connected info");
7094 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7095 if (player->build_audio_offload == is_supportable) {
7096 LOGD("keep current pipeline without re-building");
7100 /* rebuild pipeline */
7101 LOGD("re-build pipeline - offload: %d", is_supportable);
7102 player->build_audio_offload = FALSE;
7103 __mmplayer_rebuild_audio_pipeline(player);
7109 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7111 unsigned int id = 0;
7113 if (player->audio_device_cb_id != 0) {
7114 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7118 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7119 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7120 LOGD("added device connected cb (%u)", id);
7121 player->audio_device_cb_id = id;
7123 LOGW("failed to add device connected cb");
7130 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7132 mmplayer_t *player = (mmplayer_t *)hplayer;
7135 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7136 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7138 *activated = player->build_audio_offload;
7140 LOGD("offload activated : %d", (int)*activated);
7143 return MM_ERROR_NONE;
7147 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7150 this function need to be updated according to the supported media format
7151 @see player->ini.audio_offload_media_format */
7153 if (__mmplayer_is_only_mp3_type(player->type)) {
7154 LOGD("offload supportable media format type");
7162 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7164 gboolean ret = FALSE;
7165 GstElementFactory *factory = NULL;
7168 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7170 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7171 if (!__mmplayer_is_offload_supported_type(player))
7174 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7175 LOGD("there is no audio offload sink");
7179 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7180 LOGW("there is no audio device type to support offload");
7184 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7186 LOGW("there is no installed audio offload sink element");
7189 gst_object_unref(factory);
7191 if (_mmplayer_acquire_hw_resource(player,
7192 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7193 LOGE("failed to acquire audio offload decoder resource");
7197 if (!__mmplayer_add_audio_device_connected_cb(player))
7200 if (!__mmplayer_is_audio_offload_device_type(player))
7203 LOGD("audio offload can be built");
7208 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7214 static GstAutoplugSelectResult
7215 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7217 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7218 int audio_offload = 0;
7220 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7221 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7223 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7224 LOGD("expose audio path to build offload output path");
7225 player->build_audio_offload = TRUE;
7226 /* update codec info */
7227 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7228 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7229 player->audiodec_linked = 1;
7231 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7235 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7236 And need to consider the multi-track audio content.
7237 There is no HW audio decoder in public. */
7239 /* set stream information */
7240 if (!player->audiodec_linked)
7241 _mmplayer_set_audio_attrs(player, caps);
7243 /* update codec info */
7244 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7245 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7246 player->audiodec_linked = 1;
7248 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7250 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7251 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7253 /* mark video decoder for acquire */
7254 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7255 LOGW("video decoder resource is already acquired, skip it.");
7256 ret = GST_AUTOPLUG_SELECT_SKIP;
7260 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7261 LOGE("failed to acquire video decoder resource");
7262 ret = GST_AUTOPLUG_SELECT_SKIP;
7265 player->interrupted_by_resource = FALSE;
7268 /* update codec info */
7269 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7270 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7271 player->videodec_linked = 1;
7279 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7280 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7282 #define DEFAULT_IDX 0xFFFF
7283 #define MIN_FACTORY_NUM 2
7284 mmplayer_t *player = (mmplayer_t *)data;
7285 GValueArray *new_factories = NULL;
7286 GValue val = { 0, };
7287 GstElementFactory *factory = NULL;
7288 const gchar *klass = NULL;
7289 gchar *factory_name = NULL;
7290 guint hw_dec_idx = DEFAULT_IDX;
7291 guint first_sw_dec_idx = DEFAULT_IDX;
7292 guint last_sw_dec_idx = DEFAULT_IDX;
7293 guint new_pos = DEFAULT_IDX;
7294 guint rm_pos = DEFAULT_IDX;
7295 int audio_codec_type;
7296 int video_codec_type;
7297 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7299 if (factories->n_values < MIN_FACTORY_NUM)
7302 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7303 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7306 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7308 for (int i = 0 ; i < factories->n_values ; i++) {
7309 gchar *hw_dec_info = NULL;
7310 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7312 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7314 LOGW("failed to get factory object");
7317 klass = gst_element_factory_get_klass(factory);
7318 factory_name = GST_OBJECT_NAME(factory);
7321 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7323 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7324 if (!player->need_audio_dec_sorting) {
7325 LOGD("sorting is not required");
7328 codec_type = audio_codec_type;
7329 hw_dec_info = player->ini.audiocodec_element_hw;
7330 sw_dec_info = player->ini.audiocodec_element_sw;
7331 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7332 if (!player->need_video_dec_sorting) {
7333 LOGD("sorting is not required");
7336 codec_type = video_codec_type;
7337 hw_dec_info = player->ini.videocodec_element_hw;
7338 sw_dec_info = player->ini.videocodec_element_sw;
7343 if (g_strrstr(factory_name, hw_dec_info)) {
7346 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7347 if (strstr(factory_name, sw_dec_info[j])) {
7348 last_sw_dec_idx = i;
7349 if (first_sw_dec_idx == DEFAULT_IDX) {
7350 first_sw_dec_idx = i;
7355 if (first_sw_dec_idx == DEFAULT_IDX)
7356 LOGW("unknown codec %s", factory_name);
7360 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7363 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7364 if (hw_dec_idx < first_sw_dec_idx)
7366 new_pos = first_sw_dec_idx;
7367 rm_pos = hw_dec_idx + 1;
7368 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7369 if (last_sw_dec_idx < hw_dec_idx)
7371 new_pos = last_sw_dec_idx + 1;
7372 rm_pos = hw_dec_idx;
7377 /* change position - insert H/W decoder according to the new position */
7378 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7380 LOGW("failed to get factory object");
7383 new_factories = g_value_array_copy(factories);
7384 g_value_init (&val, G_TYPE_OBJECT);
7385 g_value_set_object (&val, factory);
7386 g_value_array_insert(new_factories, new_pos, &val);
7387 g_value_unset (&val);
7388 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7390 for (int i = 0 ; i < new_factories->n_values ; i++) {
7391 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7393 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7394 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7396 LOGE("[Re-arranged] failed to get factory object");
7399 return new_factories;
7403 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7404 GstCaps *caps, GstElementFactory *factory, gpointer data)
7406 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7407 mmplayer_t *player = (mmplayer_t *)data;
7409 gchar *factory_name = NULL;
7410 gchar *caps_str = NULL;
7411 const gchar *klass = NULL;
7414 factory_name = GST_OBJECT_NAME(factory);
7415 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7416 caps_str = gst_caps_to_string(caps);
7418 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7420 /* store type string */
7421 if (player->type == NULL) {
7422 player->type = gst_caps_to_string(caps);
7423 __mmplayer_update_content_type_info(player);
7426 /* filtering exclude keyword */
7427 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7428 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7429 LOGW("skipping [%s] by exclude keyword [%s]",
7430 factory_name, player->ini.exclude_element_keyword[idx]);
7432 result = GST_AUTOPLUG_SELECT_SKIP;
7437 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7438 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7439 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7440 factory_name, player->ini.unsupported_codec_keyword[idx]);
7441 result = GST_AUTOPLUG_SELECT_SKIP;
7446 /* exclude webm format */
7447 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7448 * because webm format is not supportable.
7449 * If webm is disabled in "autoplug-continue", there is no state change
7450 * failure or error because the decodebin will expose the pad directly.
7451 * It make MSL invoke _prepare_async_callback.
7452 * So, we need to disable webm format in "autoplug-select" */
7453 if (caps_str && strstr(caps_str, "webm")) {
7454 LOGW("webm is not supported");
7455 result = GST_AUTOPLUG_SELECT_SKIP;
7459 /* check factory class for filtering */
7460 /* NOTE : msl don't need to use image plugins.
7461 * So, those plugins should be skipped for error handling.
7463 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7464 LOGD("skipping [%s] by not required", factory_name);
7465 result = GST_AUTOPLUG_SELECT_SKIP;
7469 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7470 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7471 // TO CHECK : subtitle if needed, add subparse exception.
7472 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7473 result = GST_AUTOPLUG_SELECT_SKIP;
7477 if (g_strrstr(factory_name, "mpegpsdemux")) {
7478 LOGD("skipping PS container - not support");
7479 result = GST_AUTOPLUG_SELECT_SKIP;
7483 if (g_strrstr(factory_name, "mssdemux"))
7484 player->smooth_streaming = TRUE;
7486 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7487 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7490 GstStructure *str = NULL;
7491 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7493 /* don't make video because of not required */
7494 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7495 (!player->set_mode.video_export)) {
7496 LOGD("no need video decoding, expose pad");
7497 result = GST_AUTOPLUG_SELECT_EXPOSE;
7501 /* get w/h for omx state-tune */
7502 /* FIXME: deprecated? */
7503 str = gst_caps_get_structure(caps, 0);
7504 gst_structure_get_int(str, "width", &width);
7507 if (player->v_stream_caps) {
7508 gst_caps_unref(player->v_stream_caps);
7509 player->v_stream_caps = NULL;
7512 player->v_stream_caps = gst_caps_copy(caps);
7513 LOGD("take caps for video state tune");
7514 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7518 if (g_strrstr(klass, "Codec/Decoder")) {
7519 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7520 if (result != GST_AUTOPLUG_SELECT_TRY) {
7521 LOGW("skip add decoder");
7527 MMPLAYER_FREEIF(caps_str);
7533 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7536 int ret = MM_ERROR_NONE;
7537 mmplayer_t *player = (mmplayer_t *)data;
7538 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7539 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7540 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7543 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7545 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7547 if (MMPLAYER_USE_DECODEBIN(player))
7550 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7553 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7555 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7556 LOGE("failed to remove videobin");
7559 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7560 LOGE("failed to remove video concat");
7563 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL, FALSE, timeout);
7564 if (ret != MM_ERROR_NONE) {
7565 LOGE("fail to change state to NULL");
7569 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst, GST_STATE_NULL, FALSE, timeout);
7570 if (ret != MM_ERROR_NONE) {
7571 LOGE("fail to change state to NULL");
7575 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7576 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7577 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7579 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7580 MMPLAYER_FREEIF(player->pipeline->videobin);
7582 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7583 if (ret != MM_ERROR_NONE)
7584 LOGE("failed to release overlay resources");
7586 player->videodec_linked = 0;
7588 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7593 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7595 mmplayer_t *player = (mmplayer_t *)data;
7598 MMPLAYER_RETURN_IF_FAIL(player);
7600 LOGD("got about to finish signal");
7602 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7603 LOGW("Fail to get cmd lock");
7607 if (!__mmplayer_verify_gapless_play_path(player)) {
7608 LOGD("decoding is finished.");
7609 MMPLAYER_CMD_UNLOCK(player);
7613 _mmplayer_set_reconfigure_state(player, TRUE);
7614 MMPLAYER_CMD_UNLOCK(player);
7616 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7617 __mmplayer_deactivate_old_path(player);
7623 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7625 mmplayer_t *player = (mmplayer_t *)data;
7626 GstIterator *iter = NULL;
7627 GValue item = { 0, };
7629 gboolean done = FALSE;
7630 gboolean is_all_drained = TRUE;
7633 MMPLAYER_RETURN_IF_FAIL(player);
7635 LOGD("got drained signal");
7637 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7638 LOGW("Fail to get cmd lock");
7642 if (!__mmplayer_verify_gapless_play_path(player)) {
7643 LOGD("decoding is finished.");
7644 MMPLAYER_CMD_UNLOCK(player);
7648 _mmplayer_set_reconfigure_state(player, TRUE);
7649 MMPLAYER_CMD_UNLOCK(player);
7651 /* check decodebin src pads whether they received EOS or not */
7652 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7655 switch (gst_iterator_next(iter, &item)) {
7656 case GST_ITERATOR_OK:
7657 pad = g_value_get_object(&item);
7658 if (pad && !GST_PAD_IS_EOS(pad)) {
7659 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7660 is_all_drained = FALSE;
7663 g_value_reset(&item);
7665 case GST_ITERATOR_RESYNC:
7666 gst_iterator_resync(iter);
7668 case GST_ITERATOR_ERROR:
7669 case GST_ITERATOR_DONE:
7674 g_value_unset(&item);
7675 gst_iterator_free(iter);
7677 if (!is_all_drained) {
7678 LOGD("Wait util the all pads get EOS.");
7683 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7684 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7686 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7687 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7688 __mmplayer_deactivate_old_path(player);
7694 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7696 mmplayer_t *player = (mmplayer_t *)data;
7697 const gchar *klass = NULL;
7698 gchar *factory_name = NULL;
7700 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7701 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7703 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7705 if (__mmplayer_add_dump_buffer_probe(player, element))
7706 LOGD("add buffer probe");
7708 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7709 gchar *selected = NULL;
7710 selected = g_strdup(GST_ELEMENT_NAME(element));
7711 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7713 /* update codec info */
7714 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7715 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7716 player->audiodec_linked = 1;
7717 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7718 /* update codec info */
7719 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7720 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7721 player->videodec_linked = 1;
7724 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7725 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7726 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7728 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7729 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7731 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7732 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7733 "max-video-width", player->adaptive_info.limit.width,
7734 "max-video-height", player->adaptive_info.limit.height, NULL);
7736 } else if (g_strrstr(klass, "Demuxer")) {
7738 LOGD("plugged element is demuxer. take it");
7740 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7741 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7742 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7743 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7744 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7747 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7748 int surface_type = 0;
7750 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7753 // to support trust-zone only
7754 if (g_strrstr(factory_name, "asfdemux")) {
7755 LOGD("set file-location %s", player->profile.uri);
7756 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7757 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7758 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7759 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7760 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7761 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7762 (__mmplayer_is_only_mp3_type(player->type))) {
7763 LOGD("[mpegaudioparse] set streaming pull mode.");
7764 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7766 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7767 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7768 } else if (g_strrstr(factory_name, "omxdec_h264")) {
7769 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7770 if (video_parse && (g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7771 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7772 LOGD("Send SPS and PPS Insertion every IDR frame");
7776 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7777 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7778 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7780 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7781 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7783 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7784 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7785 (MMPLAYER_IS_DASH_STREAMING(player))) {
7786 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7787 _mm_player_streaming_set_multiqueue(player->streamer, element);
7788 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7797 __mmplayer_release_misc(mmplayer_t *player)
7800 bool cur_mode = player->set_mode.rich_audio;
7803 MMPLAYER_RETURN_IF_FAIL(player);
7805 player->sent_bos = FALSE;
7806 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7808 player->seek_state = MMPLAYER_SEEK_NONE;
7810 player->total_bitrate = 0;
7811 player->total_maximum_bitrate = 0;
7813 player->not_found_demuxer = 0;
7815 player->last_position = 0;
7816 player->duration = 0;
7817 player->http_content_size = 0;
7818 player->not_supported_codec = MISSING_PLUGIN_NONE;
7819 player->can_support_codec = FOUND_PLUGIN_NONE;
7820 player->pending_seek.is_pending = false;
7821 player->pending_seek.pos = 0;
7822 player->msg_posted = FALSE;
7823 player->has_many_types = FALSE;
7824 player->is_subtitle_force_drop = FALSE;
7825 player->play_subtitle = FALSE;
7826 player->adjust_subtitle_pos = 0;
7827 player->has_closed_caption = FALSE;
7828 player->set_mode.video_export = false;
7829 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7830 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7832 player->set_mode.rich_audio = cur_mode;
7834 if (player->audio_device_cb_id > 0 &&
7835 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7836 LOGW("failed to remove audio device_connected_callback");
7837 player->audio_device_cb_id = 0;
7839 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7840 player->bitrate[i] = 0;
7841 player->maximum_bitrate[i] = 0;
7844 /* free memory related to audio effect */
7845 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7847 if (player->adaptive_info.var_list) {
7848 g_list_free_full(player->adaptive_info.var_list, g_free);
7849 player->adaptive_info.var_list = NULL;
7852 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7853 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7854 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7856 /* Reset video360 settings to their defaults in case if the pipeline is to be
7859 player->video360_metadata.is_spherical = -1;
7860 player->is_openal_plugin_used = FALSE;
7862 player->is_content_spherical = FALSE;
7863 player->is_video360_enabled = TRUE;
7864 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7865 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7866 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7867 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7868 player->video360_zoom = 1.0f;
7869 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7870 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7872 player->sound.rg_enable = false;
7874 __mmplayer_initialize_video_roi(player);
7879 __mmplayer_release_misc_post(mmplayer_t *player)
7881 gchar *original_uri = NULL;
7884 /* player->pipeline is already released before. */
7885 MMPLAYER_RETURN_IF_FAIL(player);
7887 player->video_decoded_cb = NULL;
7888 player->video_decoded_cb_user_param = NULL;
7889 player->video_stream_prerolled = false;
7891 player->audio_decoded_cb = NULL;
7892 player->audio_decoded_cb_user_param = NULL;
7893 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7895 player->audio_stream_changed_cb = NULL;
7896 player->audio_stream_changed_cb_user_param = NULL;
7898 mm_player_set_attribute((MMHandleType)player, NULL,
7899 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7901 /* clean found audio decoders */
7902 if (player->audio_decoders) {
7903 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7904 player->audio_decoders = NULL;
7907 /* clean the uri list except original uri */
7908 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7910 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7911 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7912 g_list_free_full(tmp, (GDestroyNotify)g_free);
7915 LOGW("failed to get original uri info");
7917 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7918 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7919 MMPLAYER_FREEIF(original_uri);
7922 /* clear the audio stream buffer list */
7923 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7925 /* clear the video stream bo list */
7926 __mmplayer_video_stream_destroy_bo_list(player);
7927 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7929 if (player->profile.input_mem.buf) {
7930 free(player->profile.input_mem.buf);
7931 player->profile.input_mem.buf = NULL;
7933 player->profile.input_mem.len = 0;
7934 player->profile.input_mem.offset = 0;
7936 player->uri_info.uri_idx = 0;
7941 __mmplayer_check_subtitle(mmplayer_t *player)
7943 MMHandleType attrs = 0;
7944 char *subtitle_uri = NULL;
7948 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7950 /* get subtitle attribute */
7951 attrs = MMPLAYER_GET_ATTRS(player);
7955 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7956 if (!subtitle_uri || !strlen(subtitle_uri))
7959 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7960 player->is_external_subtitle_present = TRUE;
7968 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7970 MMPLAYER_RETURN_IF_FAIL(player);
7972 if (player->eos_timer) {
7973 LOGD("cancel eos timer");
7974 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7975 player->eos_timer = 0;
7982 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7986 MMPLAYER_RETURN_IF_FAIL(player);
7987 MMPLAYER_RETURN_IF_FAIL(sink);
7990 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7992 player->sink_elements = g_list_append(player->sink_elements, sink);
7998 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8002 MMPLAYER_RETURN_IF_FAIL(player);
8003 MMPLAYER_RETURN_IF_FAIL(sink);
8005 player->sink_elements = g_list_remove(player->sink_elements, sink);
8011 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8012 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8014 mmplayer_signal_item_t *item = NULL;
8017 MMPLAYER_RETURN_IF_FAIL(player);
8019 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8020 LOGE("invalid signal type [%d]", type);
8024 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8026 LOGE("cannot connect signal [%s]", signal);
8031 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8032 player->signals[type] = g_list_append(player->signals[type], item);
8038 /* NOTE : be careful with calling this api. please refer to below glib comment
8039 * glib comment : Note that there is a bug in GObject that makes this function much
8040 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8041 * will no longer be called, but, the signal handler is not currently disconnected.
8042 * If the instance is itself being freed at the same time than this doesn't matter,
8043 * since the signal will automatically be removed, but if instance persists,
8044 * then the signal handler will leak. You should not remove the signal yourself
8045 * because in a future versions of GObject, the handler will automatically be
8048 * It's possible to work around this problem in a way that will continue to work
8049 * with future versions of GObject by checking that the signal handler is still
8050 * connected before disconnected it:
8052 * if (g_signal_handler_is_connected(instance, id))
8053 * g_signal_handler_disconnect(instance, id);
8056 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8058 GList *sig_list = NULL;
8059 mmplayer_signal_item_t *item = NULL;
8063 MMPLAYER_RETURN_IF_FAIL(player);
8065 LOGD("release signals type : %d", type);
8067 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8068 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8069 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8070 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8071 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8072 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8076 sig_list = player->signals[type];
8078 for (; sig_list; sig_list = sig_list->next) {
8079 item = sig_list->data;
8081 if (item && item->obj) {
8082 if (g_signal_handler_is_connected(item->obj, item->sig))
8083 g_signal_handler_disconnect(item->obj, item->sig);
8086 MMPLAYER_FREEIF(item);
8089 g_list_free(player->signals[type]);
8090 player->signals[type] = NULL;
8098 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8100 mmplayer_t *player = 0;
8101 int prev_display_surface_type = 0;
8105 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8107 player = MM_PLAYER_CAST(handle);
8109 /* check video sinkbin is created */
8110 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8111 LOGW("Videosink is already created");
8112 return MM_ERROR_NONE;
8115 LOGD("videosink element is not yet ready");
8117 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8118 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8120 return MM_ERROR_INVALID_ARGUMENT;
8123 /* load previous attributes */
8124 if (player->attrs) {
8125 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8126 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8127 if (prev_display_surface_type == surface_type) {
8128 LOGD("incoming display surface type is same as previous one, do nothing..");
8130 return MM_ERROR_NONE;
8133 LOGE("failed to load attributes");
8135 return MM_ERROR_PLAYER_INTERNAL;
8138 /* videobin is not created yet, so we just set attributes related to display surface */
8139 LOGD("store display attribute for given surface type(%d)", surface_type);
8140 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8141 "display_overlay", wl_surface_id, NULL);
8144 return MM_ERROR_NONE;
8147 /* Note : if silent is true, then subtitle would not be displayed. :*/
8149 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8151 mmplayer_t *player = (mmplayer_t *)hplayer;
8155 /* check player handle */
8156 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8158 player->set_mode.subtitle_off = silent;
8160 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8164 return MM_ERROR_NONE;
8168 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8170 mmplayer_gst_element_t *mainbin = NULL;
8171 mmplayer_gst_element_t *textbin = NULL;
8172 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8173 GstState current_state = GST_STATE_VOID_PENDING;
8174 GstState element_state = GST_STATE_VOID_PENDING;
8175 GstState element_pending_state = GST_STATE_VOID_PENDING;
8177 GstEvent *event = NULL;
8178 int result = MM_ERROR_NONE;
8180 GstClock *curr_clock = NULL;
8181 GstClockTime base_time, start_time, curr_time;
8186 /* check player handle */
8187 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8189 player->pipeline->mainbin &&
8190 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8192 mainbin = player->pipeline->mainbin;
8193 textbin = player->pipeline->textbin;
8195 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8197 // sync clock with current pipeline
8198 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8199 curr_time = gst_clock_get_time(curr_clock);
8201 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8202 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8204 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8205 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8207 if (current_state > GST_STATE_READY) {
8208 // sync state with current pipeline
8209 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8210 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8211 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8213 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8214 if (GST_STATE_CHANGE_FAILURE == ret) {
8215 LOGE("fail to state change.");
8216 result = MM_ERROR_PLAYER_INTERNAL;
8220 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8221 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8224 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8225 gst_object_unref(curr_clock);
8228 // seek to current position
8229 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8230 result = MM_ERROR_PLAYER_INVALID_STATE;
8231 LOGE("gst_element_query_position failed, invalid state");
8235 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8236 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);
8238 _mmplayer_gst_send_event_to_sink(player, event);
8240 result = MM_ERROR_PLAYER_INTERNAL;
8241 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8245 /* sync state with current pipeline */
8246 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8247 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8248 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8250 return MM_ERROR_NONE;
8253 /* release text pipeline resource */
8254 player->textsink_linked = 0;
8256 /* release signal */
8257 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8259 /* release textbin with it's children */
8260 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8261 MMPLAYER_FREEIF(player->pipeline->textbin);
8262 player->pipeline->textbin = NULL;
8264 /* release subtitle elem */
8265 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8266 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8272 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8274 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8275 GstState current_state = GST_STATE_VOID_PENDING;
8277 MMHandleType attrs = 0;
8278 mmplayer_gst_element_t *mainbin = NULL;
8279 mmplayer_gst_element_t *textbin = NULL;
8281 gchar *subtitle_uri = NULL;
8282 int result = MM_ERROR_NONE;
8283 const gchar *charset = NULL;
8287 /* check player handle */
8288 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8290 player->pipeline->mainbin &&
8291 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8292 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8294 mainbin = player->pipeline->mainbin;
8295 textbin = player->pipeline->textbin;
8297 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8298 if (current_state < GST_STATE_READY) {
8299 result = MM_ERROR_PLAYER_INVALID_STATE;
8300 LOGE("Pipeline is not in proper state");
8304 attrs = MMPLAYER_GET_ATTRS(player);
8306 LOGE("cannot get content attribute");
8307 result = MM_ERROR_PLAYER_INTERNAL;
8311 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8312 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8313 LOGE("subtitle uri is not proper filepath");
8314 result = MM_ERROR_PLAYER_INVALID_URI;
8318 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8319 LOGE("failed to get storage info of subtitle path");
8320 result = MM_ERROR_PLAYER_INVALID_URI;
8324 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8325 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8327 if (!strcmp(filepath, subtitle_uri)) {
8328 LOGD("subtitle path is not changed");
8331 if (mm_player_set_attribute((MMHandleType)player, NULL,
8332 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8333 LOGE("failed to set attribute");
8338 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8339 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8340 player->subtitle_language_list = NULL;
8341 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8343 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8344 if (ret != GST_STATE_CHANGE_SUCCESS) {
8345 LOGE("failed to change state of textbin to READY");
8346 result = MM_ERROR_PLAYER_INTERNAL;
8350 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8351 if (ret != GST_STATE_CHANGE_SUCCESS) {
8352 LOGE("failed to change state of subparse to READY");
8353 result = MM_ERROR_PLAYER_INTERNAL;
8357 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8358 if (ret != GST_STATE_CHANGE_SUCCESS) {
8359 LOGE("failed to change state of filesrc to READY");
8360 result = MM_ERROR_PLAYER_INTERNAL;
8364 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8366 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8368 charset = _mmplayer_get_charset(filepath);
8370 LOGD("detected charset is %s", charset);
8371 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8374 result = _mmplayer_sync_subtitle_pipeline(player);
8381 /* API to switch between external subtitles */
8383 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8385 int result = MM_ERROR_NONE;
8386 mmplayer_t *player = (mmplayer_t *)hplayer;
8391 /* check player handle */
8392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8394 /* filepath can be null in idle state */
8396 /* check file path */
8397 if ((path = strstr(filepath, "file://")))
8398 result = _mmplayer_exist_file_path(path + 7);
8400 result = _mmplayer_exist_file_path(filepath);
8402 if (result != MM_ERROR_NONE) {
8403 LOGE("invalid subtitle path 0x%X", result);
8404 return result; /* file not found or permission denied */
8408 if (!player->pipeline) {
8410 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8411 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8412 LOGE("failed to set attribute");
8413 return MM_ERROR_PLAYER_INTERNAL;
8416 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8417 /* check filepath */
8418 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8420 if (!__mmplayer_check_subtitle(player)) {
8421 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8422 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8423 LOGE("failed to set attribute");
8424 return MM_ERROR_PLAYER_INTERNAL;
8427 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8428 LOGE("fail to create text pipeline");
8429 return MM_ERROR_PLAYER_INTERNAL;
8432 result = _mmplayer_sync_subtitle_pipeline(player);
8434 result = __mmplayer_change_external_subtitle_language(player, filepath);
8437 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8438 player->is_external_subtitle_added_now = TRUE;
8440 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8441 if (!player->subtitle_language_list) {
8442 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8443 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8444 LOGW("subtitle language list is not updated yet");
8446 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8454 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8456 guint active_idx = 0;
8457 GstStream *stream = NULL;
8458 GList *streams = NULL;
8459 GstCaps *caps = NULL;
8462 LOGD("Switching Streams... type: %d, index: %d", type, index);
8464 player->track[type].active_track_index = index;
8466 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8467 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8468 LOGD("track type:%d, total: %d, active: %d", i,
8469 player->track[i].total_track_num, player->track[i].active_track_index);
8470 if (player->track[i].total_track_num > 0 &&
8471 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8472 active_idx = player->track[i].active_track_index;
8473 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8474 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8475 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8477 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8478 caps = gst_stream_get_caps(stream);
8480 _mmplayer_set_audio_attrs(player, caps);
8481 gst_caps_unref(caps);
8488 LOGD("send select stream event");
8489 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8490 gst_event_new_select_streams(streams));
8491 g_list_free(streams);
8495 return MM_ERROR_NONE;
8499 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8501 int result = MM_ERROR_NONE;
8502 gchar *change_pad_name = NULL;
8503 GstPad *sinkpad = NULL;
8504 mmplayer_gst_element_t *mainbin = NULL;
8505 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8506 GstCaps *caps = NULL;
8507 gint total_track_num = 0;
8511 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8512 MM_ERROR_PLAYER_NOT_INITIALIZED);
8514 LOGD("Change Track(%d) to %d", type, index);
8516 mainbin = player->pipeline->mainbin;
8518 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8519 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8520 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8521 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8523 /* Changing Video Track is not supported. */
8524 LOGE("Track Type Error");
8528 if (mainbin[elem_idx].gst == NULL) {
8529 result = MM_ERROR_PLAYER_NO_OP;
8530 LOGD("Req track doesn't exist");
8534 total_track_num = player->track[type].total_track_num;
8535 if (total_track_num <= 0) {
8536 result = MM_ERROR_PLAYER_NO_OP;
8537 LOGD("Language list is not available");
8541 if ((index < 0) || (index >= total_track_num)) {
8542 result = MM_ERROR_INVALID_ARGUMENT;
8543 LOGD("Not a proper index : %d", index);
8547 /*To get the new pad from the selector*/
8548 change_pad_name = g_strdup_printf("sink_%u", index);
8549 if (change_pad_name == NULL) {
8550 result = MM_ERROR_PLAYER_INTERNAL;
8551 LOGD("Pad does not exists");
8555 LOGD("new active pad name: %s", change_pad_name);
8557 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8558 if (sinkpad == NULL) {
8559 LOGD("sinkpad is NULL");
8560 result = MM_ERROR_PLAYER_INTERNAL;
8564 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8565 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8567 caps = gst_pad_get_current_caps(sinkpad);
8568 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8571 gst_object_unref(sinkpad);
8573 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8574 _mmplayer_set_audio_attrs(player, caps);
8577 gst_caps_unref(caps);
8580 MMPLAYER_FREEIF(change_pad_name);
8585 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8587 int result = MM_ERROR_NONE;
8588 mmplayer_t *player = NULL;
8589 mmplayer_gst_element_t *mainbin = NULL;
8591 gint current_active_index = 0;
8593 GstState current_state = GST_STATE_VOID_PENDING;
8598 player = (mmplayer_t *)hplayer;
8599 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8601 if (!player->pipeline) {
8602 LOGE("Track %d pre setting -> %d", type, index);
8604 player->track[type].active_track_index = index;
8608 mainbin = player->pipeline->mainbin;
8610 current_active_index = player->track[type].active_track_index;
8612 /*If index is same as running index no need to change the pad*/
8613 if (current_active_index == index)
8616 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8617 result = MM_ERROR_PLAYER_INVALID_STATE;
8621 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8622 if (current_state < GST_STATE_PAUSED) {
8623 result = MM_ERROR_PLAYER_INVALID_STATE;
8624 LOGW("Pipeline not in proper state");
8628 if (MMPLAYER_USE_DECODEBIN(player))
8629 result = __mmplayer_change_selector_pad(player, type, index);
8631 result = __mmplayer_switch_stream(player, type, index);
8633 if (result != MM_ERROR_NONE) {
8634 LOGE("failed to change track");
8638 player->track[type].active_track_index = index;
8640 if (MMPLAYER_USE_DECODEBIN(player)) {
8641 GstEvent *event = NULL;
8642 if (current_state == GST_STATE_PLAYING) {
8643 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8644 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8645 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8647 _mmplayer_gst_send_event_to_sink(player, event);
8649 result = MM_ERROR_PLAYER_INTERNAL;
8660 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8662 mmplayer_t *player = (mmplayer_t *)hplayer;
8666 /* check player handle */
8667 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8669 *silent = player->set_mode.subtitle_off;
8671 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8675 return MM_ERROR_NONE;
8679 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8681 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8682 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8684 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8685 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8689 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8690 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8691 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8692 mmplayer_dump_t *dump_s;
8693 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8694 if (dump_s == NULL) {
8695 LOGE("malloc fail");
8699 dump_s->dump_element_file = NULL;
8700 dump_s->dump_pad = NULL;
8701 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8703 if (dump_s->dump_pad) {
8704 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8705 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]);
8706 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8707 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);
8708 /* add list for removed buffer probe and close FILE */
8709 player->dump_list = g_list_append(player->dump_list, dump_s);
8710 LOGD("%s sink pad added buffer probe for dump", factory_name);
8713 MMPLAYER_FREEIF(dump_s);
8714 LOGE("failed to get %s sink pad added", factory_name);
8721 static GstPadProbeReturn
8722 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8724 FILE *dump_data = (FILE *)u_data;
8726 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8727 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8729 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8731 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8733 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8735 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8737 gst_buffer_unmap(buffer, &probe_info);
8739 return GST_PAD_PROBE_OK;
8743 __mmplayer_release_dump_list(GList *dump_list)
8745 GList *d_list = dump_list;
8750 for (; d_list; d_list = g_list_next(d_list)) {
8751 mmplayer_dump_t *dump_s = d_list->data;
8752 if (dump_s->dump_pad) {
8753 if (dump_s->probe_handle_id)
8754 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8755 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8757 if (dump_s->dump_element_file) {
8758 fclose(dump_s->dump_element_file);
8759 dump_s->dump_element_file = NULL;
8761 MMPLAYER_FREEIF(dump_s);
8763 g_list_free(dump_list);
8768 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8770 mmplayer_t *player = (mmplayer_t *)hplayer;
8774 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8775 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8777 *exist = (bool)player->has_closed_caption;
8781 return MM_ERROR_NONE;
8785 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8790 LOGD("unref internal gst buffer %p", buffer);
8792 gst_buffer_unref((GstBuffer *)buffer);
8799 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8801 mmplayer_t *player = (mmplayer_t *)hplayer;
8805 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8806 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8808 if (MMPLAYER_IS_STREAMING(player))
8809 *timeout = (int)player->ini.live_state_change_timeout;
8811 *timeout = (int)player->ini.localplayback_state_change_timeout;
8813 LOGD("timeout = %d", *timeout);
8816 return MM_ERROR_NONE;
8820 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8824 MMPLAYER_RETURN_IF_FAIL(player);
8826 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8828 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8829 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8830 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8831 player->storage_info[i].id = -1;
8832 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8834 if (path_type != MMPLAYER_PATH_MAX)
8843 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8845 int ret = MM_ERROR_NONE;
8846 mmplayer_t *player = (mmplayer_t *)hplayer;
8847 MMMessageParamType msg_param = {0, };
8850 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8852 LOGW("state changed storage %d:%d", id, state);
8854 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8855 return MM_ERROR_NONE;
8857 /* FIXME: text path should be handled separately. */
8858 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8859 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8860 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8861 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8862 LOGW("external storage is removed");
8864 if (player->msg_posted == FALSE) {
8865 memset(&msg_param, 0, sizeof(MMMessageParamType));
8866 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8867 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8868 player->msg_posted = TRUE;
8871 /* unrealize the player */
8872 ret = _mmplayer_unrealize(hplayer);
8873 if (ret != MM_ERROR_NONE)
8874 LOGE("failed to unrealize");
8882 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8884 int ret = MM_ERROR_NONE;
8885 mmplayer_t *player = (mmplayer_t *)hplayer;
8886 int idx = 0, total = 0;
8887 gchar *result = NULL, *tmp = NULL;
8890 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8891 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8893 total = *num = g_list_length(player->adaptive_info.var_list);
8895 LOGW("There is no stream variant info.");
8899 result = g_strdup("");
8900 for (idx = 0 ; idx < total ; idx++) {
8901 stream_variant_t *v_data = NULL;
8902 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8905 gchar data[64] = {0};
8906 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8908 tmp = g_strconcat(result, data, NULL);
8912 LOGW("There is no variant data in %d", idx);
8917 *var_info = (char *)result;
8919 LOGD("variant info %d:%s", *num, *var_info);
8925 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8927 int ret = MM_ERROR_NONE;
8928 mmplayer_t *player = (mmplayer_t *)hplayer;
8931 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8933 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8935 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8936 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8937 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8939 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8940 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8941 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8942 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8944 /* FIXME: seek to current position for applying new variant limitation */
8953 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8955 int ret = MM_ERROR_NONE;
8956 mmplayer_t *player = (mmplayer_t *)hplayer;
8959 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8960 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8962 *bandwidth = player->adaptive_info.limit.bandwidth;
8963 *width = player->adaptive_info.limit.width;
8964 *height = player->adaptive_info.limit.height;
8966 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8973 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8975 int ret = MM_ERROR_NONE;
8976 mmplayer_t *player = (mmplayer_t *)hplayer;
8979 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8980 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8981 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8983 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8985 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8986 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8987 else /* live case */
8988 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8990 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8997 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8999 #define IDX_FIRST_SW_CODEC 0
9000 mmplayer_t *player = (mmplayer_t *)hplayer;
9001 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9002 const char *attr_name = NULL;
9003 const char *default_type = NULL;
9004 const char *element_hw = NULL;
9005 const char *element_sw = NULL;
9008 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9010 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9012 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9013 switch (stream_type) {
9014 case MM_PLAYER_STREAM_TYPE_AUDIO:
9015 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9016 default_type = player->ini.audiocodec_default_type;
9017 element_hw = player->ini.audiocodec_element_hw;
9018 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9020 case MM_PLAYER_STREAM_TYPE_VIDEO:
9021 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9022 default_type = player->ini.videocodec_default_type;
9023 element_hw = player->ini.videocodec_element_hw;
9024 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9027 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9028 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9032 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9034 if (!strcmp(default_type, "sw"))
9035 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9037 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9039 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9040 codec_type = default_codec_type;
9042 /* to support codec selection, codec info have to be added in ini file.
9043 in case of hw codec is selected, filter elements should be applied
9044 depending on the hw capabilities. */
9045 if (codec_type != default_codec_type) {
9046 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9047 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9048 LOGE("There is no codec for type %d", codec_type);
9049 return MM_ERROR_PLAYER_NO_OP;
9052 LOGD("sorting is required");
9053 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9054 player->need_audio_dec_sorting = TRUE;
9056 player->need_video_dec_sorting = TRUE;
9059 LOGD("update %s codec_type to %d", attr_name, codec_type);
9060 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9063 return MM_ERROR_NONE;
9067 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9069 mmplayer_t *player = (mmplayer_t *)hplayer;
9070 GstElement *rg_vol_element = NULL;
9074 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9076 player->sound.rg_enable = enabled;
9078 /* just hold rgvolume enable value if pipeline is not ready */
9079 if (!player->pipeline || !player->pipeline->audiobin) {
9080 LOGD("pipeline is not ready. holding rgvolume enable value");
9081 return MM_ERROR_NONE;
9084 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9086 if (!rg_vol_element) {
9087 LOGD("rgvolume element is not created");
9088 return MM_ERROR_PLAYER_INTERNAL;
9092 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9094 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9098 return MM_ERROR_NONE;
9102 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9104 mmplayer_t *player = (mmplayer_t *)hplayer;
9105 GstElement *rg_vol_element = NULL;
9106 gboolean enable = FALSE;
9110 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9111 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9113 /* just hold enable_rg value if pipeline is not ready */
9114 if (!player->pipeline || !player->pipeline->audiobin) {
9115 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9116 *enabled = player->sound.rg_enable;
9117 return MM_ERROR_NONE;
9120 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9122 if (!rg_vol_element) {
9123 LOGD("rgvolume element is not created");
9124 return MM_ERROR_PLAYER_INTERNAL;
9127 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9128 *enabled = (bool)enable;
9132 return MM_ERROR_NONE;
9136 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9138 mmplayer_t *player = (mmplayer_t *)hplayer;
9139 MMHandleType attrs = 0;
9141 int ret = MM_ERROR_NONE;
9145 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9147 attrs = MMPLAYER_GET_ATTRS(player);
9148 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9150 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9152 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9153 return MM_ERROR_PLAYER_INTERNAL;
9156 player->video_roi.scale_x = scale_x;
9157 player->video_roi.scale_y = scale_y;
9158 player->video_roi.scale_width = scale_width;
9159 player->video_roi.scale_height = scale_height;
9161 /* check video sinkbin is created */
9162 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9163 return MM_ERROR_NONE;
9165 if (!gst_video_overlay_set_video_roi_area(
9166 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9167 scale_x, scale_y, scale_width, scale_height))
9168 ret = MM_ERROR_PLAYER_INTERNAL;
9170 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9171 scale_x, scale_y, scale_width, scale_height);
9179 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9181 mmplayer_t *player = (mmplayer_t *)hplayer;
9182 int ret = MM_ERROR_NONE;
9186 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9187 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9189 *scale_x = player->video_roi.scale_x;
9190 *scale_y = player->video_roi.scale_y;
9191 *scale_width = player->video_roi.scale_width;
9192 *scale_height = player->video_roi.scale_height;
9194 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9195 *scale_x, *scale_y, *scale_width, *scale_height);
9201 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9203 mmplayer_t *player = (mmplayer_t *)hplayer;
9207 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9209 player->client_pid = pid;
9211 LOGD("client pid[%d] %p", pid, player);
9215 return MM_ERROR_NONE;
9219 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9221 mmplayer_t *player = (mmplayer_t *)hplayer;
9222 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9223 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9227 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9228 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9231 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9233 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9235 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9236 return MM_ERROR_NONE;
9238 /* in case of audio codec default type is HW */
9240 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9241 if (player->ini.support_audio_effect)
9242 return MM_ERROR_NONE;
9243 elem_id = MMPLAYER_A_FILTER;
9245 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9246 if (player->ini.support_replaygain_control)
9247 return MM_ERROR_NONE;
9248 elem_id = MMPLAYER_A_RGVOL;
9250 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9251 if (player->ini.support_pitch_control)
9252 return MM_ERROR_NONE;
9253 elem_id = MMPLAYER_A_PITCH;
9255 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9256 if (player->ini.support_audio_effect)
9257 return MM_ERROR_NONE;
9259 /* default case handling is not required */
9262 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9263 LOGW("audio control option [%d] is not available", opt);
9266 /* setting pcm exporting option is allowed before READY state */
9267 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9268 return MM_ERROR_PLAYER_INVALID_STATE;
9270 /* check whether the audio filter exist or not after READY state,
9271 because the sw codec could be added during auto-plugging in some cases */
9272 if (!player->pipeline ||
9273 !player->pipeline->audiobin ||
9274 !player->pipeline->audiobin[elem_id].gst) {
9275 LOGW("there is no audio elem [%d]", elem_id);
9280 LOGD("audio control opt %d, available %d", opt, *available);
9284 return MM_ERROR_NONE;
9288 __mmplayer_update_duration_value(mmplayer_t *player)
9290 gboolean ret = FALSE;
9291 gint64 dur_nsec = 0;
9292 LOGD("try to update duration");
9294 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9295 player->duration = dur_nsec;
9296 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9300 if (player->duration < 0) {
9301 LOGW("duration is Non-Initialized !!!");
9302 player->duration = 0;
9305 /* update streaming service type */
9306 player->streaming_type = _mmplayer_get_stream_service_type(player);
9308 /* check duration is OK */
9309 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9310 /* FIXIT : find another way to get duration here. */
9311 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9317 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9319 /* update audio params
9320 NOTE : We need original audio params and it can be only obtained from src pad of audio
9321 decoder. Below code only valid when we are not using 'resampler' just before
9322 'audioconverter'. */
9323 GstCaps *caps_a = NULL;
9325 gint samplerate = 0, channels = 0;
9326 GstStructure *p = NULL;
9327 GstElement *aconv = NULL;
9329 LOGD("try to update audio attrs");
9331 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9333 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9334 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9335 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9336 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9338 LOGE("there is no audio converter");
9342 pad = gst_element_get_static_pad(aconv, "sink");
9345 LOGW("failed to get pad from audio converter");
9349 caps_a = gst_pad_get_current_caps(pad);
9351 LOGW("not ready to get audio caps");
9352 gst_object_unref(pad);
9356 p = gst_caps_get_structure(caps_a, 0);
9357 gst_structure_get_int(p, "rate", &samplerate);
9358 gst_structure_get_int(p, "channels", &channels);
9360 mm_player_set_attribute((MMHandleType)player, NULL,
9361 "content_audio_samplerate", samplerate,
9362 "content_audio_channels", channels, NULL);
9364 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9366 gst_caps_unref(caps_a);
9367 gst_object_unref(pad);
9373 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9375 LOGD("try to update video attrs");
9377 GstCaps *caps_v = NULL;
9381 GstStructure *p = NULL;
9383 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9384 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9386 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9388 LOGD("no videosink sink pad");
9392 caps_v = gst_pad_get_current_caps(pad);
9393 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9394 if (!caps_v && player->v_stream_caps) {
9395 caps_v = player->v_stream_caps;
9396 gst_caps_ref(caps_v);
9400 LOGD("no negotiated caps from videosink");
9401 gst_object_unref(pad);
9405 p = gst_caps_get_structure(caps_v, 0);
9406 gst_structure_get_int(p, "width", &width);
9407 gst_structure_get_int(p, "height", &height);
9409 mm_player_set_attribute((MMHandleType)player, NULL,
9410 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9412 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9414 SECURE_LOGD("width : %d height : %d", width, height);
9416 gst_caps_unref(caps_v);
9417 gst_object_unref(pad);
9420 mm_player_set_attribute((MMHandleType)player, NULL,
9421 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9422 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9429 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9431 gboolean ret = FALSE;
9432 guint64 data_size = 0;
9436 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9437 if (!player->duration)
9440 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9441 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9442 if (stat(path, &sb) == 0)
9443 data_size = (guint64)sb.st_size;
9445 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9446 data_size = player->http_content_size;
9449 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9452 guint64 bitrate = 0;
9453 guint64 msec_dur = 0;
9455 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9457 bitrate = data_size * 8 * 1000 / msec_dur;
9458 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9459 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9460 mm_player_set_attribute((MMHandleType)player, NULL,
9461 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9464 LOGD("player duration is less than 0");
9468 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9469 if (player->total_bitrate) {
9470 mm_player_set_attribute((MMHandleType)player, NULL,
9471 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9480 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9482 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9483 data->uri_type = uri_type;
9487 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9489 int ret = MM_ERROR_PLAYER_INVALID_URI;
9491 char *buffer = NULL;
9492 char *seperator = strchr(path, ',');
9493 char ext[100] = {0,}, size[100] = {0,};
9496 if ((buffer = strstr(path, "ext="))) {
9497 buffer += strlen("ext=");
9499 if (strlen(buffer)) {
9500 strncpy(ext, buffer, 99);
9502 if ((seperator = strchr(ext, ','))
9503 || (seperator = strchr(ext, ' '))
9504 || (seperator = strchr(ext, '\0'))) {
9505 seperator[0] = '\0';
9510 if ((buffer = strstr(path, "size="))) {
9511 buffer += strlen("size=");
9513 if (strlen(buffer) > 0) {
9514 strncpy(size, buffer, 99);
9516 if ((seperator = strchr(size, ','))
9517 || (seperator = strchr(size, ' '))
9518 || (seperator = strchr(size, '\0'))) {
9519 seperator[0] = '\0';
9522 mem_size = atoi(size);
9527 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9529 if (mem_size && param) {
9530 if (data->input_mem.buf)
9531 free(data->input_mem.buf);
9532 data->input_mem.buf = malloc(mem_size);
9534 if (data->input_mem.buf) {
9535 memcpy(data->input_mem.buf, param, mem_size);
9536 data->input_mem.len = mem_size;
9537 ret = MM_ERROR_NONE;
9539 LOGE("failed to alloc mem %d", mem_size);
9540 ret = MM_ERROR_PLAYER_INTERNAL;
9543 data->input_mem.offset = 0;
9544 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9551 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9553 gchar *location = NULL;
9556 int ret = MM_ERROR_NONE;
9558 if ((path = strstr(uri, "file://"))) {
9559 location = g_filename_from_uri(uri, NULL, &err);
9560 if (!location || (err != NULL)) {
9561 LOGE("Invalid URI '%s' for filesrc: %s", path,
9562 (err != NULL) ? err->message : "unknown error");
9566 MMPLAYER_FREEIF(location);
9568 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9569 return MM_ERROR_PLAYER_INVALID_URI;
9571 LOGD("path from uri: %s", location);
9574 path = (location != NULL) ? (location) : ((char *)uri);
9577 ret = _mmplayer_exist_file_path(path);
9579 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9580 if (ret == MM_ERROR_NONE) {
9581 if (_mmplayer_is_sdp_file(path)) {
9582 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9583 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9584 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9586 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9587 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9589 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9590 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9592 LOGE("invalid uri, could not play..");
9593 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9596 MMPLAYER_FREEIF(location);
9601 static mmplayer_video_decoded_data_info_t *
9602 __mmplayer_create_stream_from_pad(GstPad *pad)
9604 GstCaps *caps = NULL;
9605 GstStructure *structure = NULL;
9606 unsigned int fourcc = 0;
9607 const gchar *string_format = NULL;
9608 mmplayer_video_decoded_data_info_t *stream = NULL;
9610 MMPixelFormatType format;
9613 caps = gst_pad_get_current_caps(pad);
9615 LOGE("Caps is NULL.");
9620 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9622 structure = gst_caps_get_structure(caps, 0);
9623 gst_structure_get_int(structure, "width", &width);
9624 gst_structure_get_int(structure, "height", &height);
9625 string_format = gst_structure_get_string(structure, "format");
9628 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9629 format = _mmplayer_get_pixtype(fourcc);
9630 gst_video_info_from_caps(&info, caps);
9631 gst_caps_unref(caps);
9634 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9635 LOGE("Wrong condition!!");
9639 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9641 LOGE("failed to alloc mem for video data");
9645 stream->width = width;
9646 stream->height = height;
9647 stream->format = format;
9648 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9654 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9656 unsigned int pitch = 0;
9657 unsigned int size = 0;
9659 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9662 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9663 bo = gst_tizen_memory_get_bos(mem, index);
9665 stream->bo[index] = tbm_bo_ref(bo);
9667 LOGE("failed to get bo for index %d", index);
9670 for (index = 0; index < stream->plane_num; index++) {
9671 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9672 stream->stride[index] = pitch;
9674 stream->elevation[index] = size / pitch;
9676 stream->elevation[index] = stream->height;
9681 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9683 if (stream->format == MM_PIXEL_FORMAT_I420) {
9684 int ret = TBM_SURFACE_ERROR_NONE;
9685 tbm_surface_h surface;
9686 tbm_surface_info_s info;
9688 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9690 ret = tbm_surface_get_info(surface, &info);
9691 if (ret != TBM_SURFACE_ERROR_NONE) {
9692 tbm_surface_destroy(surface);
9696 tbm_surface_destroy(surface);
9697 stream->stride[0] = info.planes[0].stride;
9698 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9699 stream->stride[1] = info.planes[1].stride;
9700 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9701 stream->stride[2] = info.planes[2].stride;
9702 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9703 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9704 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9705 stream->stride[0] = stream->width * 4;
9706 stream->elevation[0] = stream->height;
9707 stream->bo_size = stream->stride[0] * stream->height;
9709 LOGE("Not support format %d", stream->format);
9717 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9719 tbm_bo_handle thandle;
9721 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9722 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9723 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9727 unsigned char *src = NULL;
9728 unsigned char *dest = NULL;
9729 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9731 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9733 LOGE("fail to gst_memory_map");
9737 if (!mapinfo.data) {
9738 LOGE("data pointer is wrong");
9742 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9743 if (!stream->bo[0]) {
9744 LOGE("Fail to tbm_bo_alloc!!");
9748 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9750 LOGE("thandle pointer is wrong");
9754 if (stream->format == MM_PIXEL_FORMAT_I420) {
9755 src_stride[0] = GST_ROUND_UP_4(stream->width);
9756 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9757 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9758 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9761 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9762 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9764 for (i = 0; i < 3; i++) {
9765 src = mapinfo.data + src_offset[i];
9766 dest = thandle.ptr + dest_offset[i];
9771 for (j = 0; j < stream->height >> k; j++) {
9772 memcpy(dest, src, stream->width>>k);
9773 src += src_stride[i];
9774 dest += stream->stride[i];
9777 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9778 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9780 LOGE("Not support format %d", stream->format);
9784 tbm_bo_unmap(stream->bo[0]);
9785 gst_memory_unmap(mem, &mapinfo);
9791 tbm_bo_unmap(stream->bo[0]);
9794 gst_memory_unmap(mem, &mapinfo);
9800 __mmplayer_set_pause_state(mmplayer_t *player)
9802 if (player->sent_bos)
9805 /* rtsp case, get content attrs by GstMessage */
9806 if (MMPLAYER_IS_RTSP_STREAMING(player))
9809 /* it's first time to update all content attrs. */
9810 _mmplayer_update_content_attrs(player, ATTR_ALL);
9814 __mmplayer_set_playing_state(mmplayer_t *player)
9816 gchar *audio_codec = NULL;
9818 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9819 /* initialize because auto resume is done well. */
9820 player->resumed_by_rewind = FALSE;
9821 player->playback_rate = 1.0;
9824 if (player->sent_bos)
9827 /* try to get content metadata */
9829 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9830 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9831 * legacy mmfw-player api
9833 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9835 if ((player->cmd == MMPLAYER_COMMAND_START)
9836 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9837 __mmplayer_handle_missed_plugin(player);
9840 /* check audio codec field is set or not
9841 * we can get it from typefinder or codec's caps.
9843 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9845 /* The codec format can't be sent for audio only case like amr, mid etc.
9846 * Because, parser don't make related TAG.
9847 * So, if it's not set yet, fill it with found data.
9850 if (g_strrstr(player->type, "audio/midi"))
9851 audio_codec = "MIDI";
9852 else if (g_strrstr(player->type, "audio/x-amr"))
9853 audio_codec = "AMR";
9854 else if (g_strrstr(player->type, "audio/mpeg")
9855 && !g_strrstr(player->type, "mpegversion=(int)1"))
9856 audio_codec = "AAC";
9858 audio_codec = "unknown";
9860 if (mm_player_set_attribute((MMHandleType)player, NULL,
9861 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9862 LOGE("failed to set attribute");
9864 LOGD("set audio codec type with caps");