4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related function will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
143 static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
144 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void __mmplayer_release_misc(mmplayer_t *player);
150 static void __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
160 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
161 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
162 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
163 static gpointer __mmplayer_gapless_play_thread(gpointer data);
164 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
165 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_release_dump_list(GList *dump_list);
167 static int __mmplayer_gst_realize(mmplayer_t *player);
168 static int __mmplayer_gst_unrealize(mmplayer_t *player);
169 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
170 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
173 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
174 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
175 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
176 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
177 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
178 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
179 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
180 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
181 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
182 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
183 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
184 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
188 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
189 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
190 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
192 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
193 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
194 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
195 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
197 static void __mmplayer_set_pause_state(mmplayer_t *player);
198 static void __mmplayer_set_playing_state(mmplayer_t *player);
199 static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
200 /*===========================================================================================
202 | FUNCTION DEFINITIONS |
204 ========================================================================================== */
206 /* This function should be called after the pipeline goes PAUSED or higher
209 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
211 static gboolean has_duration = FALSE;
212 static gboolean has_video_attrs = FALSE;
213 static gboolean has_audio_attrs = FALSE;
214 static gboolean has_bitrate = FALSE;
215 gboolean missing_only = FALSE;
216 gboolean all = FALSE;
217 MMHandleType attrs = 0;
221 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
223 /* check player state here */
224 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
225 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
226 /* give warning now only */
227 LOGW("be careful. content attributes may not available in this state ");
230 /* get content attribute first */
231 attrs = MMPLAYER_GET_ATTRS(player);
233 LOGE("cannot get content attribute");
237 /* get update flag */
239 if (flag & ATTR_MISSING_ONLY) {
241 LOGD("updating missed attr only");
244 if (flag & ATTR_ALL) {
246 has_duration = FALSE;
247 has_video_attrs = FALSE;
248 has_audio_attrs = FALSE;
251 LOGD("updating all attrs");
254 if (missing_only && all) {
255 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
256 missing_only = FALSE;
259 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
260 has_duration = __mmplayer_update_duration_value(player);
262 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
263 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
265 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
266 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
268 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
269 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
277 _mmplayer_get_stream_service_type(mmplayer_t *player)
279 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
283 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
285 player->pipeline->mainbin &&
286 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
287 STREAMING_SERVICE_NONE);
289 /* streaming service type if streaming */
290 if (!MMPLAYER_IS_STREAMING(player))
291 return STREAMING_SERVICE_NONE;
293 streaming_type = (player->duration == 0) ?
294 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
296 switch (streaming_type) {
297 case STREAMING_SERVICE_LIVE:
298 LOGD("it's live streaming");
300 case STREAMING_SERVICE_VOD:
301 LOGD("it's vod streaming");
304 LOGE("should not get here");
310 return streaming_type;
313 /* this function sets the player state and also report
314 * it to application by calling callback function
317 _mmplayer_set_state(mmplayer_t *player, int state)
319 MMMessageParamType msg = {0, };
321 MMPLAYER_RETURN_IF_FAIL(player);
323 if (MMPLAYER_CURRENT_STATE(player) == state) {
324 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
325 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
329 /* update player states */
330 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
331 MMPLAYER_CURRENT_STATE(player) = state;
333 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
334 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
337 MMPLAYER_PRINT_STATE(player);
339 switch (MMPLAYER_CURRENT_STATE(player)) {
340 case MM_PLAYER_STATE_NULL:
341 case MM_PLAYER_STATE_READY:
343 case MM_PLAYER_STATE_PAUSED:
344 __mmplayer_set_pause_state(player);
346 case MM_PLAYER_STATE_PLAYING:
347 __mmplayer_set_playing_state(player);
349 case MM_PLAYER_STATE_NONE:
351 LOGW("invalid target state, there is nothing to do.");
356 /* post message to application */
357 if (MMPLAYER_TARGET_STATE(player) == state) {
358 /* fill the message with state of player */
359 msg.union_type = MM_MSG_UNION_STATE;
360 msg.state.previous = MMPLAYER_PREV_STATE(player);
361 msg.state.current = MMPLAYER_CURRENT_STATE(player);
363 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
365 /* state changed by resource callback */
366 if (player->interrupted_by_resource)
367 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
368 else /* state changed by usecase */
369 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
372 LOGD("intermediate state, do nothing.");
373 MMPLAYER_PRINT_STATE(player);
377 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
378 && !player->sent_bos) {
379 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
380 player->sent_bos = TRUE;
387 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
389 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
390 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
394 LOGD("incoming command : %d ", command);
396 current_state = MMPLAYER_CURRENT_STATE(player);
397 pending_state = MMPLAYER_PENDING_STATE(player);
399 MMPLAYER_PRINT_STATE(player);
402 case MMPLAYER_COMMAND_CREATE:
404 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
406 if (current_state == MM_PLAYER_STATE_NULL ||
407 current_state == MM_PLAYER_STATE_READY ||
408 current_state == MM_PLAYER_STATE_PAUSED ||
409 current_state == MM_PLAYER_STATE_PLAYING)
414 case MMPLAYER_COMMAND_DESTROY:
416 /* destroy can called anytime */
418 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
422 case MMPLAYER_COMMAND_REALIZE:
424 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
426 if (pending_state != MM_PLAYER_STATE_NONE) {
429 /* need ready state to realize */
430 if (current_state == MM_PLAYER_STATE_READY)
433 if (current_state != MM_PLAYER_STATE_NULL)
439 case MMPLAYER_COMMAND_UNREALIZE:
441 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
443 if (current_state == MM_PLAYER_STATE_NULL)
448 case MMPLAYER_COMMAND_START:
450 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
452 if (pending_state == MM_PLAYER_STATE_NONE) {
453 if (current_state == MM_PLAYER_STATE_PLAYING)
455 else if (current_state != MM_PLAYER_STATE_READY &&
456 current_state != MM_PLAYER_STATE_PAUSED)
458 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
460 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
461 LOGD("player is going to paused state, just change the pending state as playing");
468 case MMPLAYER_COMMAND_STOP:
470 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
472 if (current_state == MM_PLAYER_STATE_READY)
475 /* need playing/paused state to stop */
476 if (current_state != MM_PLAYER_STATE_PLAYING &&
477 current_state != MM_PLAYER_STATE_PAUSED)
482 case MMPLAYER_COMMAND_PAUSE:
484 if (MMPLAYER_IS_LIVE_STREAMING(player))
487 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
488 goto NOT_COMPLETED_SEEK;
490 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
492 if (pending_state == MM_PLAYER_STATE_NONE) {
493 if (current_state == MM_PLAYER_STATE_PAUSED)
495 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
497 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
499 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
500 if (current_state == MM_PLAYER_STATE_PAUSED)
501 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
508 case MMPLAYER_COMMAND_RESUME:
510 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
511 goto NOT_COMPLETED_SEEK;
513 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
515 if (pending_state == MM_PLAYER_STATE_NONE) {
516 if (current_state == MM_PLAYER_STATE_PLAYING)
518 else if (current_state != MM_PLAYER_STATE_PAUSED)
520 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
522 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
523 LOGD("player is going to paused state, just change the pending state as playing");
533 player->cmd = command;
535 return MM_ERROR_NONE;
538 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
539 MMPLAYER_STATE_GET_NAME(current_state), command);
540 return MM_ERROR_PLAYER_INVALID_STATE;
543 LOGW("not completed seek");
544 return MM_ERROR_PLAYER_DOING_SEEK;
547 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
548 return MM_ERROR_PLAYER_NO_OP;
551 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
552 return MM_ERROR_PLAYER_NO_OP;
555 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
557 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
558 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
561 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
562 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
564 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
565 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
567 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
568 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
571 LOGE("invalid mmplayer resource type %d", type);
572 return MM_ERROR_PLAYER_INTERNAL;
575 if (player->hw_resource[type] != NULL) {
576 LOGD("[%d type] resource was already acquired", type);
577 return MM_ERROR_NONE;
580 LOGD("mark for acquire [%d type] resource", type);
581 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
582 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
583 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
584 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
585 return MM_ERROR_PLAYER_INTERNAL;
588 LOGD("commit [%d type] resource", type);
589 rm_ret = mm_resource_manager_commit(player->resource_manager);
590 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
591 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
592 return MM_ERROR_PLAYER_INTERNAL;
596 return MM_ERROR_NONE;
599 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
601 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
603 MMPLAYER_RETURN_IF_FAIL(player);
604 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
606 rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
607 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
608 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
612 rm_ret = mm_resource_manager_commit(player->resource_manager);
613 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
614 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
617 /* de-initialize resource manager */
618 rm_ret = mm_resource_manager_destroy(player->resource_manager);
619 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
620 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
624 player->resource_manager = NULL;
626 LOGD("resource manager is destroyed");
629 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
631 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
635 if (player->hw_resource[type] == NULL) {
636 LOGD("there is no acquired [%d type] resource", type);
637 return MM_ERROR_NONE;
640 LOGD("mark for release [%d type] resource", type);
641 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
642 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
643 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
644 return MM_ERROR_PLAYER_INTERNAL;
647 player->hw_resource[type] = NULL;
649 LOGD("commit [%d type] resource", type);
650 rm_ret = mm_resource_manager_commit(player->resource_manager);
651 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
652 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
653 return MM_ERROR_PLAYER_INTERNAL;
657 return MM_ERROR_NONE;
661 __mmplayer_initialize_gapless_play(mmplayer_t *player)
667 player->smooth_streaming = FALSE;
668 player->videodec_linked = 0;
669 player->audiodec_linked = 0;
670 player->textsink_linked = 0;
671 player->is_external_subtitle_present = FALSE;
672 player->is_external_subtitle_added_now = FALSE;
673 player->not_supported_codec = MISSING_PLUGIN_NONE;
674 player->can_support_codec = FOUND_PLUGIN_NONE;
675 player->pending_seek.is_pending = false;
676 player->pending_seek.pos = 0;
677 player->msg_posted = FALSE;
678 player->has_many_types = FALSE;
679 player->no_more_pad = FALSE;
680 player->not_found_demuxer = 0;
681 player->seek_state = MMPLAYER_SEEK_NONE;
682 player->is_subtitle_force_drop = FALSE;
683 player->play_subtitle = FALSE;
684 player->adjust_subtitle_pos = 0;
686 player->total_bitrate = 0;
687 player->total_maximum_bitrate = 0;
689 _mmplayer_track_initialize(player);
690 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
692 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
693 player->bitrate[i] = 0;
694 player->maximum_bitrate[i] = 0;
697 if (player->v_stream_caps) {
698 gst_caps_unref(player->v_stream_caps);
699 player->v_stream_caps = NULL;
702 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
704 /* clean found audio decoders */
705 if (player->audio_decoders) {
706 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
707 player->audio_decoders = NULL;
710 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
715 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
717 LOGI("set pipeline reconfigure state %d", state);
718 MMPLAYER_RECONFIGURE_LOCK(player);
719 player->gapless.reconfigure = state;
720 if (!state) /* wake up the waiting job */
721 MMPLAYER_RECONFIGURE_SIGNAL(player);
722 MMPLAYER_RECONFIGURE_UNLOCK(player);
726 __mmplayer_gapless_play_thread(gpointer data)
728 mmplayer_t *player = (mmplayer_t *)data;
729 mmplayer_gst_element_t *mainbin = NULL;
731 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
733 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
734 while (!player->gapless_play_thread_exit) {
735 LOGD("gapless play thread started. waiting for signal.");
736 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
738 LOGD("reconfigure pipeline for gapless play.");
740 if (player->gapless_play_thread_exit) {
741 _mmplayer_set_reconfigure_state(player, FALSE);
742 LOGD("exiting gapless play thread");
746 mainbin = player->pipeline->mainbin;
748 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
749 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
752 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
754 /* Initialize Player values */
755 __mmplayer_initialize_gapless_play(player);
757 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
759 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
765 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
767 GSource *source = NULL;
771 source = g_main_context_find_source_by_id(context, source_id);
772 if (source != NULL) {
773 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
774 g_source_destroy(source);
781 _mmplayer_watcher_removed_notify(gpointer data)
783 mmplayer_t *player = (mmplayer_t *)data;
784 MMPLAYER_RETURN_IF_FAIL(player);
786 MMPLAYER_BUS_WATCHER_LOCK(player);
787 player->bus_watcher = 0;
788 MMPLAYER_BUS_WATCHER_SIGNAL(player);
789 MMPLAYER_BUS_WATCHER_UNLOCK(player);
793 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
795 mmplayer_t *player = (mmplayer_t *)hplayer;
798 MMPLAYER_RETURN_IF_FAIL(player);
800 /* disconnecting bus watch */
801 if (player->bus_watcher > 0) {
802 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
803 MMPLAYER_BUS_WATCHER_LOCK(player);
804 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
805 while (player->bus_watcher > 0) {
806 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
807 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
808 player->bus_watcher);
812 MMPLAYER_BUS_WATCHER_UNLOCK(player);
813 g_mutex_clear(&player->bus_watcher_mutex);
814 g_cond_clear(&player->bus_watcher_cond);
821 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
823 mmplayer_t *player = (mmplayer_t *)hplayer;
824 GstMessage *msg = NULL;
825 GQueue *queue = NULL;
828 MMPLAYER_RETURN_IF_FAIL(player);
830 /* destroy the gst bus msg thread */
831 if (player->bus_msg_thread) {
832 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
833 player->bus_msg_thread_exit = TRUE;
834 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
835 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
837 LOGD("gst bus msg thread exit.");
838 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
839 player->bus_msg_thread = NULL;
841 g_mutex_clear(&player->bus_msg_thread_mutex);
842 g_cond_clear(&player->bus_msg_thread_cond);
845 g_mutex_lock(&player->bus_msg_q_lock);
846 queue = player->bus_msg_q;
847 while (!g_queue_is_empty(queue)) {
848 msg = (GstMessage *)g_queue_pop_head(queue);
853 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
854 gst_message_unref(msg);
856 g_mutex_unlock(&player->bus_msg_q_lock);
862 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
864 GstElement *parent = NULL;
866 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
867 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
870 MMPLAYER_FSINK_LOCK(player);
872 /* get parent of fakesink */
873 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
875 LOGD("fakesink already removed");
879 gst_element_set_locked_state(fakesink->gst, TRUE);
881 /* setting the state to NULL never returns async
882 * so no need to wait for completion of state transition
884 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
885 LOGE("fakesink state change failure!");
886 /* FIXIT : should I return here? or try to proceed to next? */
889 /* remove fakesink from it's parent */
890 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
891 LOGE("failed to remove fakesink");
893 gst_object_unref(parent);
898 gst_object_unref(parent);
900 LOGD("state-holder removed");
902 gst_element_set_locked_state(fakesink->gst, FALSE);
904 MMPLAYER_FSINK_UNLOCK(player);
909 gst_element_set_locked_state(fakesink->gst, FALSE);
911 MMPLAYER_FSINK_UNLOCK(player);
915 static GstPadProbeReturn
916 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
918 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
919 return GST_PAD_PROBE_OK;
923 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
925 gint64 stop_running_time = 0;
926 gint64 position_running_time = 0;
930 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
931 if ((player->gapless.update_segment[idx] == TRUE) ||
932 !(player->track[idx].event_probe_id)) {
934 LOGW("[%d] skip", idx);
939 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
941 gst_segment_to_running_time(&player->gapless.segment[idx],
942 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
943 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
945 gst_segment_to_running_time(&player->gapless.segment[idx],
946 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
948 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
950 gst_segment_to_running_time(&player->gapless.segment[idx],
951 GST_FORMAT_TIME, player->duration);
954 position_running_time =
955 gst_segment_to_running_time(&player->gapless.segment[idx],
956 GST_FORMAT_TIME, player->gapless.segment[idx].position);
958 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
959 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
961 GST_TIME_ARGS(stop_running_time),
962 GST_TIME_ARGS(position_running_time),
963 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
964 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
966 position_running_time = MAX(position_running_time, stop_running_time);
967 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
968 GST_FORMAT_TIME, player->gapless.segment[idx].start);
969 position_running_time = MAX(0, position_running_time);
970 position = MAX(position, position_running_time);
974 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
975 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
976 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
978 player->gapless.start_time[stream_type] += position;
984 static GstPadProbeReturn
985 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
987 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
988 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
989 mmplayer_t *player = (mmplayer_t *)data;
990 GstCaps *caps = NULL;
991 GstStructure *str = NULL;
992 const gchar *name = NULL;
993 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
994 gboolean caps_ret = TRUE;
996 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
997 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
998 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
999 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1000 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1003 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1007 if (strstr(name, "audio")) {
1008 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1009 } else if (strstr(name, "video")) {
1010 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1012 /* text track is not supportable */
1013 LOGE("invalid name %s", name);
1017 switch (GST_EVENT_TYPE(event)) {
1020 /* in case of gapless, drop eos event not to send it to sink */
1021 if (player->gapless.reconfigure && !player->msg_posted) {
1022 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1023 ret = GST_PAD_PROBE_DROP;
1027 case GST_EVENT_STREAM_START:
1029 __mmplayer_gst_selector_update_start_time(player, stream_type);
1032 case GST_EVENT_FLUSH_STOP:
1034 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1035 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1036 player->gapless.start_time[stream_type] = 0;
1039 case GST_EVENT_SEGMENT:
1044 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1045 gst_event_copy_segment(event, &segment);
1047 if (segment.format != GST_FORMAT_TIME)
1050 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1051 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1052 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1053 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1054 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1055 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1057 /* keep the all the segment ev to cover the seeking */
1058 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1059 player->gapless.update_segment[stream_type] = TRUE;
1061 if (!player->gapless.running)
1064 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1066 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1068 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1069 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1070 gst_event_unref(event);
1071 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1077 gdouble proportion = 0.0;
1078 GstClockTimeDiff diff = 0;
1079 GstClockTime timestamp = 0;
1080 gint64 running_time_diff = -1;
1081 GstQOSType type = 0;
1082 GstEvent *tmpev = NULL;
1084 running_time_diff = player->gapless.segment[stream_type].base;
1086 if (running_time_diff <= 0) /* don't need to adjust */
1089 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1090 gst_event_unref(event);
1092 if (timestamp < running_time_diff) {
1093 LOGW("QOS event from previous group");
1094 ret = GST_PAD_PROBE_DROP;
1099 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1100 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1101 stream_type, GST_TIME_ARGS(timestamp),
1102 GST_TIME_ARGS(running_time_diff),
1103 GST_TIME_ARGS(timestamp - running_time_diff));
1106 timestamp -= running_time_diff;
1108 /* That case is invalid for QoS events */
1109 if (diff < 0 && -diff > timestamp) {
1110 LOGW("QOS event from previous group");
1111 ret = GST_PAD_PROBE_DROP;
1115 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1116 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1126 gst_caps_unref(caps);
1130 /* create fakesink for audio or video path without audiobin or videobin */
1132 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1134 GstElement *pipeline = NULL;
1135 GstElement *fakesink = NULL;
1136 GstPad *sinkpad = NULL;
1139 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1141 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1144 fakesink = gst_element_factory_make("fakesink", NULL);
1145 if (fakesink == NULL) {
1146 LOGE("failed to create fakesink");
1150 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1151 LOGE("failed to add fakesink to pipeline");
1156 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1158 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1160 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1161 LOGE("failed to link fakesink");
1165 if (strstr(name, "video")) {
1166 if (player->v_stream_caps) {
1167 gst_caps_unref(player->v_stream_caps);
1168 player->v_stream_caps = NULL;
1170 if (player->ini.set_dump_element_flag)
1171 __mmplayer_add_dump_buffer_probe(player, fakesink);
1174 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1175 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1177 /* store it as it's sink element */
1178 __mmplayer_add_sink(player, fakesink, FALSE);
1181 gst_object_unref(GST_OBJECT(sinkpad));
1189 gst_object_unref(GST_OBJECT(sinkpad));
1192 gst_element_set_state(fakesink, GST_STATE_NULL);
1194 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1195 gst_object_unref(GST_OBJECT(fakesink));
1202 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1204 GstElement *pipeline = NULL;
1205 GstElement *concat = NULL;
1208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1210 concat = gst_element_factory_make("concat", NULL);
1212 LOGE("failed to create concat");
1216 gst_element_set_state(concat, GST_STATE_PAUSED);
1218 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1219 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1220 LOGE("failed to add concat to pipeline");
1221 gst_element_set_state(concat, GST_STATE_NULL);
1222 gst_object_unref(GST_OBJECT(concat));
1226 LOGD("Create concat [%d] element", elem_idx);
1228 player->pipeline->mainbin[elem_idx].id = elem_idx;
1229 player->pipeline->mainbin[elem_idx].gst = concat;
1236 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1238 GstElement *pipeline = NULL;
1239 GstElement *selector = NULL;
1240 GstPad *srcpad = NULL;
1243 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1245 selector = gst_element_factory_make("input-selector", NULL);
1247 LOGE("failed to create input-selector");
1250 g_object_set(selector, "sync-streams", TRUE, NULL);
1252 srcpad = gst_element_get_static_pad(selector, "src");
1254 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1255 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1256 __mmplayer_gst_selector_blocked, NULL, NULL);
1257 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1258 __mmplayer_gst_selector_event_probe, player, NULL);
1260 gst_element_set_state(selector, GST_STATE_PAUSED);
1262 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1263 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1264 LOGE("failed to add selector to pipeline");
1266 if (player->track[stream_type].block_id != 0)
1267 gst_pad_remove_probe (srcpad, player->track[stream_type].block_id);
1268 player->track[stream_type].block_id = 0;
1270 if (player->track[stream_type].event_probe_id != 0)
1271 gst_pad_remove_probe (srcpad, player->track[stream_type].event_probe_id);
1272 player->track[stream_type].event_probe_id = 0;
1274 gst_object_unref(GST_OBJECT(srcpad));
1276 gst_element_set_state(selector, GST_STATE_NULL);
1277 gst_object_unref(GST_OBJECT(selector));
1281 gst_object_unref(GST_OBJECT(srcpad));
1283 player->pipeline->mainbin[elem_idx].id = elem_idx;
1284 player->pipeline->mainbin[elem_idx].gst = selector;
1291 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1293 mmplayer_t *player = (mmplayer_t *)data;
1294 GstElement *combiner = NULL;
1295 GstCaps *caps = NULL;
1296 GstStructure *str = NULL;
1297 const gchar *name = NULL;
1298 GstPad *sinkpad = NULL;
1299 gboolean first_track = FALSE;
1300 gboolean caps_ret = TRUE;
1302 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1303 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1306 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1307 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1309 LOGD("pad-added signal handling");
1311 /* get mimetype from caps */
1312 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1316 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1318 LOGD("detected mimetype : %s", name);
1321 if (strstr(name, "video")) {
1323 gchar *caps_str = NULL;
1325 caps_str = gst_caps_to_string(caps);
1326 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1327 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1328 player->set_mode.video_zc = true;
1330 MMPLAYER_FREEIF(caps_str);
1332 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1333 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1335 LOGD("surface type : %d", stype);
1337 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1338 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1342 /* in case of exporting video frame, it requires the 360 video filter.
1343 * it will be handled in _no_more_pads(). */
1344 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1345 __mmplayer_gst_make_fakesink(player, pad, name);
1349 if (MMPLAYER_USE_DECODEBIN(player)) {
1350 LOGD("video selector is required");
1351 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1353 LOGD("video concat is required");
1354 elem_idx = MMPLAYER_M_V_CONCAT;
1356 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1357 } else if (strstr(name, "audio")) {
1358 gint samplerate = 0;
1361 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1362 if (player->build_audio_offload)
1363 player->no_more_pad = TRUE; /* remove state holder */
1364 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1368 gst_structure_get_int(str, "rate", &samplerate);
1369 gst_structure_get_int(str, "channels", &channels);
1371 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1372 __mmplayer_gst_make_fakesink(player, pad, name);
1375 if (MMPLAYER_USE_DECODEBIN(player)) {
1376 LOGD("audio selector is required");
1377 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1379 LOGD("audio concat is required");
1380 elem_idx = MMPLAYER_M_A_CONCAT;
1382 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1384 } else if (strstr(name, "text")) {
1385 if (MMPLAYER_USE_DECODEBIN(player)) {
1386 LOGD("text selector is required");
1387 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1389 LOGD("text concat is required");
1390 elem_idx = MMPLAYER_M_T_CONCAT;
1392 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1394 LOGE("invalid caps info");
1398 /* check selector and create it */
1399 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1400 if (MMPLAYER_USE_DECODEBIN(player))
1401 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1403 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1409 LOGD("Combiner element is already created.");
1413 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1415 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1417 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1418 LOGE("failed to link combiner");
1419 gst_object_unref(GST_OBJECT(combiner));
1424 if (MMPLAYER_USE_DECODEBIN(player)) {
1425 LOGD("this track will be activated");
1426 g_object_set(combiner, "active-pad", sinkpad, NULL);
1430 if (MMPLAYER_USE_DECODEBIN(player)) {
1431 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1433 /* apply the text track information */
1434 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1435 mm_player_set_attribute((MMHandleType)player, NULL,
1436 "content_text_track_num", player->track[stream_type].total_track_num,
1437 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1438 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1445 gst_caps_unref(caps);
1448 gst_object_unref(GST_OBJECT(sinkpad));
1452 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1457 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1459 GstPad *srcpad = NULL;
1462 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1464 LOGD("type %d", type);
1467 LOGD("there is no %d track", type);
1471 srcpad = gst_element_get_static_pad(combiner, "src");
1473 LOGE("failed to get srcpad from combiner");
1477 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1479 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1481 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1482 if (player->track[type].block_id) {
1483 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1484 player->track[type].block_id = 0;
1488 gst_object_unref(GST_OBJECT(srcpad));
1497 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1499 gint active_index = 0;
1502 MMPLAYER_RETURN_IF_FAIL(player);
1504 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1506 /* change track to active pad */
1507 active_index = player->track[type].active_track_index;
1508 if ((active_index != DEFAULT_TRACK_INDEX) &&
1509 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1510 LOGW("failed to change %d type track to %d", type, active_index);
1511 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1515 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1516 mm_player_set_attribute((MMHandleType)player, NULL,
1517 "content_text_track_num", player->track[type].total_track_num,
1518 "current_text_track_index", player->track[type].active_track_index, NULL);
1525 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1528 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1530 if (!audio_selector) {
1531 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1533 /* in case the source is changed, output can be changed. */
1534 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1535 LOGD("remove previous audiobin if it exist");
1537 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1538 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1540 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1541 MMPLAYER_FREEIF(player->pipeline->audiobin);
1544 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1545 _mmplayer_pipeline_complete(NULL, player);
1550 /* apply the audio track information */
1551 if (MMPLAYER_USE_DECODEBIN(player))
1552 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1554 /* create audio sink path */
1555 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1556 LOGE("failed to create audio sink path");
1565 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1568 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1570 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1571 LOGD("text path is not supported");
1575 /* apply the text track information */
1576 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1578 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1579 player->has_closed_caption = TRUE;
1581 /* create text decode path */
1582 player->no_more_pad = TRUE;
1584 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1585 LOGE("failed to create text sink path");
1594 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1596 gint64 dur_bytes = 0L;
1599 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1600 player->pipeline->mainbin && player->streamer, FALSE);
1602 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1603 LOGE("fail to get duration.");
1605 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1606 * use file information was already set on Q2 when it was created. */
1607 _mm_player_streaming_set_queue2(player->streamer,
1608 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1609 TRUE, /* use_buffering */
1610 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1611 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1618 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1620 mmplayer_t *player = NULL;
1621 GstElement *video_selector = NULL;
1622 GstElement *audio_selector = NULL;
1623 GstElement *text_selector = NULL;
1626 player = (mmplayer_t *)data;
1628 LOGD("no-more-pad signal handling");
1630 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1631 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1632 LOGW("player is shutting down");
1636 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1637 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1638 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1639 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1640 LOGE("failed to set queue2 buffering");
1645 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1646 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1647 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1649 if (!video_selector && !audio_selector && !text_selector) {
1650 LOGW("there is no selector");
1651 player->no_more_pad = TRUE;
1655 /* create video path followed by video-select */
1656 if (video_selector && !audio_selector && !text_selector)
1657 player->no_more_pad = TRUE;
1659 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1662 /* create audio path followed by audio-select */
1663 if (audio_selector && !text_selector)
1664 player->no_more_pad = TRUE;
1666 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1669 /* create text path followed by text-select */
1670 __mmplayer_create_text_sink_path(player, text_selector);
1673 _mmplayer_set_reconfigure_state(player, FALSE);
1678 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1680 gboolean ret = FALSE;
1681 GstElement *pipeline = NULL;
1682 GstPad *sinkpad = NULL;
1685 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1686 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1688 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1690 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1692 LOGE("failed to get pad from sinkbin");
1698 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1699 LOGE("failed to link sinkbin for reusing");
1700 goto EXIT; /* exit either pass or fail */
1704 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1705 LOGE("failed to set state(READY) to sinkbin");
1710 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1711 LOGE("failed to add sinkbin to pipeline");
1716 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1717 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1722 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1723 LOGE("failed to set state(PAUSED) to sinkbin");
1732 gst_object_unref(GST_OBJECT(sinkpad));
1740 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1742 mmplayer_t *player = NULL;
1743 GstCaps *caps = NULL;
1744 gchar *caps_str = NULL;
1745 GstStructure *str = NULL;
1746 const gchar *name = NULL;
1747 GstElement *sinkbin = NULL;
1748 gboolean reusing = FALSE;
1749 gboolean caps_ret = TRUE;
1750 gchar *sink_pad_name = "sink";
1753 player = (mmplayer_t *)data;
1756 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1757 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1758 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1760 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1764 gst_caps_unref(caps);
1765 caps = gst_caps_ref(ref_caps);
1768 caps_str = gst_caps_to_string(caps);
1770 LOGD("detected mimetype : %s", name);
1772 if (strstr(name, "audio")) {
1773 if (player->pipeline->audiobin == NULL) {
1774 const gchar *audio_format = gst_structure_get_string(str, "format");
1776 LOGD("original audio format %s", audio_format);
1777 mm_player_set_attribute((MMHandleType)player, NULL,
1778 "content_audio_format", audio_format, strlen(audio_format), NULL);
1781 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1782 LOGE("failed to create audiobin. continuing without audio");
1786 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1787 LOGD("creating audiobin success");
1790 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1791 LOGD("reusing audiobin");
1792 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1794 } else if (strstr(name, "video")) {
1795 /* 1. zero copy is updated at _decode_pad_added()
1796 * 2. NULL surface type is handled in _decode_pad_added() */
1797 LOGD("zero copy %d", player->set_mode.video_zc);
1798 if (player->pipeline->videobin == NULL) {
1799 int surface_type = 0;
1800 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1801 LOGD("display_surface_type (%d)", surface_type);
1803 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1804 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1805 LOGE("failed to acquire video overlay resource");
1809 player->interrupted_by_resource = FALSE;
1811 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1812 LOGE("failed to create videobin. continuing without video");
1816 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1817 LOGD("creating videosink bin success");
1820 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1821 LOGD("re-using videobin");
1822 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1824 } else if (strstr(name, "text")) {
1825 if (player->pipeline->textbin == NULL) {
1826 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1827 LOGE("failed to create text sink bin. continuing without text");
1831 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1832 player->textsink_linked = 1;
1833 LOGD("creating textsink bin success");
1835 if (!player->textsink_linked) {
1836 LOGD("re-using textbin");
1838 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1839 player->textsink_linked = 1;
1841 /* linked textbin exist which means that the external subtitle path exist already */
1842 LOGW("ignoring internal subtitle since external subtitle is available");
1845 sink_pad_name = "text_sink";
1847 LOGW("unknown mime type %s, ignoring it", name);
1851 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1854 LOGD("[handle: %p] success to create and link sink bin", player);
1856 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1857 * streaming task. if the task blocked, then buffer will not flow to the next element
1858 *(autoplugging element). so this is special hack for streaming. please try to remove it
1860 /* dec stream count. we can remove fakesink if it's zero */
1861 if (player->num_dynamic_pad)
1862 player->num_dynamic_pad--;
1864 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1866 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1867 _mmplayer_pipeline_complete(NULL, player);
1871 MMPLAYER_FREEIF(caps_str);
1874 gst_caps_unref(caps);
1880 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1882 int required_angle = 0; /* Angle required for straight view */
1883 int rotation_angle = 0;
1885 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1886 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1888 /* Counter clockwise */
1889 switch (orientation) {
1894 required_angle = 270;
1897 required_angle = 180;
1900 required_angle = 90;
1904 rotation_angle = display_angle + required_angle;
1905 if (rotation_angle >= 360)
1906 rotation_angle -= 360;
1908 /* check if supported or not */
1909 if (rotation_angle % 90) {
1910 LOGD("not supported rotation angle = %d", rotation_angle);
1914 switch (rotation_angle) {
1916 *value = MM_DISPLAY_ROTATION_NONE;
1919 *value = MM_DISPLAY_ROTATION_90;
1922 *value = MM_DISPLAY_ROTATION_180;
1925 *value = MM_DISPLAY_ROTATION_270;
1929 LOGD("setting rotation property value : %d", *value);
1935 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1937 int display_rotation = 0;
1938 gchar *org_orient = NULL;
1939 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1942 LOGE("cannot get content attribute");
1943 return MM_ERROR_PLAYER_INTERNAL;
1946 if (display_angle) {
1947 /* update user rotation */
1948 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1950 /* Counter clockwise */
1951 switch (display_rotation) {
1952 case MM_DISPLAY_ROTATION_NONE:
1955 case MM_DISPLAY_ROTATION_90:
1956 *display_angle = 90;
1958 case MM_DISPLAY_ROTATION_180:
1959 *display_angle = 180;
1961 case MM_DISPLAY_ROTATION_270:
1962 *display_angle = 270;
1965 LOGW("wrong angle type : %d", display_rotation);
1968 LOGD("check user angle: %d", *display_angle);
1972 /* Counter clockwise */
1973 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1976 if (!strcmp(org_orient, "rotate-90"))
1978 else if (!strcmp(org_orient, "rotate-180"))
1980 else if (!strcmp(org_orient, "rotate-270"))
1983 LOGD("original rotation is %s", org_orient);
1985 LOGD("content_video_orientation get fail");
1988 LOGD("check orientation: %d", *orientation);
1991 return MM_ERROR_NONE;
1994 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1996 int rotation_value = 0;
1997 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1998 int display_angle = 0;
2001 /* check video sinkbin is created */
2002 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2005 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2007 /* get rotation value to set */
2008 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2009 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2010 LOGD("set video param : rotate %d", rotation_value);
2013 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2015 MMHandleType attrs = 0;
2019 /* check video sinkbin is created */
2020 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2021 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2024 attrs = MMPLAYER_GET_ATTRS(player);
2025 MMPLAYER_RETURN_IF_FAIL(attrs);
2027 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2028 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2029 LOGD("set video param : visible %d", visible);
2032 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2034 MMHandleType attrs = 0;
2035 int display_method = 0;
2038 /* check video sinkbin is created */
2039 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2042 attrs = MMPLAYER_GET_ATTRS(player);
2043 MMPLAYER_RETURN_IF_FAIL(attrs);
2045 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2046 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2047 LOGD("set video param : method %d", display_method);
2050 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2052 MMHandleType attrs = 0;
2056 /* check video sinkbin is created */
2057 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2060 attrs = MMPLAYER_GET_ATTRS(player);
2061 MMPLAYER_RETURN_IF_FAIL(attrs);
2063 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2064 MMPLAYER_RETURN_IF_FAIL(handle);
2066 gst_video_overlay_set_video_roi_area(
2067 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2068 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2069 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2070 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2073 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2075 MMHandleType attrs = 0;
2080 int win_roi_width = 0;
2081 int win_roi_height = 0;
2084 /* check video sinkbin is created */
2085 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2088 attrs = MMPLAYER_GET_ATTRS(player);
2089 MMPLAYER_RETURN_IF_FAIL(attrs);
2091 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2092 MMPLAYER_RETURN_IF_FAIL(handle);
2094 /* It should be set after setting window */
2095 mm_attrs_multiple_get(attrs, NULL,
2096 "display_win_roi_x", &win_roi_x,
2097 "display_win_roi_y", &win_roi_y,
2098 "display_win_roi_width", &win_roi_width,
2099 "display_win_roi_height", &win_roi_height, NULL);
2101 /* After setting window handle, set display roi area */
2102 gst_video_overlay_set_display_roi_area(
2103 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2104 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2105 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2106 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2109 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2111 MMHandleType attrs = 0;
2112 gchar *handle = NULL;
2114 /* check video sinkbin is created */
2115 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2118 attrs = MMPLAYER_GET_ATTRS(player);
2119 MMPLAYER_RETURN_IF_FAIL(attrs);
2121 /* common case if using overlay surface */
2122 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2123 MMPLAYER_RETURN_IF_FAIL(handle);
2125 gst_video_overlay_set_wl_window_exported_shell_handle(
2126 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2128 LOGD("set video param: exported_shell_handle (%s)", handle);
2131 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2133 MMHandleType attrs = 0;
2136 /* check video sinkbin is created */
2137 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2140 attrs = MMPLAYER_GET_ATTRS(player);
2141 MMPLAYER_RETURN_IF_FAIL(attrs);
2143 /* common case if using overlay surface */
2144 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2145 MMPLAYER_RETURN_IF_FAIL(handle);
2147 /* default is using wl_surface_id */
2148 LOGD("set video param : wl_surface_id %d", handle);
2149 gst_video_overlay_set_wl_window_wl_surface_id(
2150 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2155 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2157 gboolean update_all_param = FALSE;
2158 int curr_type = MM_DISPLAY_SURFACE_NUM;
2162 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2163 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2164 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2165 LOGW("videosink is not ready yet");
2166 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2169 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2171 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2172 LOGE("current type(%d) is wrong", curr_type);
2173 return MM_ERROR_PLAYER_INTERNAL;
2176 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2177 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2178 return MM_ERROR_PLAYER_INTERNAL;
2181 LOGD("param_name : %s", param_name);
2182 if (!g_strcmp0(param_name, "update_all_param"))
2183 update_all_param = TRUE;
2185 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2186 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2188 return MM_ERROR_NONE;
2190 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2191 __mmplayer_video_param_set_display_overlay(player);
2192 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2193 __mmplayer_video_param_set_display_method(player);
2194 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2195 __mmplayer_video_param_set_display_visible(player);
2196 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2197 __mmplayer_video_param_set_display_rotation(player);
2198 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2199 __mmplayer_video_param_set_roi_area(player);
2200 if (update_all_param)
2201 __mmplayer_video_param_set_video_roi_area(player);
2204 return MM_ERROR_NONE;
2207 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2209 gboolean disable_overlay = FALSE;
2212 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2213 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2214 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2216 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2217 LOGW("Display control is not supported");
2218 return MM_ERROR_PLAYER_INTERNAL;
2221 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2223 if (disable == (bool)disable_overlay) {
2224 LOGE("It's the same with current setting: (%d)", disable);
2225 return MM_ERROR_NONE;
2229 LOGE("disable overlay");
2230 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2232 /* release overlay resource */
2233 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2234 LOGE("failed to release overlay resource");
2235 return MM_ERROR_PLAYER_INTERNAL;
2238 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2239 LOGE("failed to acquire video overlay resource");
2240 return MM_ERROR_PLAYER_INTERNAL;
2242 player->interrupted_by_resource = FALSE;
2244 LOGD("enable overlay");
2245 __mmplayer_video_param_set_display_overlay(player);
2246 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2247 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2251 return MM_ERROR_NONE;
2255 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2257 int ret = MM_ERROR_NONE;
2258 mmplayer_t *player = (mmplayer_t *)hplayer;
2261 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2263 if (MMPLAYER_USE_DECODEBIN(player)) {
2264 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2269 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2270 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2271 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2273 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
2275 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2277 /* release decoder resource */
2278 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2279 LOGE("failed to release video decoder resources");
2280 return MM_ERROR_PLAYER_INTERNAL;
2282 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2284 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2288 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2295 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2297 GList *bucket = element_bucket;
2298 mmplayer_gst_element_t *element = NULL;
2299 mmplayer_gst_element_t *prv_element = NULL;
2300 GstElement *tee_element = NULL;
2301 gint successful_link_count = 0;
2305 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2307 prv_element = (mmplayer_gst_element_t *)bucket->data;
2308 bucket = bucket->next;
2310 for (; bucket; bucket = bucket->next) {
2311 element = (mmplayer_gst_element_t *)bucket->data;
2313 if (element && element->gst) {
2314 if (prv_element && prv_element->gst) {
2315 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2317 prv_element->gst = tee_element;
2319 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2320 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2321 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2325 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2326 LOGD("linking [%s] to [%s] success",
2327 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2328 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2329 successful_link_count++;
2330 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2331 LOGD("keep audio-tee element for next audio pipeline branch");
2332 tee_element = prv_element->gst;
2335 LOGD("linking [%s] to [%s] failed",
2336 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2337 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2343 prv_element = element;
2348 return successful_link_count;
2352 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2354 GList *bucket = element_bucket;
2355 mmplayer_gst_element_t *element = NULL;
2356 int successful_add_count = 0;
2360 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2361 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2363 for (; bucket; bucket = bucket->next) {
2364 element = (mmplayer_gst_element_t *)bucket->data;
2366 if (element && element->gst) {
2367 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2368 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2369 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2370 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2373 successful_add_count++;
2379 return successful_add_count;
2383 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2385 mmplayer_t *player = (mmplayer_t *)data;
2386 GstCaps *caps = NULL;
2387 GstStructure *str = NULL;
2389 gboolean caps_ret = TRUE;
2393 MMPLAYER_RETURN_IF_FAIL(pad);
2394 MMPLAYER_RETURN_IF_FAIL(unused);
2395 MMPLAYER_RETURN_IF_FAIL(data);
2397 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2401 LOGD("name = %s", name);
2403 if (strstr(name, "audio")) {
2404 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2406 if (player->audio_stream_changed_cb) {
2407 LOGE("call the audio stream changed cb");
2408 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2410 } else if (strstr(name, "video")) {
2411 if ((name = gst_structure_get_string(str, "format")))
2412 player->set_mode.video_zc = name[0] == 'S';
2414 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2415 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2417 LOGW("invalid caps info");
2422 gst_caps_unref(caps);
2430 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2435 MMPLAYER_RETURN_IF_FAIL(player);
2437 if (player->audio_stream_buff_list) {
2438 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2439 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2442 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2443 __mmplayer_audio_stream_send_data(player, tmp);
2445 MMPLAYER_FREEIF(tmp->pcm_data);
2446 MMPLAYER_FREEIF(tmp);
2449 g_list_free(player->audio_stream_buff_list);
2450 player->audio_stream_buff_list = NULL;
2457 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2459 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2462 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2464 audio_stream.bitrate = a_buffer->bitrate;
2465 audio_stream.channel = a_buffer->channel;
2466 audio_stream.channel_mask = a_buffer->channel_mask;
2467 audio_stream.data_size = a_buffer->data_size;
2468 audio_stream.data = a_buffer->pcm_data;
2469 audio_stream.pcm_format = a_buffer->pcm_format;
2471 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2473 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2479 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2481 mmplayer_t *player = (mmplayer_t *)data;
2482 const gchar *pcm_format = NULL;
2485 guint64 channel_mask = 0;
2486 void *a_data = NULL;
2488 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2489 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2493 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2495 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2496 a_data = mapinfo.data;
2497 a_size = mapinfo.size;
2499 GstCaps *caps = gst_pad_get_current_caps(pad);
2500 GstStructure *structure = gst_caps_get_structure(caps, 0);
2502 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2504 pcm_format = gst_structure_get_string(structure, "format");
2505 gst_structure_get_int(structure, "rate", &rate);
2506 gst_structure_get_int(structure, "channels", &channel);
2507 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2508 gst_caps_unref(GST_CAPS(caps));
2510 /* In case of the sync is false, use buffer list. *
2511 * The num of buffer list depends on the num of audio channels */
2512 if (player->audio_stream_buff_list) {
2513 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2514 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2516 if (channel_mask == tmp->channel_mask) {
2518 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2520 if (tmp->data_size + a_size < tmp->buff_size) {
2521 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2522 tmp->data_size += a_size;
2524 /* send data to client */
2525 __mmplayer_audio_stream_send_data(player, tmp);
2527 if (a_size > tmp->buff_size) {
2528 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2529 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2530 if (tmp->pcm_data == NULL) {
2531 LOGE("failed to realloc data.");
2534 tmp->buff_size = a_size;
2536 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2537 memcpy(tmp->pcm_data, a_data, a_size);
2538 tmp->data_size = a_size;
2543 LOGE("data is empty in list.");
2549 /* create new audio stream data for newly found audio channel */
2550 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2551 if (a_buffer == NULL) {
2552 LOGE("failed to alloc data.");
2555 a_buffer->bitrate = rate;
2556 a_buffer->channel = channel;
2557 a_buffer->channel_mask = channel_mask;
2558 a_buffer->data_size = a_size;
2559 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2561 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2562 /* If sync is FALSE, use buffer list to reduce the IPC. */
2563 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2564 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2565 if (a_buffer->pcm_data == NULL) {
2566 LOGE("failed to alloc data.");
2567 MMPLAYER_FREEIF(a_buffer);
2570 memcpy(a_buffer->pcm_data, a_data, a_size);
2572 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2574 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2576 /* If sync is TRUE, send data directly. */
2577 a_buffer->pcm_data = a_data;
2578 __mmplayer_audio_stream_send_data(player, a_buffer);
2579 MMPLAYER_FREEIF(a_buffer);
2583 gst_buffer_unmap(buffer, &mapinfo);
2588 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2590 mmplayer_t *player = (mmplayer_t *)data;
2591 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2592 GstPad *sinkpad = NULL;
2593 GstElement *queue = NULL, *sink = NULL;
2596 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2598 queue = gst_element_factory_make("queue", NULL);
2599 if (queue == NULL) {
2600 LOGD("fail make queue");
2604 sink = gst_element_factory_make("fakesink", NULL);
2606 LOGD("fail make fakesink");
2610 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2612 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2613 LOGW("failed to link queue & sink");
2617 sinkpad = gst_element_get_static_pad(queue, "sink");
2619 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2620 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2624 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2626 gst_object_unref(sinkpad);
2627 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2628 g_object_set(sink, "sync", TRUE, NULL);
2629 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2631 /* keep the first sink reference only */
2632 if (!audiobin[MMPLAYER_A_SINK].gst) {
2633 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2634 audiobin[MMPLAYER_A_SINK].gst = sink;
2638 _mmplayer_add_signal_connection(player,
2640 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2642 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2645 __mmplayer_add_sink(player, sink, FALSE);
2647 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2648 LOGE("failed to sync state");
2652 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2653 LOGE("failed to sync state");
2661 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2663 gst_object_unref(GST_OBJECT(queue));
2667 gst_object_unref(GST_OBJECT(sink));
2671 gst_object_unref(GST_OBJECT(sinkpad));
2679 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2681 mmplayer_t *player = (mmplayer_t *)data;
2684 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2686 player->no_more_pad = TRUE;
2687 _mmplayer_pipeline_complete(NULL, player);
2694 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2696 #define MAX_PROPS_LEN 128
2697 mmplayer_gst_element_t *audiobin = NULL;
2698 gint latency_mode = 0;
2699 gchar *stream_type = NULL;
2700 gchar *latency = NULL;
2702 gchar stream_props[MAX_PROPS_LEN] = {0,};
2703 GstStructure *props = NULL;
2706 * It should be set after player creation through attribute.
2707 * But, it can not be changed during playing.
2710 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2712 audiobin = player->pipeline->audiobin;
2714 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2715 if (player->sound.mute) {
2716 LOGD("mute enabled");
2717 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2720 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2721 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2724 snprintf(stream_props, sizeof(stream_props) - 1,
2725 "props,application.process.id.origin=%d", player->client_pid);
2727 snprintf(stream_props, sizeof(stream_props) - 1,
2728 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2729 stream_type, stream_id, player->client_pid);
2731 props = gst_structure_from_string(stream_props, NULL);
2732 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2733 LOGI("props result[%s].", stream_props);
2734 gst_structure_free(props);
2736 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2738 switch (latency_mode) {
2739 case AUDIO_LATENCY_MODE_LOW:
2740 latency = g_strdup("low");
2742 case AUDIO_LATENCY_MODE_MID:
2743 latency = g_strdup("mid");
2745 case AUDIO_LATENCY_MODE_HIGH:
2746 latency = g_strdup("high");
2749 latency = g_strdup("mid");
2753 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2755 LOGD("audiosink property - latency=%s", latency);
2757 MMPLAYER_FREEIF(latency);
2763 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2765 mmplayer_gst_element_t *audiobin = NULL;
2768 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2769 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2771 audiobin = player->pipeline->audiobin;
2773 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2774 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2775 LOGE("failed to create media stream info");
2776 return MM_ERROR_PLAYER_INTERNAL;
2779 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2781 if (player->video360_yaw_radians <= M_PI &&
2782 player->video360_yaw_radians >= -M_PI &&
2783 player->video360_pitch_radians <= M_PI_2 &&
2784 player->video360_pitch_radians >= -M_PI_2) {
2785 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2786 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2787 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2788 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2789 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2790 "source-orientation-y", player->video360_metadata.init_view_heading,
2791 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2795 return MM_ERROR_NONE;
2799 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2801 mmplayer_gst_element_t *audiobin = NULL;
2802 GstPad *sink_pad = NULL;
2803 GstCaps *acaps = NULL;
2805 int pitch_control = 0;
2806 double pitch_value = 1.0;
2809 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2810 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2812 audiobin = player->pipeline->audiobin;
2814 LOGD("make element for normal audio playback");
2816 /* audio bin structure for playback. {} means optional.
2817 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2819 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2820 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2823 /* for pitch control */
2824 mm_attrs_multiple_get(player->attrs, NULL,
2825 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2826 MM_PLAYER_PITCH_VALUE, &pitch_value,
2829 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2830 if (pitch_control && (player->videodec_linked == 0)) {
2831 GstElementFactory *factory;
2833 factory = gst_element_factory_find("pitch");
2835 gst_object_unref(factory);
2838 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2841 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2842 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2844 LOGW("there is no pitch element");
2849 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2851 /* replaygain volume */
2852 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2853 if (player->sound.rg_enable)
2854 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2856 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2859 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2861 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2862 /* currently, only openalsink uses volume element */
2863 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2864 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2866 if (player->sound.mute) {
2867 LOGD("mute enabled");
2868 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2872 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2874 /* audio effect element. if audio effect is enabled */
2875 if ((strcmp(player->ini.audioeffect_element, ""))
2877 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2878 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2880 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2882 if ((!player->bypass_audio_effect)
2883 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2884 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2885 if (!_mmplayer_audio_effect_custom_apply(player))
2886 LOGI("apply audio effect(custom) setting success");
2890 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2891 && (player->set_mode.rich_audio)) {
2892 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2896 /* create audio sink */
2897 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2898 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2899 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2901 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2902 if (player->is_360_feature_enabled &&
2903 player->is_content_spherical &&
2905 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2906 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2907 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2909 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2911 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2913 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2914 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2915 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2916 gst_caps_unref(acaps);
2918 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2920 player->is_openal_plugin_used = TRUE;
2922 if (player->is_360_feature_enabled && player->is_content_spherical)
2923 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2924 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2927 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2928 (player->videodec_linked && player->ini.use_system_clock)) {
2929 LOGD("system clock will be used.");
2930 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2933 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2934 __mmplayer_gst_set_pulsesink_property(player);
2935 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2936 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2941 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2942 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2944 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2945 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2946 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2947 gst_object_unref(GST_OBJECT(sink_pad));
2949 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2952 return MM_ERROR_NONE;
2954 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2956 return MM_ERROR_PLAYER_INTERNAL;
2960 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2962 mmplayer_gst_element_t *audiobin = NULL;
2963 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2965 gchar *dst_format = NULL;
2967 int dst_samplerate = 0;
2968 int dst_channels = 0;
2969 GstCaps *caps = NULL;
2970 char *caps_str = NULL;
2973 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2974 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2976 audiobin = player->pipeline->audiobin;
2978 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2980 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2982 [case 1] extract interleave audio pcm without playback
2983 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2984 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2986 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2988 [case 2] deinterleave for each channel without playback
2989 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2990 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2992 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2993 - fakesink (sync or not)
2996 [case 3] [case 1(sync only)] + playback
2997 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2999 * src - ... - tee - queue1 - playback path
3000 - queue2 - [case1 pipeline with sync]
3002 [case 4] [case 2(sync only)] + playback
3003 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3005 * src - ... - tee - queue1 - playback path
3006 - queue2 - [case2 pipeline with sync]
3010 /* 1. create tee and playback path
3011 'tee' should be added at first to copy the decoded stream
3013 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3014 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3015 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3017 /* tee - path 1 : for playback path */
3018 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3019 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3021 /* tee - path 2 : for extract path */
3022 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3023 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3026 /* if there is tee, 'tee - path 2' is linked here */
3028 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3031 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3033 /* 2. decide the extract pcm format */
3034 mm_attrs_multiple_get(player->attrs, NULL,
3035 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3036 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3037 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3040 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3041 dst_format, dst_len, dst_samplerate, dst_channels);
3043 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3044 mm_attrs_multiple_get(player->attrs, NULL,
3045 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3046 "content_audio_samplerate", &dst_samplerate,
3047 "content_audio_channels", &dst_channels,
3050 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3051 dst_format, dst_len, dst_samplerate, dst_channels);
3053 /* If there is no enough information, set it to platform default value. */
3054 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3055 LOGD("set platform default format");
3056 dst_format = DEFAULT_PCM_OUT_FORMAT;
3058 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3059 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3062 /* 3. create capsfilter */
3063 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3064 caps = gst_caps_new_simple("audio/x-raw",
3065 "format", G_TYPE_STRING, dst_format,
3066 "rate", G_TYPE_INT, dst_samplerate,
3067 "channels", G_TYPE_INT, dst_channels,
3070 caps_str = gst_caps_to_string(caps);
3071 LOGD("new caps : %s", caps_str);
3073 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3076 gst_caps_unref(caps);
3077 MMPLAYER_FREEIF(caps_str);
3079 /* 4-1. create deinterleave to extract pcm for each channel */
3080 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3081 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3082 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3084 /* audiosink will be added after getting signal for each channel */
3085 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3086 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3087 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3088 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3089 player->no_more_pad = FALSE;
3091 /* 4-2. create fakesink to extract interleaved pcm */
3092 LOGD("add audio fakesink for interleaved audio");
3093 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3094 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3095 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3096 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3098 _mmplayer_add_signal_connection(player,
3099 G_OBJECT(audiobin[extract_sink_id].gst),
3100 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3102 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3105 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3109 return MM_ERROR_NONE;
3111 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3113 return MM_ERROR_PLAYER_INTERNAL;
3117 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3119 int ret = MM_ERROR_NONE;
3120 mmplayer_gst_element_t *audiobin = NULL;
3121 GList *element_bucket = NULL;
3124 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3125 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3127 audiobin = player->pipeline->audiobin;
3129 if (player->build_audio_offload) { /* skip all the audio filters */
3130 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3132 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3133 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3134 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3136 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3140 /* FIXME: need to mention the supportable condition at API reference */
3141 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3142 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3144 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3146 if (ret != MM_ERROR_NONE)
3149 LOGD("success to make audio bin element");
3150 *bucket = element_bucket;
3153 return MM_ERROR_NONE;
3156 LOGE("failed to make audio bin element");
3157 g_list_free(element_bucket);
3161 return MM_ERROR_PLAYER_INTERNAL;
3165 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3167 mmplayer_gst_element_t *first_element = NULL;
3168 mmplayer_gst_element_t *audiobin = NULL;
3170 GstPad *ghostpad = NULL;
3171 GList *element_bucket = NULL;
3175 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3178 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3180 LOGE("failed to allocate memory for audiobin");
3181 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3185 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3186 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3187 if (!audiobin[MMPLAYER_A_BIN].gst) {
3188 LOGE("failed to create audiobin");
3193 player->pipeline->audiobin = audiobin;
3195 /* create audio filters and audiosink */
3196 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3199 /* adding created elements to bin */
3200 LOGD("adding created elements to bin");
3201 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3204 /* linking elements in the bucket by added order. */
3205 LOGD("Linking elements in the bucket by added order.");
3206 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3209 /* get first element's sinkpad for creating ghostpad */
3210 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3211 if (!first_element) {
3212 LOGE("failed to get first elem");
3216 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3218 LOGE("failed to get pad from first element of audiobin");
3222 ghostpad = gst_ghost_pad_new("sink", pad);
3224 LOGE("failed to create ghostpad");
3228 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3229 LOGE("failed to add ghostpad to audiobin");
3233 gst_object_unref(pad);
3235 g_list_free(element_bucket);
3238 return MM_ERROR_NONE;
3241 LOGD("ERROR : releasing audiobin");
3244 gst_object_unref(GST_OBJECT(pad));
3247 gst_object_unref(GST_OBJECT(ghostpad));
3250 g_list_free(element_bucket);
3252 /* release element which are not added to bin */
3253 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3254 /* NOTE : skip bin */
3255 if (audiobin[i].gst) {
3256 GstObject *parent = NULL;
3257 parent = gst_element_get_parent(audiobin[i].gst);
3260 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3261 audiobin[i].gst = NULL;
3263 gst_object_unref(GST_OBJECT(parent));
3267 /* release audiobin with it's children */
3268 if (audiobin[MMPLAYER_A_BIN].gst)
3269 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3271 MMPLAYER_FREEIF(audiobin);
3273 player->pipeline->audiobin = NULL;
3275 return MM_ERROR_PLAYER_INTERNAL;
3279 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3281 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3285 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3287 int ret = MM_ERROR_NONE;
3289 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3290 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3292 MMPLAYER_VIDEO_BO_LOCK(player);
3294 if (player->video_bo_list) {
3295 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3296 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3297 if (tmp && tmp->bo == bo) {
3299 LOGD("release bo %p", bo);
3300 tbm_bo_unref(tmp->bo);
3301 MMPLAYER_VIDEO_BO_UNLOCK(player);
3302 MMPLAYER_VIDEO_BO_SIGNAL(player);
3307 /* hw codec is running or the list was reset for DRC. */
3308 LOGW("there is no bo list.");
3310 MMPLAYER_VIDEO_BO_UNLOCK(player);
3312 LOGW("failed to find bo %p", bo);
3316 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3322 tbm_bo_unref(tmp->bo);
3327 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3330 MMPLAYER_RETURN_IF_FAIL(player);
3332 MMPLAYER_VIDEO_BO_LOCK(player);
3333 if (player->video_bo_list) {
3334 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3335 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3336 player->video_bo_list = NULL;
3338 player->video_bo_size = 0;
3339 MMPLAYER_VIDEO_BO_UNLOCK(player);
3346 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3349 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3350 gboolean ret = TRUE;
3351 gint64 end_time = 0;
3353 /* check DRC, if it is, destroy the prev bo list to create again */
3354 if (player->video_bo_size != size) {
3355 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3356 __mmplayer_video_stream_destroy_bo_list(player);
3357 player->video_bo_size = size;
3360 MMPLAYER_VIDEO_BO_LOCK(player);
3362 if ((!player->video_bo_list) ||
3363 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3365 /* create bo list */
3367 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3369 if (player->video_bo_list) {
3370 /* if bo list did not created all, try it again. */
3371 idx = g_list_length(player->video_bo_list);
3372 LOGD("bo list exist(len: %d)", idx);
3375 for (; idx < player->ini.num_of_video_bo; idx++) {
3376 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3378 LOGE("Fail to alloc bo_info.");
3381 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3383 LOGE("Fail to tbm_bo_alloc.");
3384 MMPLAYER_FREEIF(bo_info);
3387 bo_info->used = FALSE;
3388 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3391 /* update video num buffers */
3392 LOGD("video_num_buffers : %d", idx);
3393 mm_player_set_attribute((MMHandleType)player, NULL,
3394 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3395 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3399 MMPLAYER_VIDEO_BO_UNLOCK(player);
3404 if (player->ini.video_bo_timeout > 0)
3405 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3408 /* get bo from list*/
3409 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3410 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3411 if (tmp && (tmp->used == FALSE)) {
3412 LOGD("found bo %p to use", tmp->bo);
3414 MMPLAYER_VIDEO_BO_UNLOCK(player);
3415 return tbm_bo_ref(tmp->bo);
3419 if (player->ini.video_bo_timeout <= 0) {
3420 MMPLAYER_VIDEO_BO_WAIT(player);
3422 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3424 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3430 MMPLAYER_VIDEO_BO_UNLOCK(player);
3435 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3437 mmplayer_t *player = (mmplayer_t *)data;
3439 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3441 /* send prerolled pkt */
3442 player->video_stream_prerolled = false;
3444 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3446 /* not to send prerolled pkt again */
3447 player->video_stream_prerolled = true;
3451 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3453 mmplayer_t *player = (mmplayer_t *)data;
3454 mmplayer_video_decoded_data_info_t *stream = NULL;
3455 GstMemory *mem = NULL;
3458 MMPLAYER_RETURN_IF_FAIL(player);
3459 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3461 if (player->video_stream_prerolled) {
3462 player->video_stream_prerolled = false;
3463 LOGD("skip the prerolled pkt not to send it again");
3467 /* clear stream data structure */
3468 stream = __mmplayer_create_stream_from_pad(pad);
3470 LOGE("failed to alloc stream");
3474 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3476 /* set size and timestamp */
3477 mem = gst_buffer_peek_memory(buffer, 0);
3478 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3479 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3481 /* check zero-copy */
3482 if (player->set_mode.video_zc &&
3483 player->set_mode.video_export &&
3484 gst_is_tizen_memory(mem)) {
3485 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3486 stream->internal_buffer = gst_buffer_ref(buffer);
3487 } else { /* sw codec */
3488 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3491 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3495 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3496 LOGE("failed to send video decoded data.");
3503 LOGE("release video stream resource.");
3504 if (gst_is_tizen_memory(mem)) {
3506 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3508 tbm_bo_unref(stream->bo[i]);
3511 /* unref gst buffer */
3512 if (stream->internal_buffer)
3513 gst_buffer_unref(stream->internal_buffer);
3516 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3518 MMPLAYER_FREEIF(stream);
3523 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3525 mmplayer_gst_element_t *videobin = NULL;
3528 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3530 videobin = player->pipeline->videobin;
3532 /* Set spatial media metadata and/or user settings to the element.
3534 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3535 "projection-type", player->video360_metadata.projection_type, NULL);
3537 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3538 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3540 if (player->video360_metadata.full_pano_width_pixels &&
3541 player->video360_metadata.full_pano_height_pixels &&
3542 player->video360_metadata.cropped_area_image_width &&
3543 player->video360_metadata.cropped_area_image_height) {
3544 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3545 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3546 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3547 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3548 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3549 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3550 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3554 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3555 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3556 "horizontal-fov", player->video360_horizontal_fov,
3557 "vertical-fov", player->video360_vertical_fov, NULL);
3560 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3561 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3562 "zoom", 1.0f / player->video360_zoom, NULL);
3565 if (player->video360_yaw_radians <= M_PI &&
3566 player->video360_yaw_radians >= -M_PI &&
3567 player->video360_pitch_radians <= M_PI_2 &&
3568 player->video360_pitch_radians >= -M_PI_2) {
3569 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3570 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3571 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3572 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3573 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3574 "pose-yaw", player->video360_metadata.init_view_heading,
3575 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3578 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3579 "passthrough", !player->is_video360_enabled, NULL);
3586 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3588 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3589 GList *element_bucket = NULL;
3592 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3594 /* create video360 filter */
3595 if (player->is_360_feature_enabled && player->is_content_spherical) {
3596 LOGD("create video360 element");
3597 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3598 __mmplayer_gst_set_video360_property(player);
3602 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3603 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3604 player->set_mode.video_zc) {
3605 LOGD("skip creating the videoconv and rotator");
3606 return MM_ERROR_NONE;
3609 /* in case of sw codec & overlay surface type, except 360 playback.
3610 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3611 LOGD("create video converter: %s", video_csc);
3612 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3615 *bucket = element_bucket;
3617 return MM_ERROR_NONE;
3619 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3620 g_list_free(element_bucket);
3624 return MM_ERROR_PLAYER_INTERNAL;
3628 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3630 gchar *factory_name = NULL;
3632 switch (surface_type) {
3633 case MM_DISPLAY_SURFACE_OVERLAY:
3635 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3636 if (strlen(player->ini.videosink_element_overlay) > 0)
3637 factory_name = player->ini.videosink_element_overlay;
3639 case MM_DISPLAY_SURFACE_REMOTE:
3641 case MM_DISPLAY_SURFACE_NULL:
3642 if (strlen(player->ini.videosink_element_fake) > 0)
3643 factory_name = player->ini.videosink_element_fake;
3646 LOGE("unidentified surface type");
3650 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3651 return factory_name;
3655 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3657 gchar *factory_name = NULL;
3658 mmplayer_gst_element_t *videobin = NULL;
3663 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3665 videobin = player->pipeline->videobin;
3666 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3668 attrs = MMPLAYER_GET_ATTRS(player);
3670 LOGE("cannot get content attribute");
3671 return MM_ERROR_PLAYER_INTERNAL;
3674 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3675 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3676 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3677 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3678 "use-tbm", use_tbm, NULL);
3681 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3682 return MM_ERROR_PLAYER_INTERNAL;
3684 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3687 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3688 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3691 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3693 LOGD("disable last-sample");
3694 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3697 if (player->set_mode.video_export) {
3699 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3700 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3701 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3703 _mmplayer_add_signal_connection(player,
3704 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3705 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3707 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3710 _mmplayer_add_signal_connection(player,
3711 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3712 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3714 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3718 if (videobin[MMPLAYER_V_SINK].gst) {
3719 GstPad *sink_pad = NULL;
3720 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3722 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3723 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3724 gst_object_unref(GST_OBJECT(sink_pad));
3726 LOGE("failed to get sink pad from videosink");
3730 return MM_ERROR_NONE;
3735 * - video overlay surface(arm/x86) : tizenwlsink
3738 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3741 GList *element_bucket = NULL;
3742 mmplayer_gst_element_t *first_element = NULL;
3743 mmplayer_gst_element_t *videobin = NULL;
3744 gchar *videosink_factory_name = NULL;
3747 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3750 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3752 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3754 player->pipeline->videobin = videobin;
3757 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3758 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3759 if (!videobin[MMPLAYER_V_BIN].gst) {
3760 LOGE("failed to create videobin");
3764 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3767 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3768 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3770 /* additional setting for sink plug-in */
3771 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3772 LOGE("failed to set video property");
3776 /* store it as it's sink element */
3777 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3779 /* adding created elements to bin */
3780 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3781 LOGE("failed to add elements");
3785 /* Linking elements in the bucket by added order */
3786 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3787 LOGE("failed to link elements");
3791 /* get first element's sinkpad for creating ghostpad */
3792 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3793 if (!first_element) {
3794 LOGE("failed to get first element from bucket");
3798 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3800 LOGE("failed to get pad from first element");
3804 /* create ghostpad */
3805 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3806 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3807 LOGE("failed to add ghostpad to videobin");
3810 gst_object_unref(pad);
3812 /* done. free allocated variables */
3813 g_list_free(element_bucket);
3817 return MM_ERROR_NONE;
3820 LOGE("ERROR : releasing videobin");
3821 g_list_free(element_bucket);
3824 gst_object_unref(GST_OBJECT(pad));
3826 /* release videobin with it's children */
3827 if (videobin[MMPLAYER_V_BIN].gst)
3828 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3830 MMPLAYER_FREEIF(videobin);
3831 player->pipeline->videobin = NULL;
3833 return MM_ERROR_PLAYER_INTERNAL;
3837 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3839 GList *element_bucket = NULL;
3840 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3842 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3843 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3844 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3845 "signal-handoffs", FALSE,
3848 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3849 _mmplayer_add_signal_connection(player,
3850 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3851 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3853 G_CALLBACK(__mmplayer_update_subtitle),
3856 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3857 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3859 if (!player->play_subtitle) {
3860 LOGD("add textbin sink as sink element of whole pipeline.");
3861 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3864 /* adding created elements to bin */
3865 LOGD("adding created elements to bin");
3866 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3867 LOGE("failed to add elements");
3871 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3872 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3873 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3875 /* linking elements in the bucket by added order. */
3876 LOGD("Linking elements in the bucket by added order.");
3877 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3878 LOGE("failed to link elements");
3882 if (textbin[MMPLAYER_T_QUEUE].gst) {
3884 GstPad *ghostpad = NULL;
3886 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3888 LOGE("failed to get sink pad of text queue");
3892 ghostpad = gst_ghost_pad_new("text_sink", pad);
3893 gst_object_unref(pad);
3896 LOGE("failed to create ghostpad of textbin");
3900 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3901 LOGE("failed to add ghostpad to textbin");
3902 gst_object_unref(ghostpad);
3907 g_list_free(element_bucket);
3909 return MM_ERROR_NONE;
3913 g_list_free(element_bucket);
3915 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3916 LOGE("remove textbin sink from sink list");
3917 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3920 /* release element at __mmplayer_gst_create_text_sink_bin */
3921 return MM_ERROR_PLAYER_INTERNAL;
3925 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3927 mmplayer_gst_element_t *textbin = NULL;
3928 int surface_type = 0;
3933 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3936 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3938 LOGE("failed to allocate memory for textbin");
3939 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3943 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3944 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3945 if (!textbin[MMPLAYER_T_BIN].gst) {
3946 LOGE("failed to create textbin");
3951 player->pipeline->textbin = textbin;
3954 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3955 LOGD("surface type for subtitle : %d", surface_type);
3956 switch (surface_type) {
3957 case MM_DISPLAY_SURFACE_OVERLAY:
3958 case MM_DISPLAY_SURFACE_NULL:
3959 case MM_DISPLAY_SURFACE_REMOTE:
3960 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3961 LOGE("failed to make plain text elements");
3972 return MM_ERROR_NONE;
3976 LOGD("ERROR : releasing textbin");
3978 /* release signal */
3979 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3981 /* release element which are not added to bin */
3982 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3983 /* NOTE : skip bin */
3984 if (textbin[i].gst) {
3985 GstObject *parent = NULL;
3986 parent = gst_element_get_parent(textbin[i].gst);
3989 gst_object_unref(GST_OBJECT(textbin[i].gst));
3990 textbin[i].gst = NULL;
3992 gst_object_unref(GST_OBJECT(parent));
3997 /* release textbin with it's children */
3998 if (textbin[MMPLAYER_T_BIN].gst)
3999 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4001 MMPLAYER_FREEIF(textbin);
4002 player->pipeline->textbin = NULL;
4005 return MM_ERROR_PLAYER_INTERNAL;
4009 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4011 mmplayer_gst_element_t *mainbin = NULL;
4012 mmplayer_gst_element_t *textbin = NULL;
4013 MMHandleType attrs = 0;
4014 GstElement *subsrc = NULL;
4015 GstElement *subparse = NULL;
4016 gchar *subtitle_uri = NULL;
4017 const gchar *charset = NULL;
4023 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4025 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4027 mainbin = player->pipeline->mainbin;
4029 attrs = MMPLAYER_GET_ATTRS(player);
4031 LOGE("cannot get content attribute");
4032 return MM_ERROR_PLAYER_INTERNAL;
4035 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4036 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4037 LOGE("subtitle uri is not proper filepath.");
4038 return MM_ERROR_PLAYER_INVALID_URI;
4041 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4042 LOGE("failed to get storage info of subtitle path");
4043 return MM_ERROR_PLAYER_INVALID_URI;
4046 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4048 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4049 player->subtitle_language_list = NULL;
4050 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4052 /* create the subtitle source */
4053 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4055 LOGE("failed to create filesrc element");
4058 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4060 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4061 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4063 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4064 LOGW("failed to add queue");
4065 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4066 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4067 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4072 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4074 LOGE("failed to create subparse element");
4078 charset = _mmplayer_get_charset(subtitle_uri);
4080 LOGD("detected charset is %s", charset);
4081 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4084 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4085 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4087 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4088 LOGW("failed to add subparse");
4089 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4090 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4091 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4095 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4096 LOGW("failed to link subsrc and subparse");
4100 player->play_subtitle = TRUE;
4101 player->adjust_subtitle_pos = 0;
4103 LOGD("play subtitle using subtitle file");
4105 if (player->pipeline->textbin == NULL) {
4106 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4107 LOGE("failed to create text sink bin. continuing without text");
4111 textbin = player->pipeline->textbin;
4113 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4114 LOGW("failed to add textbin");
4116 /* release signal */
4117 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4119 /* release textbin with it's children */
4120 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4121 MMPLAYER_FREEIF(player->pipeline->textbin);
4122 player->pipeline->textbin = textbin = NULL;
4126 LOGD("link text input selector and textbin ghost pad");
4128 player->textsink_linked = 1;
4129 player->external_text_idx = 0;
4130 LOGI("textsink is linked");
4132 textbin = player->pipeline->textbin;
4133 LOGD("text bin has been created. reuse it.");
4134 player->external_text_idx = 1;
4137 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4138 LOGW("failed to link subparse and textbin");
4142 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4144 LOGE("failed to get sink pad from textsink to probe data");
4148 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4149 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4151 gst_object_unref(pad);
4154 /* create dot. for debugging */
4155 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4158 return MM_ERROR_NONE;
4161 /* release text pipeline resource */
4162 player->textsink_linked = 0;
4164 /* release signal */
4165 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4167 if (player->pipeline->textbin) {
4168 LOGE("remove textbin");
4170 /* release textbin with it's children */
4171 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4172 MMPLAYER_FREEIF(player->pipeline->textbin);
4173 player->pipeline->textbin = NULL;
4177 /* release subtitle elem */
4178 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4179 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4181 return MM_ERROR_PLAYER_INTERNAL;
4185 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4187 mmplayer_t *player = (mmplayer_t *)data;
4188 MMMessageParamType msg = {0, };
4189 GstClockTime duration = 0;
4190 gpointer text = NULL;
4191 guint text_size = 0;
4192 gboolean ret = TRUE;
4193 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4197 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4198 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4200 if (player->is_subtitle_force_drop) {
4201 LOGW("subtitle is dropped forcedly.");
4205 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4206 text = mapinfo.data;
4207 text_size = mapinfo.size;
4209 if (player->set_mode.subtitle_off) {
4210 LOGD("subtitle is OFF.");
4214 if (!text || (text_size == 0)) {
4215 LOGD("There is no subtitle to be displayed.");
4219 msg.data = (void *)text;
4221 duration = GST_BUFFER_DURATION(buffer);
4223 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4224 if (player->duration > GST_BUFFER_PTS(buffer))
4225 duration = player->duration - GST_BUFFER_PTS(buffer);
4228 LOGI("subtitle duration is invalid, subtitle duration change "
4229 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4231 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4233 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4235 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4236 gst_buffer_unmap(buffer, &mapinfo);
4243 static GstPadProbeReturn
4244 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4246 mmplayer_t *player = (mmplayer_t *)u_data;
4247 GstClockTime cur_timestamp = 0;
4248 gint64 adjusted_timestamp = 0;
4249 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4251 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4253 if (player->set_mode.subtitle_off) {
4254 LOGD("subtitle is OFF.");
4258 if (player->adjust_subtitle_pos == 0) {
4259 LOGD("nothing to do");
4263 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4264 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4266 if (adjusted_timestamp < 0) {
4267 LOGD("adjusted_timestamp under zero");
4272 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4273 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4274 GST_TIME_ARGS(cur_timestamp),
4275 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4277 return GST_PAD_PROBE_OK;
4281 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4285 /* check player and subtitlebin are created */
4286 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4287 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4289 if (position == 0) {
4290 LOGD("nothing to do");
4292 return MM_ERROR_NONE;
4295 /* check current position */
4296 player->adjust_subtitle_pos = position;
4298 LOGD("save adjust_subtitle_pos in player");
4302 return MM_ERROR_NONE;
4306 * This function is to create audio or video pipeline for playing.
4308 * @param player [in] handle of player
4310 * @return This function returns zero on success.
4315 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4317 int ret = MM_ERROR_NONE;
4318 mmplayer_gst_element_t *mainbin = NULL;
4319 MMHandleType attrs = 0;
4322 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4324 /* get profile attribute */
4325 attrs = MMPLAYER_GET_ATTRS(player);
4327 LOGE("failed to get content attribute");
4331 /* create pipeline handles */
4332 if (player->pipeline) {
4333 LOGE("pipeline should be released before create new one");
4337 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4339 /* create mainbin */
4340 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4341 if (mainbin == NULL)
4344 /* create pipeline */
4345 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4346 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4347 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4348 LOGE("failed to create pipeline");
4353 player->pipeline->mainbin = mainbin;
4355 /* create the source and decoder elements */
4356 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4357 ret = _mmplayer_gst_build_es_pipeline(player);
4359 if (MMPLAYER_USE_DECODEBIN(player))
4360 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4362 ret = _mmplayer_gst_build_pipeline_with_src(player);
4365 if (ret != MM_ERROR_NONE) {
4366 LOGE("failed to create some elements");
4370 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4371 if (__mmplayer_check_subtitle(player)
4372 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4373 LOGE("failed to create text pipeline");
4376 ret = _mmplayer_gst_add_bus_watch(player);
4377 if (ret != MM_ERROR_NONE) {
4378 LOGE("failed to add bus watch");
4383 return MM_ERROR_NONE;
4386 _mmplayer_bus_watcher_remove(player);
4387 __mmplayer_gst_destroy_pipeline(player);
4388 return MM_ERROR_PLAYER_INTERNAL;
4392 __mmplayer_reset_gapless_state(mmplayer_t *player)
4395 MMPLAYER_RETURN_IF_FAIL(player
4397 && player->pipeline->audiobin
4398 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4400 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4407 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4410 int ret = MM_ERROR_NONE;
4414 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4416 /* cleanup stuffs */
4417 MMPLAYER_FREEIF(player->type);
4418 player->no_more_pad = FALSE;
4419 player->num_dynamic_pad = 0;
4421 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4422 player->subtitle_language_list = NULL;
4423 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4425 MMPLAYER_RECONFIGURE_LOCK(player);
4426 __mmplayer_reset_gapless_state(player);
4427 MMPLAYER_RECONFIGURE_UNLOCK(player);
4429 if (player->streamer) {
4430 _mm_player_streaming_initialize(player->streamer, FALSE);
4431 _mm_player_streaming_destroy(player->streamer);
4432 player->streamer = NULL;
4435 /* cleanup unlinked mime type */
4436 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4437 MMPLAYER_FREEIF(player->unlinked_video_mime);
4438 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4440 /* cleanup running stuffs */
4441 _mmplayer_cancel_eos_timer(player);
4443 /* cleanup gst stuffs */
4444 if (player->pipeline) {
4445 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4446 GstTagList *tag_list = player->pipeline->tag_list;
4448 /* first we need to disconnect all signal hander */
4449 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4452 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4453 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4454 gst_object_unref(bus);
4456 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4457 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4458 if (ret != MM_ERROR_NONE) {
4459 LOGE("fail to change state to NULL");
4460 return MM_ERROR_PLAYER_INTERNAL;
4463 LOGW("succeeded in changing state to NULL");
4465 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4468 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4469 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4471 MMPLAYER_FREEIF(player->pipeline->audiobin);
4472 MMPLAYER_FREEIF(player->pipeline->videobin);
4473 MMPLAYER_FREEIF(player->pipeline->textbin);
4474 MMPLAYER_FREEIF(mainbin);
4478 gst_tag_list_unref(tag_list);
4480 MMPLAYER_FREEIF(player->pipeline);
4482 MMPLAYER_FREEIF(player->album_art);
4484 if (player->type_caps) {
4485 gst_caps_unref(player->type_caps);
4486 player->type_caps = NULL;
4489 if (player->v_stream_caps) {
4490 gst_caps_unref(player->v_stream_caps);
4491 player->v_stream_caps = NULL;
4494 if (player->a_stream_caps) {
4495 gst_caps_unref(player->a_stream_caps);
4496 player->a_stream_caps = NULL;
4499 if (player->s_stream_caps) {
4500 gst_caps_unref(player->s_stream_caps);
4501 player->s_stream_caps = NULL;
4503 _mmplayer_track_destroy(player);
4505 if (player->sink_elements)
4506 g_list_free(player->sink_elements);
4507 player->sink_elements = NULL;
4509 if (player->bufmgr) {
4510 tbm_bufmgr_deinit(player->bufmgr);
4511 player->bufmgr = NULL;
4514 LOGW("finished destroy pipeline");
4522 __mmplayer_gst_realize(mmplayer_t *player)
4525 int ret = MM_ERROR_NONE;
4529 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4531 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4533 ret = __mmplayer_gst_create_pipeline(player);
4535 LOGE("failed to create pipeline");
4539 /* set pipeline state to READY */
4540 /* NOTE : state change to READY must be performed sync. */
4541 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4542 ret = _mmplayer_gst_set_state(player,
4543 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4545 if (ret != MM_ERROR_NONE) {
4546 /* return error if failed to set state */
4547 LOGE("failed to set READY state");
4551 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4553 /* create dot before error-return. for debugging */
4554 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4562 __mmplayer_gst_unrealize(mmplayer_t *player)
4564 int ret = MM_ERROR_NONE;
4568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4570 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4571 MMPLAYER_PRINT_STATE(player);
4573 /* release miscellaneous information */
4574 __mmplayer_release_misc(player);
4576 /* destroy pipeline */
4577 ret = __mmplayer_gst_destroy_pipeline(player);
4578 if (ret != MM_ERROR_NONE) {
4579 LOGE("failed to destroy pipeline");
4583 /* release miscellaneous information.
4584 these info needs to be released after pipeline is destroyed. */
4585 __mmplayer_release_misc_post(player);
4587 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4595 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4600 LOGW("set_message_callback is called with invalid player handle");
4601 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4604 player->msg_cb = callback;
4605 player->msg_cb_param = user_param;
4607 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4611 return MM_ERROR_NONE;
4615 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4617 int ret = MM_ERROR_NONE;
4622 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4623 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4624 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4626 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4628 if (strstr(uri, "es_buff://")) {
4629 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4630 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4631 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4632 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4634 tmp = g_ascii_strdown(uri, strlen(uri));
4635 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4636 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4638 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4640 } else if (strstr(uri, "mms://")) {
4641 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4642 } else if ((path = strstr(uri, "mem://"))) {
4643 ret = __mmplayer_set_mem_uri(data, path, param);
4645 ret = __mmplayer_set_file_uri(data, uri);
4648 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4649 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4650 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4651 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4653 /* dump parse result */
4654 SECURE_LOGW("incoming uri : %s", uri);
4655 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4656 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4664 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4667 mmplayer_t *player = NULL;
4668 MMMessageParamType msg = {0, };
4670 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4675 LOGE("user_data is null");
4679 player = (mmplayer_t *)user_data;
4681 if (!player->pipeline || !player->attrs) {
4682 LOGW("not initialized");
4686 LOGD("cmd lock player, cmd state : %d", player->cmd);
4687 MMPLAYER_CMD_LOCK(player);
4688 LOGD("cmd locked player");
4690 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4691 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4692 LOGW("player already destroyed");
4693 MMPLAYER_CMD_UNLOCK(player);
4697 player->interrupted_by_resource = TRUE;
4699 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4701 /* get last play position */
4702 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4703 msg.union_type = MM_MSG_UNION_TIME;
4704 msg.time.elapsed = pos;
4705 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4707 LOGW("failed to get play position.");
4710 LOGD("video resource conflict so, resource will be freed by unrealizing");
4711 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4712 LOGE("failed to unrealize");
4714 MMPLAYER_CMD_UNLOCK(player);
4716 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4717 player->hw_resource[res_idx] = NULL;
4721 return TRUE; /* release all the resources */
4725 __mmplayer_initialize_video_roi(mmplayer_t *player)
4727 player->video_roi.scale_x = 0.0;
4728 player->video_roi.scale_y = 0.0;
4729 player->video_roi.scale_width = 1.0;
4730 player->video_roi.scale_height = 1.0;
4734 _mmplayer_create_player(MMHandleType handle)
4736 int ret = MM_ERROR_PLAYER_INTERNAL;
4737 bool enabled = false;
4739 mmplayer_t *player = MM_PLAYER_CAST(handle);
4743 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4745 /* initialize player state */
4746 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4747 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4748 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4749 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4751 /* check current state */
4752 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4754 /* construct attributes */
4755 player->attrs = _mmplayer_construct_attribute(handle);
4757 if (!player->attrs) {
4758 LOGE("Failed to construct attributes");
4762 /* initialize gstreamer with configured parameter */
4763 if (!__mmplayer_init_gstreamer(player)) {
4764 LOGE("Initializing gstreamer failed");
4765 _mmplayer_deconstruct_attribute(handle);
4769 /* create lock. note that g_tread_init() has already called in gst_init() */
4770 g_mutex_init(&player->fsink_lock);
4772 /* create update tag lock */
4773 g_mutex_init(&player->update_tag_lock);
4775 /* create gapless play mutex */
4776 g_mutex_init(&player->gapless_play_thread_mutex);
4778 /* create gapless play cond */
4779 g_cond_init(&player->gapless_play_thread_cond);
4781 /* create gapless play thread */
4782 player->gapless_play_thread =
4783 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4784 if (!player->gapless_play_thread) {
4785 LOGE("failed to create gapless play thread");
4786 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4787 g_mutex_clear(&player->gapless_play_thread_mutex);
4788 g_cond_clear(&player->gapless_play_thread_cond);
4792 player->bus_msg_q = g_queue_new();
4793 if (!player->bus_msg_q) {
4794 LOGE("failed to create queue for bus_msg");
4795 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4799 ret = _mmplayer_initialize_video_capture(player);
4800 if (ret != MM_ERROR_NONE) {
4801 LOGW("video capture is not supported");
4802 /* do not handle as error for headless profile */
4805 /* initialize resource manager */
4806 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4807 __resource_release_cb, player, &player->resource_manager)
4808 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4809 LOGE("failed to create resource manager");
4810 ret = MM_ERROR_PLAYER_INTERNAL;
4814 /* create video bo lock and cond */
4815 g_mutex_init(&player->video_bo_mutex);
4816 g_cond_init(&player->video_bo_cond);
4818 /* create subtitle info lock and cond */
4819 g_mutex_init(&player->subtitle_info_mutex);
4820 g_cond_init(&player->subtitle_info_cond);
4822 player->streaming_type = STREAMING_SERVICE_NONE;
4824 /* give default value of audio effect setting */
4825 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4826 player->sound.rg_enable = false;
4827 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4829 player->play_subtitle = FALSE;
4830 player->has_closed_caption = FALSE;
4831 player->pending_resume = FALSE;
4832 if (player->ini.dump_element_keyword[0][0] == '\0')
4833 player->ini.set_dump_element_flag = FALSE;
4835 player->ini.set_dump_element_flag = TRUE;
4837 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4838 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4839 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4841 /* Set video360 settings to their defaults for just-created player.
4844 player->is_360_feature_enabled = FALSE;
4845 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4846 LOGI("spherical feature info: %d", enabled);
4848 player->is_360_feature_enabled = TRUE;
4850 LOGE("failed to get spherical feature info");
4853 player->is_content_spherical = FALSE;
4854 player->is_video360_enabled = TRUE;
4855 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4856 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4857 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4858 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4859 player->video360_zoom = 1.0f;
4860 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4861 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4863 __mmplayer_initialize_video_roi(player);
4865 /* set player state to null */
4866 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4867 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4871 return MM_ERROR_NONE;
4875 g_mutex_clear(&player->fsink_lock);
4876 /* free update tag lock */
4877 g_mutex_clear(&player->update_tag_lock);
4878 g_queue_free(player->bus_msg_q);
4879 player->bus_msg_q = NULL;
4880 /* free gapless play thread */
4881 if (player->gapless_play_thread) {
4882 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4883 player->gapless_play_thread_exit = TRUE;
4884 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4885 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4887 g_thread_join(player->gapless_play_thread);
4888 player->gapless_play_thread = NULL;
4890 g_mutex_clear(&player->gapless_play_thread_mutex);
4891 g_cond_clear(&player->gapless_play_thread_cond);
4894 /* release attributes */
4895 _mmplayer_deconstruct_attribute(handle);
4903 __mmplayer_init_gstreamer(mmplayer_t *player)
4905 static gboolean initialized = FALSE;
4906 static const int max_argc = 50;
4908 gchar **argv = NULL;
4909 gchar **argv2 = NULL;
4915 LOGD("gstreamer already initialized.");
4920 argc = malloc(sizeof(int));
4921 argv = malloc(sizeof(gchar *) * max_argc);
4922 argv2 = malloc(sizeof(gchar *) * max_argc);
4924 if (!argc || !argv || !argv2)
4927 memset(argv, 0, sizeof(gchar *) * max_argc);
4928 memset(argv2, 0, sizeof(gchar *) * max_argc);
4932 argv[0] = g_strdup("mmplayer");
4935 for (i = 0; i < 5; i++) {
4936 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4937 if (strlen(player->ini.gst_param[i]) > 0) {
4938 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4943 /* we would not do fork for scanning plugins */
4944 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4947 /* check disable registry scan */
4948 if (player->ini.skip_rescan) {
4949 argv[*argc] = g_strdup("--gst-disable-registry-update");
4953 /* check disable segtrap */
4954 if (player->ini.disable_segtrap) {
4955 argv[*argc] = g_strdup("--gst-disable-segtrap");
4959 LOGD("initializing gstreamer with following parameter");
4960 LOGD("argc : %d", *argc);
4963 for (i = 0; i < arg_count; i++) {
4965 LOGD("argv[%d] : %s", i, argv2[i]);
4968 /* initializing gstreamer */
4969 if (!gst_init_check(argc, &argv, &err)) {
4970 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4977 for (i = 0; i < arg_count; i++) {
4979 LOGD("release - argv[%d] : %s", i, argv2[i]);
4981 MMPLAYER_FREEIF(argv2[i]);
4984 MMPLAYER_FREEIF(argv);
4985 MMPLAYER_FREEIF(argv2);
4986 MMPLAYER_FREEIF(argc);
4996 for (i = 0; i < arg_count; i++) {
4997 LOGD("free[%d] : %s", i, argv2[i]);
4998 MMPLAYER_FREEIF(argv2[i]);
5001 MMPLAYER_FREEIF(argv);
5002 MMPLAYER_FREEIF(argv2);
5003 MMPLAYER_FREEIF(argc);
5009 __mmplayer_check_async_state_transition(mmplayer_t *player)
5011 GstState element_state = GST_STATE_VOID_PENDING;
5012 GstState element_pending_state = GST_STATE_VOID_PENDING;
5013 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5014 GstElement *element = NULL;
5015 gboolean async = FALSE;
5017 /* check player handle */
5018 MMPLAYER_RETURN_IF_FAIL(player &&
5020 player->pipeline->mainbin &&
5021 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5024 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5026 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5027 LOGD("don't need to check the pipeline state");
5031 MMPLAYER_PRINT_STATE(player);
5033 /* wait for state transition */
5034 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5035 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5037 if (ret == GST_STATE_CHANGE_FAILURE) {
5038 LOGE(" [%s] state : %s pending : %s",
5039 GST_ELEMENT_NAME(element),
5040 gst_element_state_get_name(element_state),
5041 gst_element_state_get_name(element_pending_state));
5043 /* dump state of all element */
5044 _mmplayer_dump_pipeline_state(player);
5049 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5054 _mmplayer_destroy(MMHandleType handle)
5056 mmplayer_t *player = MM_PLAYER_CAST(handle);
5060 /* check player handle */
5061 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5063 /* destroy can called at anytime */
5064 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5066 /* check async state transition */
5067 __mmplayer_check_async_state_transition(player);
5069 /* release gapless play thread */
5070 if (player->gapless_play_thread) {
5071 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5072 player->gapless_play_thread_exit = TRUE;
5073 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5074 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5076 LOGD("waiting for gapless play thread exit");
5077 g_thread_join(player->gapless_play_thread);
5078 g_mutex_clear(&player->gapless_play_thread_mutex);
5079 g_cond_clear(&player->gapless_play_thread_cond);
5080 LOGD("gapless play thread released");
5083 _mmplayer_release_video_capture(player);
5085 /* release miscellaneous information */
5086 __mmplayer_release_misc(player);
5088 /* release pipeline */
5089 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5090 LOGE("failed to destroy pipeline");
5091 return MM_ERROR_PLAYER_INTERNAL;
5094 __mmplayer_destroy_hw_resource(player);
5096 g_queue_free(player->bus_msg_q);
5098 /* release subtitle info lock and cond */
5099 g_mutex_clear(&player->subtitle_info_mutex);
5100 g_cond_clear(&player->subtitle_info_cond);
5102 __mmplayer_release_dump_list(player->dump_list);
5104 /* release miscellaneous information.
5105 these info needs to be released after pipeline is destroyed. */
5106 __mmplayer_release_misc_post(player);
5108 /* release attributes */
5109 _mmplayer_deconstruct_attribute(handle);
5111 if (player->uri_info.uri_list) {
5112 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5113 player->uri_info.uri_list = NULL;
5117 g_mutex_clear(&player->fsink_lock);
5120 g_mutex_clear(&player->update_tag_lock);
5122 /* release video bo lock and cond */
5123 g_mutex_clear(&player->video_bo_mutex);
5124 g_cond_clear(&player->video_bo_cond);
5128 return MM_ERROR_NONE;
5132 _mmplayer_realize(MMHandleType hplayer)
5134 mmplayer_t *player = (mmplayer_t *)hplayer;
5135 int ret = MM_ERROR_NONE;
5138 MMHandleType attrs = 0;
5142 /* check player handle */
5143 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5145 /* check current state */
5146 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5148 attrs = MMPLAYER_GET_ATTRS(player);
5150 LOGE("fail to get attributes.");
5151 return MM_ERROR_PLAYER_INTERNAL;
5153 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5154 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5156 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5157 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5159 if (ret != MM_ERROR_NONE) {
5160 LOGE("failed to parse profile");
5165 if (uri && (strstr(uri, "es_buff://"))) {
5166 if (strstr(uri, "es_buff://push_mode"))
5167 player->es_player_push_mode = TRUE;
5169 player->es_player_push_mode = FALSE;
5172 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5173 LOGW("mms protocol is not supported format.");
5174 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5177 if (MMPLAYER_IS_STREAMING(player))
5178 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5180 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5182 player->smooth_streaming = FALSE;
5183 player->videodec_linked = 0;
5184 player->audiodec_linked = 0;
5185 player->textsink_linked = 0;
5186 player->is_external_subtitle_present = FALSE;
5187 player->is_external_subtitle_added_now = FALSE;
5188 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5189 player->video360_metadata.is_spherical = -1;
5190 player->is_openal_plugin_used = FALSE;
5191 player->subtitle_language_list = NULL;
5192 player->is_subtitle_force_drop = FALSE;
5194 _mmplayer_track_initialize(player);
5195 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5197 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5198 gint prebuffer_ms = 0, rebuffer_ms = 0;
5200 player->streamer = _mm_player_streaming_create();
5201 _mm_player_streaming_initialize(player->streamer, TRUE);
5203 mm_attrs_multiple_get(player->attrs, NULL,
5204 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5205 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5207 if (prebuffer_ms > 0) {
5208 prebuffer_ms = MAX(prebuffer_ms, 1000);
5209 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5212 if (rebuffer_ms > 0) {
5213 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5214 rebuffer_ms = MAX(rebuffer_ms, 1000);
5215 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5218 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5219 player->streamer->buffering_req.rebuffer_time);
5222 /* realize pipeline */
5223 ret = __mmplayer_gst_realize(player);
5224 if (ret != MM_ERROR_NONE)
5225 LOGE("fail to realize the player.");
5227 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5235 _mmplayer_unrealize(MMHandleType hplayer)
5237 mmplayer_t *player = (mmplayer_t *)hplayer;
5238 int ret = MM_ERROR_NONE;
5239 int rm_ret = MM_ERROR_NONE;
5240 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5244 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5246 MMPLAYER_CMD_UNLOCK(player);
5247 _mmplayer_bus_watcher_remove(player);
5248 /* destroy the gst bus msg thread which is created during realize.
5249 this funct have to be called before getting cmd lock. */
5250 _mmplayer_bus_msg_thread_destroy(player);
5251 MMPLAYER_CMD_LOCK(player);
5253 /* check current state */
5254 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5256 /* check async state transition */
5257 __mmplayer_check_async_state_transition(player);
5259 /* unrealize pipeline */
5260 ret = __mmplayer_gst_unrealize(player);
5262 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5263 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5264 if (rm_ret != MM_ERROR_NONE)
5265 LOGE("failed to release [%d] resources", res_idx);
5268 player->interrupted_by_resource = FALSE;
5275 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5277 mmplayer_t *player = (mmplayer_t *)hplayer;
5279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5281 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5285 _mmplayer_get_state(MMHandleType hplayer, int *state)
5287 mmplayer_t *player = (mmplayer_t *)hplayer;
5289 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5291 *state = MMPLAYER_CURRENT_STATE(player);
5293 return MM_ERROR_NONE;
5297 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5299 GstElement *vol_element = NULL;
5300 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5303 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5304 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5306 /* check pipeline handle */
5307 if (!player->pipeline || !player->pipeline->audiobin) {
5308 LOGD("'%s' will be applied when audiobin is created", prop_name);
5310 /* NOTE : stored value will be used in create_audiobin
5311 * returning MM_ERROR_NONE here makes application to able to
5312 * set audio volume or mute at anytime.
5314 return MM_ERROR_NONE;
5317 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5318 volume_elem_id = MMPLAYER_A_SINK;
5320 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5322 LOGE("failed to get vol element %d", volume_elem_id);
5323 return MM_ERROR_PLAYER_INTERNAL;
5326 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5328 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5329 LOGE("there is no '%s' property", prop_name);
5330 return MM_ERROR_PLAYER_INTERNAL;
5333 if (!strcmp(prop_name, "volume")) {
5334 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5335 } else if (!strcmp(prop_name, "mute")) {
5336 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5338 LOGE("invalid property %s", prop_name);
5339 return MM_ERROR_PLAYER_INTERNAL;
5342 return MM_ERROR_NONE;
5346 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5348 int ret = MM_ERROR_NONE;
5349 mmplayer_t *player = (mmplayer_t *)hplayer;
5352 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5354 LOGD("volume = %f", volume);
5356 /* invalid factor range or not */
5357 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5358 LOGE("Invalid volume value");
5359 return MM_ERROR_INVALID_ARGUMENT;
5362 player->sound.volume = volume;
5364 ret = __mmplayer_gst_set_volume_property(player, "volume");
5371 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5373 mmplayer_t *player = (mmplayer_t *)hplayer;
5377 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5378 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5380 *volume = player->sound.volume;
5382 LOGD("current vol = %f", *volume);
5385 return MM_ERROR_NONE;
5389 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5391 int ret = MM_ERROR_NONE;
5392 mmplayer_t *player = (mmplayer_t *)hplayer;
5395 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5397 LOGD("mute = %d", mute);
5399 player->sound.mute = mute;
5401 ret = __mmplayer_gst_set_volume_property(player, "mute");
5408 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5410 mmplayer_t *player = (mmplayer_t *)hplayer;
5414 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5415 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5417 *mute = player->sound.mute;
5419 LOGD("current mute = %d", *mute);
5423 return MM_ERROR_NONE;
5427 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5429 mmplayer_t *player = (mmplayer_t *)hplayer;
5433 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5435 player->audio_stream_changed_cb = callback;
5436 player->audio_stream_changed_cb_user_param = user_param;
5437 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5441 return MM_ERROR_NONE;
5445 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5447 mmplayer_t *player = (mmplayer_t *)hplayer;
5451 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5453 player->audio_decoded_cb = callback;
5454 player->audio_decoded_cb_user_param = user_param;
5455 player->audio_extract_opt = opt;
5456 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5460 return MM_ERROR_NONE;
5464 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5466 mmplayer_t *player = (mmplayer_t *)hplayer;
5470 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5472 if (callback && !player->bufmgr)
5473 player->bufmgr = tbm_bufmgr_init(-1);
5475 player->set_mode.video_export = (callback) ? true : false;
5476 player->video_decoded_cb = callback;
5477 player->video_decoded_cb_user_param = user_param;
5479 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5483 return MM_ERROR_NONE;
5487 _mmplayer_start(MMHandleType hplayer)
5489 mmplayer_t *player = (mmplayer_t *)hplayer;
5490 gint ret = MM_ERROR_NONE;
5494 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5496 /* check current state */
5497 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5499 /* start pipeline */
5500 ret = _mmplayer_gst_start(player);
5501 if (ret != MM_ERROR_NONE)
5502 LOGE("failed to start player.");
5504 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5505 LOGD("force playing start even during buffering");
5506 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5514 /* NOTE: post "not supported codec message" to application
5515 * when one codec is not found during AUTOPLUGGING in MSL.
5516 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5517 * And, if any codec is not found, don't send message here.
5518 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5521 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5523 MMMessageParamType msg_param;
5524 memset(&msg_param, 0, sizeof(MMMessageParamType));
5525 gboolean post_msg_direct = FALSE;
5529 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5531 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5532 player->not_supported_codec, player->can_support_codec);
5534 if (player->not_found_demuxer) {
5535 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5536 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5538 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5539 MMPLAYER_FREEIF(msg_param.data);
5541 return MM_ERROR_NONE;
5544 if (player->not_supported_codec) {
5545 if (player->can_support_codec) {
5546 // There is one codec to play
5547 post_msg_direct = TRUE;
5549 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5550 post_msg_direct = TRUE;
5553 if (post_msg_direct) {
5554 MMMessageParamType msg_param;
5555 memset(&msg_param, 0, sizeof(MMMessageParamType));
5557 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5558 LOGW("not found AUDIO codec, posting error code to application.");
5560 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5561 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5562 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5563 LOGW("not found VIDEO codec, posting error code to application.");
5565 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5566 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5569 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5571 MMPLAYER_FREEIF(msg_param.data);
5573 return MM_ERROR_NONE;
5575 // no any supported codec case
5576 LOGW("not found any codec, posting error code to application.");
5578 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5579 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5580 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5582 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5583 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5586 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5588 MMPLAYER_FREEIF(msg_param.data);
5594 return MM_ERROR_NONE;
5597 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5599 GstState element_state = GST_STATE_VOID_PENDING;
5600 GstState element_pending_state = GST_STATE_VOID_PENDING;
5601 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5602 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5604 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5606 MMPLAYER_RECONFIGURE_LOCK(player);
5607 if (!player->gapless.reconfigure) {
5608 MMPLAYER_RECONFIGURE_UNLOCK(player);
5612 LOGI("reconfigure is under process");
5613 MMPLAYER_RECONFIGURE_WAIT(player);
5614 MMPLAYER_RECONFIGURE_UNLOCK(player);
5615 LOGI("reconfigure is completed.");
5617 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5618 &element_state, &element_pending_state, timeout * GST_SECOND);
5619 if (result == GST_STATE_CHANGE_FAILURE)
5620 LOGW("failed to get pipeline state in %d sec", timeout);
5625 /* NOTE : it should be able to call 'stop' anytime*/
5627 _mmplayer_stop(MMHandleType hplayer)
5629 mmplayer_t *player = (mmplayer_t *)hplayer;
5630 int ret = MM_ERROR_NONE;
5634 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5636 /* check current state */
5637 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5639 /* need to wait till the rebuilding pipeline is completed */
5640 __mmplayer_check_pipeline_reconfigure_state(player);
5641 MMPLAYER_RECONFIGURE_LOCK(player);
5642 __mmplayer_reset_gapless_state(player);
5643 MMPLAYER_RECONFIGURE_UNLOCK(player);
5645 /* NOTE : application should not wait for EOS after calling STOP */
5646 _mmplayer_cancel_eos_timer(player);
5649 player->seek_state = MMPLAYER_SEEK_NONE;
5652 ret = _mmplayer_gst_stop(player);
5654 if (ret != MM_ERROR_NONE)
5655 LOGE("failed to stop player.");
5663 _mmplayer_pause(MMHandleType hplayer)
5665 mmplayer_t *player = (mmplayer_t *)hplayer;
5666 gint64 pos_nsec = 0;
5667 gboolean async = FALSE;
5668 gint ret = MM_ERROR_NONE;
5672 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5674 /* check current state */
5675 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5677 /* check pipeline reconfigure state */
5678 __mmplayer_check_pipeline_reconfigure_state(player);
5680 switch (MMPLAYER_CURRENT_STATE(player)) {
5681 case MM_PLAYER_STATE_READY:
5683 /* check prepare async or not.
5684 * In the case of streaming playback, it's recommended to avoid blocking wait.
5686 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5687 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5689 /* Changing back sync of rtspsrc to async */
5690 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5691 LOGD("async prepare working mode for rtsp");
5697 case MM_PLAYER_STATE_PLAYING:
5699 /* NOTE : store current point to overcome some bad operation
5700 *(returning zero when getting current position in paused state) of some
5703 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5704 LOGW("getting current position failed in paused");
5706 player->last_position = pos_nsec;
5708 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5709 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5710 This causes problem is position calculation during normal pause resume scenarios also.
5711 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5712 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5713 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5714 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5720 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5721 LOGD("doing async pause in case of ms buff src");
5725 /* pause pipeline */
5726 ret = _mmplayer_gst_pause(player, async);
5727 if (ret != MM_ERROR_NONE) {
5728 LOGE("failed to pause player. ret : 0x%x", ret);
5729 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5733 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5734 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5735 LOGE("failed to update display_rotation");
5739 return MM_ERROR_NONE;
5742 /* in case of streaming, pause could take long time.*/
5744 _mmplayer_abort_pause(MMHandleType hplayer)
5746 mmplayer_t *player = (mmplayer_t *)hplayer;
5747 int ret = MM_ERROR_NONE;
5751 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5753 player->pipeline->mainbin,
5754 MM_ERROR_PLAYER_NOT_INITIALIZED);
5756 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5757 LOGD("set the videobin state to READY");
5758 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5759 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5763 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5764 LOGD("set the audiobin state to READY");
5765 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5766 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5770 LOGD("set the pipeline state to READY");
5771 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5772 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5774 if (ret != MM_ERROR_NONE) {
5775 LOGE("fail to change state to READY");
5776 return MM_ERROR_PLAYER_INTERNAL;
5779 LOGD("succeeded in changing state to READY");
5784 _mmplayer_resume(MMHandleType hplayer)
5786 mmplayer_t *player = (mmplayer_t *)hplayer;
5787 int ret = MM_ERROR_NONE;
5788 gboolean async = FALSE;
5792 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5794 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5795 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5796 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5800 /* Changing back sync mode rtspsrc to async */
5801 LOGD("async resume for rtsp case");
5805 /* check current state */
5806 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5808 ret = _mmplayer_gst_resume(player, async);
5809 if (ret != MM_ERROR_NONE)
5810 LOGE("failed to resume player.");
5812 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5813 LOGD("force resume even during buffering");
5814 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5823 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5825 mmplayer_t *player = (mmplayer_t *)hplayer;
5826 gint64 pos_nsec = 0;
5827 int ret = MM_ERROR_NONE;
5829 signed long long start = 0, stop = 0;
5830 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5833 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5834 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5836 /* The sound of video is not supported under 0.0 and over 2.0. */
5837 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5838 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5841 _mmplayer_set_mute(hplayer, mute);
5843 if (player->playback_rate == rate)
5844 return MM_ERROR_NONE;
5846 /* If the position is reached at start potion during fast backward, EOS is posted.
5847 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5849 player->playback_rate = rate;
5851 current_state = MMPLAYER_CURRENT_STATE(player);
5853 if (current_state != MM_PLAYER_STATE_PAUSED)
5854 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5856 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5858 if ((current_state == MM_PLAYER_STATE_PAUSED)
5859 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5860 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5861 pos_nsec = player->last_position;
5866 stop = GST_CLOCK_TIME_NONE;
5868 start = GST_CLOCK_TIME_NONE;
5872 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5873 player->playback_rate,
5875 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5876 GST_SEEK_TYPE_SET, start,
5877 GST_SEEK_TYPE_SET, stop)) {
5878 LOGE("failed to set speed playback");
5879 return MM_ERROR_PLAYER_SEEK;
5882 LOGD("succeeded to set speed playback as %0.1f", rate);
5886 return MM_ERROR_NONE;;
5890 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5892 mmplayer_t *player = (mmplayer_t *)hplayer;
5893 int ret = MM_ERROR_NONE;
5897 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5899 /* check pipeline reconfigure state */
5900 __mmplayer_check_pipeline_reconfigure_state(player);
5902 ret = _mmplayer_gst_set_position(player, position, FALSE);
5910 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5912 mmplayer_t *player = (mmplayer_t *)hplayer;
5913 int ret = MM_ERROR_NONE;
5915 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5916 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5918 if (g_strrstr(player->type, "video/mpegts"))
5919 __mmplayer_update_duration_value(player);
5921 *duration = player->duration;
5926 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5928 mmplayer_t *player = (mmplayer_t *)hplayer;
5929 int ret = MM_ERROR_NONE;
5931 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5933 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5939 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5941 mmplayer_t *player = (mmplayer_t *)hplayer;
5942 int ret = MM_ERROR_NONE;
5946 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5948 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5956 __mmplayer_is_midi_type(gchar *str_caps)
5958 if ((g_strrstr(str_caps, "audio/midi")) ||
5959 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5960 (g_strrstr(str_caps, "application/x-smaf")) ||
5961 (g_strrstr(str_caps, "audio/x-imelody")) ||
5962 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5963 (g_strrstr(str_caps, "audio/xmf")) ||
5964 (g_strrstr(str_caps, "audio/mxmf"))) {
5973 __mmplayer_is_only_mp3_type(gchar *str_caps)
5975 if (g_strrstr(str_caps, "application/x-id3") ||
5976 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5982 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5984 GstStructure *caps_structure = NULL;
5985 gint samplerate = 0;
5989 MMPLAYER_RETURN_IF_FAIL(player && caps);
5991 caps_structure = gst_caps_get_structure(caps, 0);
5993 /* set stream information */
5994 gst_structure_get_int(caps_structure, "rate", &samplerate);
5995 gst_structure_get_int(caps_structure, "channels", &channels);
5997 mm_player_set_attribute((MMHandleType)player, NULL,
5998 "content_audio_samplerate", samplerate,
5999 "content_audio_channels", channels, NULL);
6001 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6005 __mmplayer_update_content_type_info(mmplayer_t *player)
6008 MMPLAYER_RETURN_IF_FAIL(player && player->type);
6010 if (__mmplayer_is_midi_type(player->type)) {
6011 player->bypass_audio_effect = TRUE;
6015 if (!player->streamer) {
6016 LOGD("no need to check streaming type");
6020 if (g_strrstr(player->type, "application/x-hls")) {
6021 /* If it can't know exact type when it parses uri because of redirection case,
6022 * it will be fixed by typefinder or when doing autoplugging.
6024 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6025 player->streamer->is_adaptive_streaming = TRUE;
6026 } else if (g_strrstr(player->type, "application/dash+xml")) {
6027 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6028 player->streamer->is_adaptive_streaming = TRUE;
6031 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6032 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
6033 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6035 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6036 if (player->streamer->is_adaptive_streaming)
6037 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6039 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6043 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6048 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6049 GstCaps *caps, gpointer data)
6051 mmplayer_t *player = (mmplayer_t *)data;
6055 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6057 /* store type string */
6058 if (player->type_caps) {
6059 gst_caps_unref(player->type_caps);
6060 player->type_caps = NULL;
6063 player->type_caps = gst_caps_copy(caps);
6064 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
6066 MMPLAYER_FREEIF(player->type);
6067 player->type = gst_caps_to_string(caps);
6069 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6070 player, player->type, probability, gst_caps_get_size(caps));
6072 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6073 (g_strrstr(player->type, "audio/x-raw-int"))) {
6074 LOGE("not support media format");
6076 if (player->msg_posted == FALSE) {
6077 MMMessageParamType msg_param;
6078 memset(&msg_param, 0, sizeof(MMMessageParamType));
6080 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6081 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6083 /* don't post more if one was sent already */
6084 player->msg_posted = TRUE;
6089 __mmplayer_update_content_type_info(player);
6091 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6094 pad = gst_element_get_static_pad(tf, "src");
6096 LOGE("fail to get typefind src pad.");
6100 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6101 gboolean async = FALSE;
6102 LOGE("failed to autoplug %s", player->type);
6104 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6106 if (async && player->msg_posted == FALSE)
6107 __mmplayer_handle_missed_plugin(player);
6109 gst_object_unref(GST_OBJECT(pad));
6116 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6118 GstElement *decodebin = NULL;
6122 /* create decodebin */
6123 decodebin = gst_element_factory_make("decodebin", NULL);
6126 LOGE("fail to create decodebin");
6130 /* raw pad handling signal */
6131 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6132 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6134 /* no-more-pad pad handling signal */
6135 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6136 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6138 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6139 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6141 /* This signal is emitted when a pad for which there is no further possible
6142 decoding is added to the decodebin.*/
6143 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6144 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6146 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6147 before looking for any elements that can handle that stream.*/
6148 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6149 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6151 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6152 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6153 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6155 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6156 before looking for any elements that can handle that stream.*/
6157 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6158 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6160 /* This signal is emitted once decodebin has finished decoding all the data.*/
6161 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6162 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6164 /* This signal is emitted when a element is added to the bin.*/
6165 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6166 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6173 __mmplayer_gst_make_queue2(mmplayer_t *player)
6175 GstElement *queue2 = NULL;
6176 gint64 dur_bytes = 0L;
6177 mmplayer_gst_element_t *mainbin = NULL;
6178 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6181 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6183 mainbin = player->pipeline->mainbin;
6185 queue2 = gst_element_factory_make("queue2", "queue2");
6187 LOGE("failed to create buffering queue element");
6191 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6192 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6194 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6196 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6197 * skip the pull mode(file or ring buffering) setting. */
6198 if (dur_bytes > 0) {
6199 if (!g_strrstr(player->type, "video/mpegts")) {
6200 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6201 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6207 _mm_player_streaming_set_queue2(player->streamer,
6211 (guint64)dur_bytes); /* no meaning at the moment */
6217 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6219 mmplayer_gst_element_t *mainbin = NULL;
6220 GstElement *decodebin = NULL;
6221 GstElement *queue2 = NULL;
6222 GstPad *sinkpad = NULL;
6223 GstPad *qsrcpad = NULL;
6226 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6228 mainbin = player->pipeline->mainbin;
6230 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6232 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6233 LOGW("need to check: muxed buffer is not null");
6236 queue2 = __mmplayer_gst_make_queue2(player);
6238 LOGE("failed to make queue2");
6242 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6243 LOGE("failed to add buffering queue");
6247 sinkpad = gst_element_get_static_pad(queue2, "sink");
6248 qsrcpad = gst_element_get_static_pad(queue2, "src");
6250 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6251 LOGE("failed to link [%s:%s]-[%s:%s]",
6252 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6256 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6257 LOGE("failed to sync queue2 state with parent");
6261 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6262 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6266 gst_object_unref(GST_OBJECT(sinkpad));
6270 /* create decodebin */
6271 decodebin = _mmplayer_gst_make_decodebin(player);
6273 LOGE("failed to make decodebin");
6277 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6278 LOGE("failed to add decodebin");
6282 /* to force caps on the decodebin element and avoid reparsing stuff by
6283 * typefind. It also avoids a deadlock in the way typefind activates pads in
6284 * the state change */
6285 g_object_set(decodebin, "sink-caps", caps, NULL);
6287 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6289 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6290 LOGE("failed to link [%s:%s]-[%s:%s]",
6291 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6295 gst_object_unref(GST_OBJECT(sinkpad));
6297 gst_object_unref(GST_OBJECT(qsrcpad));
6300 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6301 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6303 /* set decodebin property about buffer in streaming playback. *
6304 * in case of HLS/DASH, it does not need to have big buffer *
6305 * because it is kind of adaptive streaming. */
6306 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6307 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6308 gint high_percent = 0;
6310 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6311 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6313 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6315 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6317 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6318 "high-percent", high_percent,
6319 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6320 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6321 "max-size-buffers", 0, NULL); // disable or automatic
6324 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6325 LOGE("failed to sync decodebin state with parent");
6336 gst_object_unref(GST_OBJECT(sinkpad));
6339 gst_object_unref(GST_OBJECT(qsrcpad));
6342 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6343 * You need to explicitly set elements to the NULL state before
6344 * dropping the final reference, to allow them to clean up.
6346 gst_element_set_state(queue2, GST_STATE_NULL);
6348 /* And, it still has a parent "player".
6349 * You need to let the parent manage the object instead of unreffing the object directly.
6351 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6352 LOGE("failed to remove queue2");
6353 gst_object_unref(queue2);
6359 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6360 * You need to explicitly set elements to the NULL state before
6361 * dropping the final reference, to allow them to clean up.
6363 gst_element_set_state(decodebin, GST_STATE_NULL);
6365 /* And, it still has a parent "player".
6366 * You need to let the parent manage the object instead of unreffing the object directly.
6369 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6370 LOGE("failed to remove decodebin");
6371 gst_object_unref(decodebin);
6380 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6384 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6385 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6387 LOGD("class : %s, mime : %s", factory_class, mime);
6389 /* add missing plugin */
6390 /* NOTE : msl should check missing plugin for image mime type.
6391 * Some motion jpeg clips can have playable audio track.
6392 * So, msl have to play audio after displaying popup written video format not supported.
6394 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6395 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6396 LOGD("not found demuxer");
6397 player->not_found_demuxer = TRUE;
6398 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6404 if (!g_strrstr(factory_class, "Demuxer")) {
6405 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6406 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6407 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6409 /* check that clip have multi tracks or not */
6410 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6411 LOGD("video plugin is already linked");
6413 LOGW("add VIDEO to missing plugin");
6414 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6415 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6417 } else if (g_str_has_prefix(mime, "audio")) {
6418 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6419 LOGD("audio plugin is already linked");
6421 LOGW("add AUDIO to missing plugin");
6422 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6423 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6431 return MM_ERROR_NONE;
6435 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6437 mmplayer_t *player = (mmplayer_t *)data;
6441 MMPLAYER_RETURN_IF_FAIL(player);
6443 /* remove fakesink. */
6444 if (!_mmplayer_gst_remove_fakesink(player,
6445 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6446 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6447 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6448 * source element are not same. To overcome this situation, this function will called
6449 * several places and several times. Therefore, this is not an error case.
6454 LOGD("[handle: %p] pipeline has completely constructed", player);
6456 if ((player->msg_posted == FALSE) &&
6457 (player->cmd >= MMPLAYER_COMMAND_START))
6458 __mmplayer_handle_missed_plugin(player);
6460 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6464 __mmplayer_check_profile(void)
6467 static int profile_tv = -1;
6469 if (__builtin_expect(profile_tv != -1, 1))
6472 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6473 switch (*profileName) {
6488 __mmplayer_get_next_uri(mmplayer_t *player)
6490 mmplayer_parse_profile_t profile;
6492 guint num_of_list = 0;
6495 num_of_list = g_list_length(player->uri_info.uri_list);
6496 uri_idx = player->uri_info.uri_idx;
6498 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6499 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6500 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6502 LOGW("next uri does not exist");
6506 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6507 LOGE("failed to parse profile");
6511 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6512 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6513 LOGW("uri type is not supported(%d)", profile.uri_type);
6517 LOGD("success to find next uri %d", uri_idx);
6521 if (!uri || uri_idx == num_of_list) {
6522 LOGE("failed to find next uri");
6526 player->uri_info.uri_idx = uri_idx;
6527 if (mm_player_set_attribute((MMHandleType)player, NULL,
6528 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6529 LOGE("failed to set attribute");
6533 SECURE_LOGD("next playback uri: %s", uri);
6538 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6540 #define REPEAT_COUNT_INFINITE -1
6541 #define REPEAT_COUNT_MIN 2
6542 #define ORIGINAL_URI_ONLY 1
6544 MMHandleType attrs = 0;
6548 guint num_of_uri = 0;
6549 int profile_tv = -1;
6553 LOGD("checking for gapless play option");
6555 if (player->build_audio_offload) {
6556 LOGE("offload path is not supportable.");
6560 if (player->pipeline->textbin) {
6561 LOGE("subtitle path is enabled. gapless play is not supported.");
6565 attrs = MMPLAYER_GET_ATTRS(player);
6567 LOGE("fail to get attributes.");
6571 mm_attrs_multiple_get(player->attrs, NULL,
6572 "content_video_found", &video,
6573 "profile_play_count", &count,
6574 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6576 /* gapless playback is not supported in case of video at TV profile. */
6577 profile_tv = __mmplayer_check_profile();
6578 if (profile_tv && video) {
6579 LOGW("not support video gapless playback");
6583 /* check repeat count in case of audio */
6585 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6586 LOGW("gapless is disabled");
6590 num_of_uri = g_list_length(player->uri_info.uri_list);
6592 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6594 if (num_of_uri == ORIGINAL_URI_ONLY) {
6595 /* audio looping path */
6596 if (count >= REPEAT_COUNT_MIN) {
6597 /* decrease play count */
6598 /* we succeeded to rewind. update play count and then wait for next EOS */
6600 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6601 } else if (count != REPEAT_COUNT_INFINITE) {
6602 LOGD("there is no next uri and no repeat");
6605 LOGD("looping cnt %d", count);
6607 /* gapless playback path */
6608 if (!__mmplayer_get_next_uri(player)) {
6609 LOGE("failed to get next uri");
6616 LOGE("unable to play gapless path. EOS will be posted soon");
6621 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6623 GstPad *sinkpad = g_value_get_object (item);
6624 GstElement *element = GST_ELEMENT(user_data);
6625 if (!sinkpad || !element) {
6626 LOGE("invalid parameter");
6630 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6631 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6635 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6637 mmplayer_gst_element_t *sinkbin = NULL;
6638 main_element_id_e concatId = MMPLAYER_M_NUM;
6639 main_element_id_e sinkId = MMPLAYER_M_NUM;
6640 gboolean send_notice = FALSE;
6641 GstElement *element;
6645 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6647 LOGD("type %d", type);
6650 case MM_PLAYER_TRACK_TYPE_AUDIO:
6651 concatId = MMPLAYER_M_A_CONCAT;
6652 sinkId = MMPLAYER_A_BIN;
6653 sinkbin = player->pipeline->audiobin;
6655 case MM_PLAYER_TRACK_TYPE_VIDEO:
6656 concatId = MMPLAYER_M_V_CONCAT;
6657 sinkId = MMPLAYER_V_BIN;
6658 sinkbin = player->pipeline->videobin;
6661 case MM_PLAYER_TRACK_TYPE_TEXT:
6662 concatId = MMPLAYER_M_T_CONCAT;
6663 sinkId = MMPLAYER_T_BIN;
6664 sinkbin = player->pipeline->textbin;
6667 LOGE("requested type is not supportable");
6672 element = player->pipeline->mainbin[concatId].gst;
6676 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6677 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6678 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6679 if (srcpad && sinkpad) {
6680 /* after getting drained signal there is no data flows, so no need to do pad_block */
6681 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6682 gst_pad_unlink(srcpad, sinkpad);
6684 /* send custom event to sink pad to handle it at video sink */
6686 LOGD("send custom event to sinkpad");
6687 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6688 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6689 gst_pad_send_event(sinkpad, event);
6692 gst_object_unref(srcpad);
6693 gst_object_unref(sinkpad);
6696 LOGD("release concat request pad");
6697 /* release and unref requests pad from the selector */
6698 iter = gst_element_iterate_sink_pads(element);
6699 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6700 gst_iterator_resync(iter);
6701 gst_iterator_free(iter);
6707 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6709 mmplayer_track_t *selector = &player->track[type];
6710 mmplayer_gst_element_t *sinkbin = NULL;
6711 main_element_id_e selectorId = MMPLAYER_M_NUM;
6712 main_element_id_e sinkId = MMPLAYER_M_NUM;
6713 GstPad *srcpad = NULL;
6714 GstPad *sinkpad = NULL;
6715 gboolean send_notice = FALSE;
6718 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6720 LOGD("type %d", type);
6723 case MM_PLAYER_TRACK_TYPE_AUDIO:
6724 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6725 sinkId = MMPLAYER_A_BIN;
6726 sinkbin = player->pipeline->audiobin;
6728 case MM_PLAYER_TRACK_TYPE_VIDEO:
6729 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6730 sinkId = MMPLAYER_V_BIN;
6731 sinkbin = player->pipeline->videobin;
6734 case MM_PLAYER_TRACK_TYPE_TEXT:
6735 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6736 sinkId = MMPLAYER_T_BIN;
6737 sinkbin = player->pipeline->textbin;
6740 LOGE("requested type is not supportable");
6745 if (player->pipeline->mainbin[selectorId].gst) {
6748 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6750 if (selector->event_probe_id != 0)
6751 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6752 selector->event_probe_id = 0;
6754 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6755 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6757 if (srcpad && sinkpad) {
6758 /* after getting drained signal there is no data flows, so no need to do pad_block */
6759 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6760 gst_pad_unlink(srcpad, sinkpad);
6762 /* send custom event to sink pad to handle it at video sink */
6764 LOGD("send custom event to sinkpad");
6765 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6766 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6767 gst_pad_send_event(sinkpad, event);
6771 gst_object_unref(sinkpad);
6774 gst_object_unref(srcpad);
6777 LOGD("selector release");
6779 /* release and unref requests pad from the selector */
6780 for (n = 0; n < selector->streams->len; n++) {
6781 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6782 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6785 g_ptr_array_set_size(selector->streams, 0);
6787 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6788 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6789 player->pipeline->mainbin[selectorId].gst)) {
6790 LOGE("failed to remove selector");
6791 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6794 player->pipeline->mainbin[selectorId].gst = NULL;
6802 __mmplayer_deactivate_old_path(mmplayer_t *player)
6805 MMPLAYER_RETURN_IF_FAIL(player);
6807 if (MMPLAYER_USE_DECODEBIN(player)) {
6808 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6809 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6810 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6811 LOGE("deactivate selector error");
6815 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6816 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6817 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6818 LOGE("deactivate concat error");
6823 _mmplayer_track_destroy(player);
6824 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6826 if (player->streamer) {
6827 _mm_player_streaming_initialize(player->streamer, FALSE);
6828 _mm_player_streaming_destroy(player->streamer);
6829 player->streamer = NULL;
6832 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6838 if (!player->msg_posted) {
6839 MMMessageParamType msg = {0,};
6842 msg.code = MM_ERROR_PLAYER_INTERNAL;
6843 LOGE("gapless_uri_play> deactivate error");
6845 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6846 player->msg_posted = TRUE;
6852 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6854 int result = MM_ERROR_NONE;
6855 mmplayer_t *player = (mmplayer_t *)hplayer;
6858 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6859 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6861 if (mm_player_set_attribute(hplayer, NULL,
6862 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6863 LOGE("failed to set attribute");
6864 result = MM_ERROR_PLAYER_INTERNAL;
6866 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6867 LOGE("failed to add the original uri in the uri list.");
6875 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6877 mmplayer_t *player = (mmplayer_t *)hplayer;
6878 guint num_of_list = 0;
6882 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6883 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6885 if (player->pipeline && player->pipeline->textbin) {
6886 LOGE("subtitle path is enabled.");
6887 return MM_ERROR_PLAYER_INVALID_STATE;
6890 num_of_list = g_list_length(player->uri_info.uri_list);
6892 if (is_first_path) {
6893 if (num_of_list == 0) {
6894 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6895 SECURE_LOGD("add original path : %s", uri);
6897 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6898 player->uri_info.uri_list = g_list_prepend(
6899 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6900 SECURE_LOGD("change original path : %s", uri);
6903 MMHandleType attrs = 0;
6904 attrs = MMPLAYER_GET_ATTRS(player);
6906 if (num_of_list == 0) {
6907 char *original_uri = NULL;
6910 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6912 if (!original_uri) {
6913 LOGE("there is no original uri.");
6914 return MM_ERROR_PLAYER_INVALID_STATE;
6917 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6918 player->uri_info.uri_idx = 0;
6920 SECURE_LOGD("add original path at first : %s", original_uri);
6924 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6925 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6929 return MM_ERROR_NONE;
6933 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6935 mmplayer_t *player = (mmplayer_t *)hplayer;
6936 char *next_uri = NULL;
6937 guint num_of_list = 0;
6940 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6942 num_of_list = g_list_length(player->uri_info.uri_list);
6944 if (num_of_list > 0) {
6945 gint uri_idx = player->uri_info.uri_idx;
6947 if (uri_idx < num_of_list - 1)
6952 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6953 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6955 *uri = g_strdup(next_uri);
6959 return MM_ERROR_NONE;
6963 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6964 GstCaps *caps, gpointer data)
6966 mmplayer_t *player = (mmplayer_t *)data;
6967 const gchar *klass = NULL;
6968 const gchar *mime = NULL;
6969 gchar *caps_str = NULL;
6971 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6972 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6973 caps_str = gst_caps_to_string(caps);
6975 LOGW("unknown type of caps : %s from %s",
6976 caps_str, GST_ELEMENT_NAME(elem));
6978 MMPLAYER_FREEIF(caps_str);
6980 /* There is no available codec. */
6981 __mmplayer_check_not_supported_codec(player, klass, mime);
6985 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6986 GstCaps *caps, gpointer data)
6988 mmplayer_t *player = (mmplayer_t *)data;
6989 const char *mime = NULL;
6990 gboolean ret = TRUE;
6992 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6993 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6995 if (g_str_has_prefix(mime, "audio")) {
6996 GstStructure *caps_structure = NULL;
6997 gint samplerate = 0;
6999 gchar *caps_str = NULL;
7001 caps_structure = gst_caps_get_structure(caps, 0);
7002 gst_structure_get_int(caps_structure, "rate", &samplerate);
7003 gst_structure_get_int(caps_structure, "channels", &channels);
7005 if ((channels > 0 && samplerate == 0)) {
7006 LOGD("exclude audio...");
7010 caps_str = gst_caps_to_string(caps);
7011 /* set it directly because not sent by TAG */
7012 if (g_strrstr(caps_str, "mobile-xmf"))
7013 mm_player_set_attribute((MMHandleType)player, NULL,
7014 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7016 MMPLAYER_FREEIF(caps_str);
7017 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7018 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7019 LOGD("video is already linked, allow the stream switch");
7022 LOGD("video is already linked");
7026 LOGD("found new stream");
7033 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7035 gboolean ret = FALSE;
7036 GDBusConnection *conn = NULL;
7038 GVariant *result = NULL;
7039 const gchar *dbus_device_type = NULL;
7040 const gchar *dbus_ret = NULL;
7043 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7045 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7050 result = g_dbus_connection_call_sync(conn,
7051 "org.pulseaudio.Server",
7052 "/org/pulseaudio/StreamManager",
7053 "org.pulseaudio.StreamManager",
7054 "GetCurrentMediaRoutingPath",
7055 g_variant_new("(s)", "out"),
7056 G_VARIANT_TYPE("(ss)"),
7057 G_DBUS_CALL_FLAGS_NONE,
7061 if (!result || err) {
7062 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7067 /* device type is listed in stream-map.json at mmfw-sysconf */
7068 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7070 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7071 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7074 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7075 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7076 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7077 LOGD("audio offload is supportable");
7083 LOGD("audio offload is not supportable");
7086 g_variant_unref(result);
7088 g_object_unref(conn);
7093 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7095 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7096 gint64 position = 0;
7098 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7099 player->pipeline && player->pipeline->mainbin);
7101 MMPLAYER_CMD_LOCK(player);
7102 current_state = MMPLAYER_CURRENT_STATE(player);
7104 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7105 LOGW("getting current position failed in paused");
7107 _mmplayer_unrealize((MMHandleType)player);
7108 _mmplayer_realize((MMHandleType)player);
7110 _mmplayer_set_position((MMHandleType)player, position);
7112 /* async not to be blocked in streaming case */
7113 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7115 _mmplayer_pause((MMHandleType)player);
7117 if (current_state == MM_PLAYER_STATE_PLAYING)
7118 _mmplayer_start((MMHandleType)player);
7119 MMPLAYER_CMD_UNLOCK(player);
7121 LOGD("rebuilding audio pipeline is completed.");
7124 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7126 mmplayer_t *player = (mmplayer_t *)user_data;
7127 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7128 gboolean is_supportable = FALSE;
7130 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7131 LOGW("failed to get device type");
7133 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7135 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7136 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7137 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7138 LOGD("ignore this dev connected info");
7142 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7143 if (player->build_audio_offload == is_supportable) {
7144 LOGD("keep current pipeline without re-building");
7148 /* rebuild pipeline */
7149 LOGD("re-build pipeline - offload: %d", is_supportable);
7150 player->build_audio_offload = FALSE;
7151 __mmplayer_rebuild_audio_pipeline(player);
7157 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7159 unsigned int id = 0;
7161 if (player->audio_device_cb_id != 0) {
7162 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7166 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7167 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7168 LOGD("added device connected cb (%u)", id);
7169 player->audio_device_cb_id = id;
7171 LOGW("failed to add device connected cb");
7178 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7180 mmplayer_t *player = (mmplayer_t *)hplayer;
7183 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7184 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7186 *activated = player->build_audio_offload;
7188 LOGD("offload activated : %d", (int)*activated);
7191 return MM_ERROR_NONE;
7195 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7198 this function need to be updated according to the supported media format
7199 @see player->ini.audio_offload_media_format */
7201 if (__mmplayer_is_only_mp3_type(player->type)) {
7202 LOGD("offload supportable media format type");
7210 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7212 gboolean ret = FALSE;
7213 GstElementFactory *factory = NULL;
7216 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7218 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7219 if (!__mmplayer_is_offload_supported_type(player))
7222 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7223 LOGD("there is no audio offload sink");
7227 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7228 LOGW("there is no audio device type to support offload");
7232 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7234 LOGW("there is no installed audio offload sink element");
7237 gst_object_unref(factory);
7239 if (_mmplayer_acquire_hw_resource(player,
7240 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7241 LOGE("failed to acquire audio offload decoder resource");
7245 if (!__mmplayer_add_audio_device_connected_cb(player))
7248 if (!__mmplayer_is_audio_offload_device_type(player))
7251 LOGD("audio offload can be built");
7256 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7262 static GstAutoplugSelectResult
7263 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7265 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7266 int audio_offload = 0;
7268 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7269 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7271 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7272 LOGD("expose audio path to build offload output path");
7273 player->build_audio_offload = TRUE;
7274 /* update codec info */
7275 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7276 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7277 player->audiodec_linked = 1;
7279 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7283 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7284 And need to consider the multi-track audio content.
7285 There is no HW audio decoder in public. */
7287 /* set stream information */
7288 if (!player->audiodec_linked)
7289 _mmplayer_set_audio_attrs(player, caps);
7291 /* update codec info */
7292 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7293 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7294 player->audiodec_linked = 1;
7296 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7298 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7299 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7301 /* mark video decoder for acquire */
7302 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7303 LOGW("video decoder resource is already acquired, skip it.");
7304 ret = GST_AUTOPLUG_SELECT_SKIP;
7308 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7309 LOGE("failed to acquire video decoder resource");
7310 ret = GST_AUTOPLUG_SELECT_SKIP;
7313 player->interrupted_by_resource = FALSE;
7316 /* update codec info */
7317 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7318 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7319 player->videodec_linked = 1;
7327 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7328 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7330 #define DEFAULT_IDX 0xFFFF
7331 #define MIN_FACTORY_NUM 2
7332 mmplayer_t *player = (mmplayer_t *)data;
7333 GValueArray *new_factories = NULL;
7334 GValue val = { 0, };
7335 GstElementFactory *factory = NULL;
7336 const gchar *klass = NULL;
7337 gchar *factory_name = NULL;
7338 guint hw_dec_idx = DEFAULT_IDX;
7339 guint first_sw_dec_idx = DEFAULT_IDX;
7340 guint last_sw_dec_idx = DEFAULT_IDX;
7341 guint new_pos = DEFAULT_IDX;
7342 guint rm_pos = DEFAULT_IDX;
7343 int audio_codec_type;
7344 int video_codec_type;
7345 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7347 if (factories->n_values < MIN_FACTORY_NUM)
7350 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7351 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7354 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7356 for (int i = 0 ; i < factories->n_values ; i++) {
7357 gchar *hw_dec_info = NULL;
7358 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7360 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7362 LOGW("failed to get factory object");
7365 klass = gst_element_factory_get_klass(factory);
7366 factory_name = GST_OBJECT_NAME(factory);
7369 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7371 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7372 if (!player->need_audio_dec_sorting) {
7373 LOGD("sorting is not required");
7376 codec_type = audio_codec_type;
7377 hw_dec_info = player->ini.audiocodec_element_hw;
7378 sw_dec_info = player->ini.audiocodec_element_sw;
7379 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7380 if (!player->need_video_dec_sorting) {
7381 LOGD("sorting is not required");
7384 codec_type = video_codec_type;
7385 hw_dec_info = player->ini.videocodec_element_hw;
7386 sw_dec_info = player->ini.videocodec_element_sw;
7391 if (g_strrstr(factory_name, hw_dec_info)) {
7394 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7395 if (strstr(factory_name, sw_dec_info[j])) {
7396 last_sw_dec_idx = i;
7397 if (first_sw_dec_idx == DEFAULT_IDX) {
7398 first_sw_dec_idx = i;
7403 if (first_sw_dec_idx == DEFAULT_IDX)
7404 LOGW("unknown codec %s", factory_name);
7408 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7411 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7412 if (hw_dec_idx < first_sw_dec_idx)
7414 new_pos = first_sw_dec_idx;
7415 rm_pos = hw_dec_idx + 1;
7416 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7417 if (last_sw_dec_idx < hw_dec_idx)
7419 new_pos = last_sw_dec_idx + 1;
7420 rm_pos = hw_dec_idx;
7425 /* change position - insert H/W decoder according to the new position */
7426 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7428 LOGW("failed to get factory object");
7431 new_factories = g_value_array_copy(factories);
7432 g_value_init (&val, G_TYPE_OBJECT);
7433 g_value_set_object (&val, factory);
7434 g_value_array_insert(new_factories, new_pos, &val);
7435 g_value_unset (&val);
7436 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7438 for (int i = 0 ; i < new_factories->n_values ; i++) {
7439 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7441 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7442 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7444 LOGE("[Re-arranged] failed to get factory object");
7447 return new_factories;
7451 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7452 GstCaps *caps, GstElementFactory *factory, gpointer data)
7454 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7455 mmplayer_t *player = (mmplayer_t *)data;
7457 gchar *factory_name = NULL;
7458 gchar *caps_str = NULL;
7459 const gchar *klass = NULL;
7462 factory_name = GST_OBJECT_NAME(factory);
7463 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7464 caps_str = gst_caps_to_string(caps);
7466 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7468 /* store type string */
7469 if (player->type == NULL) {
7470 player->type = gst_caps_to_string(caps);
7471 __mmplayer_update_content_type_info(player);
7474 /* filtering exclude keyword */
7475 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7476 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7477 LOGW("skipping [%s] by exclude keyword [%s]",
7478 factory_name, player->ini.exclude_element_keyword[idx]);
7480 result = GST_AUTOPLUG_SELECT_SKIP;
7485 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7486 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7487 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7488 factory_name, player->ini.unsupported_codec_keyword[idx]);
7489 result = GST_AUTOPLUG_SELECT_SKIP;
7494 /* exclude webm format */
7495 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7496 * because webm format is not supportable.
7497 * If webm is disabled in "autoplug-continue", there is no state change
7498 * failure or error because the decodebin will expose the pad directly.
7499 * It make MSL invoke _prepare_async_callback.
7500 * So, we need to disable webm format in "autoplug-select" */
7501 if (caps_str && strstr(caps_str, "webm")) {
7502 LOGW("webm is not supported");
7503 result = GST_AUTOPLUG_SELECT_SKIP;
7507 /* check factory class for filtering */
7508 /* NOTE : msl don't need to use image plugins.
7509 * So, those plugins should be skipped for error handling.
7511 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7512 LOGD("skipping [%s] by not required", factory_name);
7513 result = GST_AUTOPLUG_SELECT_SKIP;
7517 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7518 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7519 // TO CHECK : subtitle if needed, add subparse exception.
7520 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7521 result = GST_AUTOPLUG_SELECT_SKIP;
7525 if (g_strrstr(factory_name, "mpegpsdemux")) {
7526 LOGD("skipping PS container - not support");
7527 result = GST_AUTOPLUG_SELECT_SKIP;
7531 if (g_strrstr(factory_name, "mssdemux"))
7532 player->smooth_streaming = TRUE;
7534 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7535 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7538 GstStructure *str = NULL;
7539 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7541 /* don't make video because of not required */
7542 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7543 (!player->set_mode.video_export)) {
7544 LOGD("no need video decoding, expose pad");
7545 result = GST_AUTOPLUG_SELECT_EXPOSE;
7549 /* get w/h for omx state-tune */
7550 /* FIXME: deprecated? */
7551 str = gst_caps_get_structure(caps, 0);
7552 gst_structure_get_int(str, "width", &width);
7555 if (player->v_stream_caps) {
7556 gst_caps_unref(player->v_stream_caps);
7557 player->v_stream_caps = NULL;
7560 player->v_stream_caps = gst_caps_copy(caps);
7561 LOGD("take caps for video state tune");
7562 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7566 if (g_strrstr(klass, "Codec/Decoder")) {
7567 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7568 if (result != GST_AUTOPLUG_SELECT_TRY) {
7569 LOGW("skip add decoder");
7575 MMPLAYER_FREEIF(caps_str);
7581 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7584 int ret = MM_ERROR_NONE;
7585 mmplayer_t *player = (mmplayer_t *)data;
7586 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7587 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7588 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7591 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7593 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7595 if (MMPLAYER_USE_DECODEBIN(player))
7598 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7601 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7603 __mmplayer_del_sink(player, videobin[MMPLAYER_V_SINK].gst);
7605 LOGD("remove videobin");
7606 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst,
7607 GST_STATE_NULL, FALSE, timeout);
7608 if (ret != MM_ERROR_NONE) {
7609 LOGE("fail to change state of videobin to NULL");
7613 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7614 LOGE("failed to remove videobin");
7615 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7618 LOGD("remove concat");
7619 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst,
7620 GST_STATE_NULL, FALSE, timeout);
7621 if (ret != MM_ERROR_NONE) {
7622 LOGE("fail to change state of concat to NULL");
7626 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7627 LOGE("failed to remove video concat");
7628 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7631 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7632 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7633 MMPLAYER_FREEIF(player->pipeline->videobin);
7635 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7636 if (ret != MM_ERROR_NONE)
7637 LOGE("failed to release overlay resources");
7639 player->videodec_linked = 0;
7641 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7646 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7648 mmplayer_t *player = (mmplayer_t *)data;
7651 MMPLAYER_RETURN_IF_FAIL(player);
7653 LOGD("got about to finish signal");
7655 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7656 LOGW("Fail to get cmd lock");
7660 if (!__mmplayer_verify_gapless_play_path(player)) {
7661 LOGD("decoding is finished.");
7662 MMPLAYER_CMD_UNLOCK(player);
7666 _mmplayer_set_reconfigure_state(player, TRUE);
7667 MMPLAYER_CMD_UNLOCK(player);
7669 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7670 __mmplayer_deactivate_old_path(player);
7676 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7678 mmplayer_t *player = (mmplayer_t *)data;
7679 GstIterator *iter = NULL;
7680 GValue item = { 0, };
7682 gboolean done = FALSE;
7683 gboolean is_all_drained = TRUE;
7686 MMPLAYER_RETURN_IF_FAIL(player);
7688 LOGD("got drained signal");
7690 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7691 LOGW("Fail to get cmd lock");
7695 if (!__mmplayer_verify_gapless_play_path(player)) {
7696 LOGD("decoding is finished.");
7697 MMPLAYER_CMD_UNLOCK(player);
7701 _mmplayer_set_reconfigure_state(player, TRUE);
7702 MMPLAYER_CMD_UNLOCK(player);
7704 /* check decodebin src pads whether they received EOS or not */
7705 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7708 switch (gst_iterator_next(iter, &item)) {
7709 case GST_ITERATOR_OK:
7710 pad = g_value_get_object(&item);
7711 if (pad && !GST_PAD_IS_EOS(pad)) {
7712 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7713 is_all_drained = FALSE;
7716 g_value_reset(&item);
7718 case GST_ITERATOR_RESYNC:
7719 gst_iterator_resync(iter);
7721 case GST_ITERATOR_ERROR:
7722 case GST_ITERATOR_DONE:
7727 g_value_unset(&item);
7728 gst_iterator_free(iter);
7730 if (!is_all_drained) {
7731 LOGD("Wait util the all pads get EOS.");
7736 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7737 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7739 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7740 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7741 __mmplayer_deactivate_old_path(player);
7747 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7749 mmplayer_t *player = (mmplayer_t *)data;
7750 const gchar *klass = NULL;
7751 gchar *factory_name = NULL;
7753 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7754 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7756 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7758 if (__mmplayer_add_dump_buffer_probe(player, element))
7759 LOGD("add buffer probe");
7761 if (g_strrstr(klass, "Decoder")) {
7762 if (g_strrstr(klass, "Audio")) {
7763 player->audio_decoders = g_list_append(player->audio_decoders,
7764 g_strdup(GST_ELEMENT_NAME(element)));
7766 /* update codec info */
7767 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7768 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7769 player->audiodec_linked = 1;
7770 } else if (g_strrstr(klass, "Video")) {
7771 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7772 /* update codec info */
7773 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7774 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7775 player->videodec_linked = 1;
7778 GstPad *srcpad = gst_element_get_static_pad (video_parse, "src");
7780 GstCaps *caps = NULL;
7781 GstStructure *str = NULL;
7782 const gchar *name = NULL;
7783 gboolean caps_ret = TRUE;
7785 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD (srcpad, caps, str, name, caps_ret);
7786 if (caps_ret && str) {
7787 const gchar *stream_format = gst_structure_get_string (str, "stream-format");
7788 if (stream_format && g_strrstr(stream_format, "byte-stream")) {
7789 if ((g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7790 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7791 LOGD("Send SPS and PPS Insertion every IDR frame");
7795 gst_object_unref(GST_OBJECT(srcpad));
7799 } else if (g_strrstr(klass, "Demuxer")) {
7800 if (g_strrstr(klass, "Adaptive")) {
7801 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7802 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7804 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7805 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7807 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7808 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7809 "max-video-width", player->adaptive_info.limit.width,
7810 "max-video-height", player->adaptive_info.limit.height, NULL);
7813 LOGD("plugged element is demuxer. take it");
7815 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7816 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7818 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7819 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7820 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7823 if (g_strrstr(factory_name, "mpegaudioparse")) {
7824 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7825 (__mmplayer_is_only_mp3_type(player->type))) {
7826 LOGD("[mpegaudioparse] set streaming pull mode.");
7827 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7829 } else if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7830 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7831 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7833 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7834 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7836 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7837 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7838 (MMPLAYER_IS_DASH_STREAMING(player))) {
7839 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7840 _mm_player_streaming_set_multiqueue(player->streamer, element);
7841 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7849 __mmplayer_release_misc(mmplayer_t *player)
7852 bool cur_mode = player->set_mode.rich_audio;
7855 MMPLAYER_RETURN_IF_FAIL(player);
7857 player->sent_bos = FALSE;
7858 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7860 player->seek_state = MMPLAYER_SEEK_NONE;
7862 player->total_bitrate = 0;
7863 player->total_maximum_bitrate = 0;
7865 player->not_found_demuxer = 0;
7867 player->last_position = 0;
7868 player->duration = 0;
7869 player->http_content_size = 0;
7870 player->not_supported_codec = MISSING_PLUGIN_NONE;
7871 player->can_support_codec = FOUND_PLUGIN_NONE;
7872 player->pending_seek.is_pending = false;
7873 player->pending_seek.pos = 0;
7874 player->msg_posted = FALSE;
7875 player->has_many_types = FALSE;
7876 player->is_subtitle_force_drop = FALSE;
7877 player->play_subtitle = FALSE;
7878 player->adjust_subtitle_pos = 0;
7879 player->has_closed_caption = FALSE;
7880 player->set_mode.video_export = false;
7881 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7882 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7884 player->set_mode.rich_audio = cur_mode;
7886 if (player->audio_device_cb_id > 0 &&
7887 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7888 LOGW("failed to remove audio device_connected_callback");
7889 player->audio_device_cb_id = 0;
7891 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7892 player->bitrate[i] = 0;
7893 player->maximum_bitrate[i] = 0;
7896 /* free memory related to audio effect */
7897 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7899 if (player->adaptive_info.var_list) {
7900 g_list_free_full(player->adaptive_info.var_list, g_free);
7901 player->adaptive_info.var_list = NULL;
7904 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7905 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7906 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7908 /* Reset video360 settings to their defaults in case if the pipeline is to be
7911 player->video360_metadata.is_spherical = -1;
7912 player->is_openal_plugin_used = FALSE;
7914 player->is_content_spherical = FALSE;
7915 player->is_video360_enabled = TRUE;
7916 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7917 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7918 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7919 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7920 player->video360_zoom = 1.0f;
7921 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7922 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7924 player->sound.rg_enable = false;
7926 __mmplayer_initialize_video_roi(player);
7931 __mmplayer_release_misc_post(mmplayer_t *player)
7933 gchar *original_uri = NULL;
7936 /* player->pipeline is already released before. */
7937 MMPLAYER_RETURN_IF_FAIL(player);
7939 player->video_decoded_cb = NULL;
7940 player->video_decoded_cb_user_param = NULL;
7941 player->video_stream_prerolled = false;
7943 player->audio_decoded_cb = NULL;
7944 player->audio_decoded_cb_user_param = NULL;
7945 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7947 player->audio_stream_changed_cb = NULL;
7948 player->audio_stream_changed_cb_user_param = NULL;
7950 mm_player_set_attribute((MMHandleType)player, NULL,
7951 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7953 /* clean found audio decoders */
7954 if (player->audio_decoders) {
7955 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7956 player->audio_decoders = NULL;
7959 /* clean the uri list except original uri */
7960 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7962 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7963 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7964 g_list_free_full(tmp, (GDestroyNotify)g_free);
7967 LOGW("failed to get original uri info");
7969 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7970 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7971 MMPLAYER_FREEIF(original_uri);
7974 /* clear the audio stream buffer list */
7975 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7977 /* clear the video stream bo list */
7978 __mmplayer_video_stream_destroy_bo_list(player);
7979 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7981 if (player->profile.input_mem.buf) {
7982 free(player->profile.input_mem.buf);
7983 player->profile.input_mem.buf = NULL;
7985 player->profile.input_mem.len = 0;
7986 player->profile.input_mem.offset = 0;
7988 player->uri_info.uri_idx = 0;
7993 __mmplayer_check_subtitle(mmplayer_t *player)
7995 MMHandleType attrs = 0;
7996 char *subtitle_uri = NULL;
8000 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8002 /* get subtitle attribute */
8003 attrs = MMPLAYER_GET_ATTRS(player);
8007 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8008 if (!subtitle_uri || !strlen(subtitle_uri))
8011 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
8012 player->is_external_subtitle_present = TRUE;
8020 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8022 MMPLAYER_RETURN_IF_FAIL(player);
8024 if (player->eos_timer) {
8025 LOGD("cancel eos timer");
8026 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8027 player->eos_timer = 0;
8034 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8038 MMPLAYER_RETURN_IF_FAIL(player);
8039 MMPLAYER_RETURN_IF_FAIL(sink);
8042 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8044 player->sink_elements = g_list_append(player->sink_elements, sink);
8050 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8054 MMPLAYER_RETURN_IF_FAIL(player);
8055 MMPLAYER_RETURN_IF_FAIL(sink);
8057 player->sink_elements = g_list_remove(player->sink_elements, sink);
8063 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8064 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8066 mmplayer_signal_item_t *item = NULL;
8069 MMPLAYER_RETURN_IF_FAIL(player);
8071 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8072 LOGE("invalid signal type [%d]", type);
8076 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8078 LOGE("cannot connect signal [%s]", signal);
8083 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8084 player->signals[type] = g_list_append(player->signals[type], item);
8090 /* NOTE : be careful with calling this api. please refer to below glib comment
8091 * glib comment : Note that there is a bug in GObject that makes this function much
8092 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8093 * will no longer be called, but, the signal handler is not currently disconnected.
8094 * If the instance is itself being freed at the same time than this doesn't matter,
8095 * since the signal will automatically be removed, but if instance persists,
8096 * then the signal handler will leak. You should not remove the signal yourself
8097 * because in a future versions of GObject, the handler will automatically be
8100 * It's possible to work around this problem in a way that will continue to work
8101 * with future versions of GObject by checking that the signal handler is still
8102 * connected before disconnected it:
8104 * if (g_signal_handler_is_connected(instance, id))
8105 * g_signal_handler_disconnect(instance, id);
8108 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8110 GList *sig_list = NULL;
8111 mmplayer_signal_item_t *item = NULL;
8115 MMPLAYER_RETURN_IF_FAIL(player);
8117 LOGD("release signals type : %d", type);
8119 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8120 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8121 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8122 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8123 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8124 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8128 sig_list = player->signals[type];
8130 for (; sig_list; sig_list = sig_list->next) {
8131 item = sig_list->data;
8133 if (item && item->obj) {
8134 if (g_signal_handler_is_connected(item->obj, item->sig))
8135 g_signal_handler_disconnect(item->obj, item->sig);
8138 MMPLAYER_FREEIF(item);
8141 g_list_free(player->signals[type]);
8142 player->signals[type] = NULL;
8150 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8152 mmplayer_t *player = 0;
8153 int prev_display_surface_type = 0;
8157 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8159 player = MM_PLAYER_CAST(handle);
8161 /* check video sinkbin is created */
8162 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8163 LOGW("Videosink is already created");
8164 return MM_ERROR_NONE;
8167 LOGD("videosink element is not yet ready");
8169 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8170 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8172 return MM_ERROR_INVALID_ARGUMENT;
8175 /* load previous attributes */
8176 if (player->attrs) {
8177 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8178 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8179 if (prev_display_surface_type == surface_type) {
8180 LOGD("incoming display surface type is same as previous one, do nothing..");
8182 return MM_ERROR_NONE;
8185 LOGE("failed to load attributes");
8187 return MM_ERROR_PLAYER_INTERNAL;
8190 /* videobin is not created yet, so we just set attributes related to display surface */
8191 LOGD("store display attribute for given surface type(%d)", surface_type);
8192 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8193 "display_overlay", wl_surface_id, NULL);
8196 return MM_ERROR_NONE;
8199 /* Note : if silent is true, then subtitle would not be displayed. :*/
8201 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8203 mmplayer_t *player = (mmplayer_t *)hplayer;
8207 /* check player handle */
8208 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8210 player->set_mode.subtitle_off = silent;
8212 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8216 return MM_ERROR_NONE;
8220 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8222 mmplayer_gst_element_t *mainbin = NULL;
8223 mmplayer_gst_element_t *textbin = NULL;
8224 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8225 GstState current_state = GST_STATE_VOID_PENDING;
8226 GstState element_state = GST_STATE_VOID_PENDING;
8227 GstState element_pending_state = GST_STATE_VOID_PENDING;
8229 GstEvent *event = NULL;
8230 int result = MM_ERROR_NONE;
8232 GstClock *curr_clock = NULL;
8233 GstClockTime base_time, start_time, curr_time;
8238 /* check player handle */
8239 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8241 player->pipeline->mainbin &&
8242 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8244 mainbin = player->pipeline->mainbin;
8245 textbin = player->pipeline->textbin;
8247 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8249 // sync clock with current pipeline
8250 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8251 curr_time = gst_clock_get_time(curr_clock);
8253 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8254 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8256 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8257 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8259 if (current_state > GST_STATE_READY) {
8260 // sync state with current pipeline
8261 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8262 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8263 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8265 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8266 if (GST_STATE_CHANGE_FAILURE == ret) {
8267 LOGE("fail to state change.");
8268 result = MM_ERROR_PLAYER_INTERNAL;
8272 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8273 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8276 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8277 gst_object_unref(curr_clock);
8280 // seek to current position
8281 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8282 result = MM_ERROR_PLAYER_INVALID_STATE;
8283 LOGE("gst_element_query_position failed, invalid state");
8287 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8288 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);
8290 _mmplayer_gst_send_event_to_sink(player, event);
8292 result = MM_ERROR_PLAYER_INTERNAL;
8293 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8297 /* sync state with current pipeline */
8298 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8299 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8300 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8302 return MM_ERROR_NONE;
8305 /* release text pipeline resource */
8306 player->textsink_linked = 0;
8308 /* release signal */
8309 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8311 /* release textbin with it's children */
8312 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8313 MMPLAYER_FREEIF(player->pipeline->textbin);
8314 player->pipeline->textbin = NULL;
8316 /* release subtitle elem */
8317 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8318 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8324 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8326 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8327 GstState current_state = GST_STATE_VOID_PENDING;
8329 MMHandleType attrs = 0;
8330 mmplayer_gst_element_t *mainbin = NULL;
8331 mmplayer_gst_element_t *textbin = NULL;
8333 gchar *subtitle_uri = NULL;
8334 int result = MM_ERROR_NONE;
8335 const gchar *charset = NULL;
8339 /* check player handle */
8340 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8342 player->pipeline->mainbin &&
8343 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8344 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8346 mainbin = player->pipeline->mainbin;
8347 textbin = player->pipeline->textbin;
8349 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8350 if (current_state < GST_STATE_READY) {
8351 result = MM_ERROR_PLAYER_INVALID_STATE;
8352 LOGE("Pipeline is not in proper state");
8356 attrs = MMPLAYER_GET_ATTRS(player);
8358 LOGE("cannot get content attribute");
8359 result = MM_ERROR_PLAYER_INTERNAL;
8363 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8364 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8365 LOGE("subtitle uri is not proper filepath");
8366 result = MM_ERROR_PLAYER_INVALID_URI;
8370 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8371 LOGE("failed to get storage info of subtitle path");
8372 result = MM_ERROR_PLAYER_INVALID_URI;
8376 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8377 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8379 if (!strcmp(filepath, subtitle_uri)) {
8380 LOGD("subtitle path is not changed");
8383 if (mm_player_set_attribute((MMHandleType)player, NULL,
8384 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8385 LOGE("failed to set attribute");
8390 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8391 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8392 player->subtitle_language_list = NULL;
8393 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8395 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8396 if (ret != GST_STATE_CHANGE_SUCCESS) {
8397 LOGE("failed to change state of textbin to READY");
8398 result = MM_ERROR_PLAYER_INTERNAL;
8402 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8403 if (ret != GST_STATE_CHANGE_SUCCESS) {
8404 LOGE("failed to change state of subparse to READY");
8405 result = MM_ERROR_PLAYER_INTERNAL;
8409 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8410 if (ret != GST_STATE_CHANGE_SUCCESS) {
8411 LOGE("failed to change state of filesrc to READY");
8412 result = MM_ERROR_PLAYER_INTERNAL;
8416 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8418 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8420 charset = _mmplayer_get_charset(filepath);
8422 LOGD("detected charset is %s", charset);
8423 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8426 result = _mmplayer_sync_subtitle_pipeline(player);
8433 /* API to switch between external subtitles */
8435 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8437 int result = MM_ERROR_NONE;
8438 mmplayer_t *player = (mmplayer_t *)hplayer;
8443 /* check player handle */
8444 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8446 /* filepath can be null in idle state */
8448 /* check file path */
8449 if ((path = strstr(filepath, "file://")))
8450 result = _mmplayer_exist_file_path(path + 7);
8452 result = _mmplayer_exist_file_path(filepath);
8454 if (result != MM_ERROR_NONE) {
8455 LOGE("invalid subtitle path 0x%X", result);
8456 return result; /* file not found or permission denied */
8460 if (!player->pipeline) {
8462 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8463 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8464 LOGE("failed to set attribute");
8465 return MM_ERROR_PLAYER_INTERNAL;
8468 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8469 /* check filepath */
8470 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8472 if (!__mmplayer_check_subtitle(player)) {
8473 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8474 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8475 LOGE("failed to set attribute");
8476 return MM_ERROR_PLAYER_INTERNAL;
8479 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8480 LOGE("fail to create text pipeline");
8481 return MM_ERROR_PLAYER_INTERNAL;
8484 result = _mmplayer_sync_subtitle_pipeline(player);
8486 result = __mmplayer_change_external_subtitle_language(player, filepath);
8489 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8490 player->is_external_subtitle_added_now = TRUE;
8492 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8493 if (!player->subtitle_language_list) {
8494 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8495 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8496 LOGW("subtitle language list is not updated yet");
8498 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8506 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8508 guint active_idx = 0;
8509 GstStream *stream = NULL;
8510 GList *streams = NULL;
8511 GstCaps *caps = NULL;
8514 LOGD("Switching Streams... type: %d, index: %d", type, index);
8516 player->track[type].active_track_index = index;
8518 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8519 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8520 LOGD("track type:%d, total: %d, active: %d", i,
8521 player->track[i].total_track_num, player->track[i].active_track_index);
8522 if (player->track[i].total_track_num > 0 &&
8523 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8524 active_idx = player->track[i].active_track_index;
8525 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8526 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8527 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8529 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8530 caps = gst_stream_get_caps(stream);
8532 _mmplayer_set_audio_attrs(player, caps);
8533 gst_caps_unref(caps);
8540 LOGD("send select stream event");
8541 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8542 gst_event_new_select_streams(streams));
8543 g_list_free(streams);
8546 /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8547 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8548 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8550 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8551 pos_nsec = player->last_position;
8553 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8555 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8556 player->playback_rate, GST_FORMAT_TIME,
8557 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8558 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8559 LOGW("failed to seek");
8560 return MM_ERROR_PLAYER_INTERNAL;
8565 return MM_ERROR_NONE;
8569 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8571 int result = MM_ERROR_NONE;
8572 gchar *change_pad_name = NULL;
8573 GstPad *sinkpad = NULL;
8574 mmplayer_gst_element_t *mainbin = NULL;
8575 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8576 GstCaps *caps = NULL;
8577 gint total_track_num = 0;
8581 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8582 MM_ERROR_PLAYER_NOT_INITIALIZED);
8584 LOGD("Change Track(%d) to %d", type, index);
8586 mainbin = player->pipeline->mainbin;
8588 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8589 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8590 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8591 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8593 /* Changing Video Track is not supported. */
8594 LOGE("Track Type Error");
8598 if (mainbin[elem_idx].gst == NULL) {
8599 result = MM_ERROR_PLAYER_NO_OP;
8600 LOGD("Req track doesn't exist");
8604 total_track_num = player->track[type].total_track_num;
8605 if (total_track_num <= 0) {
8606 result = MM_ERROR_PLAYER_NO_OP;
8607 LOGD("Language list is not available");
8611 if ((index < 0) || (index >= total_track_num)) {
8612 result = MM_ERROR_INVALID_ARGUMENT;
8613 LOGD("Not a proper index : %d", index);
8617 /*To get the new pad from the selector*/
8618 change_pad_name = g_strdup_printf("sink_%u", index);
8619 if (change_pad_name == NULL) {
8620 result = MM_ERROR_PLAYER_INTERNAL;
8621 LOGD("Pad does not exists");
8625 LOGD("new active pad name: %s", change_pad_name);
8627 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8628 if (sinkpad == NULL) {
8629 LOGD("sinkpad is NULL");
8630 result = MM_ERROR_PLAYER_INTERNAL;
8634 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8635 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8637 caps = gst_pad_get_current_caps(sinkpad);
8638 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8641 gst_object_unref(sinkpad);
8643 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8644 _mmplayer_set_audio_attrs(player, caps);
8647 gst_caps_unref(caps);
8650 MMPLAYER_FREEIF(change_pad_name);
8655 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8657 int result = MM_ERROR_NONE;
8658 mmplayer_t *player = NULL;
8659 mmplayer_gst_element_t *mainbin = NULL;
8661 gint current_active_index = 0;
8663 GstState current_state = GST_STATE_VOID_PENDING;
8668 player = (mmplayer_t *)hplayer;
8669 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8671 if (!player->pipeline) {
8672 LOGE("Track %d pre setting -> %d", type, index);
8674 player->track[type].active_track_index = index;
8678 mainbin = player->pipeline->mainbin;
8680 current_active_index = player->track[type].active_track_index;
8682 /*If index is same as running index no need to change the pad*/
8683 if (current_active_index == index)
8686 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8687 result = MM_ERROR_PLAYER_INVALID_STATE;
8691 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8692 if (current_state < GST_STATE_PAUSED) {
8693 result = MM_ERROR_PLAYER_INVALID_STATE;
8694 LOGW("Pipeline not in proper state");
8698 if (MMPLAYER_USE_DECODEBIN(player))
8699 result = __mmplayer_change_selector_pad(player, type, index);
8701 result = __mmplayer_switch_stream(player, type, index);
8703 if (result != MM_ERROR_NONE) {
8704 LOGE("failed to change track");
8708 player->track[type].active_track_index = index;
8710 if (MMPLAYER_USE_DECODEBIN(player)) {
8711 GstEvent *event = NULL;
8712 if (current_state == GST_STATE_PLAYING) {
8713 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8714 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8715 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8717 _mmplayer_gst_send_event_to_sink(player, event);
8719 result = MM_ERROR_PLAYER_INTERNAL;
8730 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8732 mmplayer_t *player = (mmplayer_t *)hplayer;
8736 /* check player handle */
8737 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8739 *silent = player->set_mode.subtitle_off;
8741 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8745 return MM_ERROR_NONE;
8749 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8751 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8752 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8754 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8755 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8759 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8760 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8761 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8762 mmplayer_dump_t *dump_s;
8763 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8764 if (dump_s == NULL) {
8765 LOGE("malloc fail");
8769 dump_s->dump_element_file = NULL;
8770 dump_s->dump_pad = NULL;
8771 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8773 if (dump_s->dump_pad) {
8774 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8775 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]);
8776 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8777 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);
8778 /* add list for removed buffer probe and close FILE */
8779 player->dump_list = g_list_append(player->dump_list, dump_s);
8780 LOGD("%s sink pad added buffer probe for dump", factory_name);
8783 MMPLAYER_FREEIF(dump_s);
8784 LOGE("failed to get %s sink pad added", factory_name);
8791 static GstPadProbeReturn
8792 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8794 FILE *dump_data = (FILE *)u_data;
8796 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8797 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8799 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8801 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8803 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8805 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8807 gst_buffer_unmap(buffer, &probe_info);
8809 return GST_PAD_PROBE_OK;
8813 __mmplayer_release_dump_list(GList *dump_list)
8815 GList *d_list = dump_list;
8820 for (; d_list; d_list = g_list_next(d_list)) {
8821 mmplayer_dump_t *dump_s = d_list->data;
8822 if (dump_s->dump_pad) {
8823 if (dump_s->probe_handle_id)
8824 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8825 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8827 if (dump_s->dump_element_file) {
8828 fclose(dump_s->dump_element_file);
8829 dump_s->dump_element_file = NULL;
8831 MMPLAYER_FREEIF(dump_s);
8833 g_list_free(dump_list);
8838 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8840 mmplayer_t *player = (mmplayer_t *)hplayer;
8844 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8845 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8847 *exist = (bool)player->has_closed_caption;
8851 return MM_ERROR_NONE;
8855 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8860 LOGD("unref internal gst buffer %p", buffer);
8862 gst_buffer_unref((GstBuffer *)buffer);
8869 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8871 mmplayer_t *player = (mmplayer_t *)hplayer;
8875 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8876 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8878 if (MMPLAYER_IS_STREAMING(player))
8879 *timeout = (int)player->ini.live_state_change_timeout;
8881 *timeout = (int)player->ini.localplayback_state_change_timeout;
8883 LOGD("timeout = %d", *timeout);
8886 return MM_ERROR_NONE;
8890 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8894 MMPLAYER_RETURN_IF_FAIL(player);
8896 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8898 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8899 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8900 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8901 player->storage_info[i].id = -1;
8902 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8904 if (path_type != MMPLAYER_PATH_MAX)
8913 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8915 int ret = MM_ERROR_NONE;
8916 mmplayer_t *player = (mmplayer_t *)hplayer;
8917 MMMessageParamType msg_param = {0, };
8920 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8922 LOGW("state changed storage %d:%d", id, state);
8924 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8925 return MM_ERROR_NONE;
8927 /* FIXME: text path should be handled separately. */
8928 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8929 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8930 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8931 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8932 LOGW("external storage is removed");
8934 if (player->msg_posted == FALSE) {
8935 memset(&msg_param, 0, sizeof(MMMessageParamType));
8936 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8937 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8938 player->msg_posted = TRUE;
8941 /* unrealize the player */
8942 ret = _mmplayer_unrealize(hplayer);
8943 if (ret != MM_ERROR_NONE)
8944 LOGE("failed to unrealize");
8952 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8954 int ret = MM_ERROR_NONE;
8955 mmplayer_t *player = (mmplayer_t *)hplayer;
8956 int idx = 0, total = 0;
8957 gchar *result = NULL, *tmp = NULL;
8960 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8961 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8963 total = *num = g_list_length(player->adaptive_info.var_list);
8965 LOGW("There is no stream variant info.");
8969 result = g_strdup("");
8970 for (idx = 0 ; idx < total ; idx++) {
8971 stream_variant_t *v_data = NULL;
8972 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8975 gchar data[64] = {0};
8976 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8978 tmp = g_strconcat(result, data, NULL);
8982 LOGW("There is no variant data in %d", idx);
8987 *var_info = (char *)result;
8989 LOGD("variant info %d:%s", *num, *var_info);
8995 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8997 int ret = MM_ERROR_NONE;
8998 mmplayer_t *player = (mmplayer_t *)hplayer;
9001 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9003 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9005 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9006 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9007 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9009 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9010 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9011 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9012 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9014 /* FIXME: seek to current position for applying new variant limitation */
9023 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9025 int ret = MM_ERROR_NONE;
9026 mmplayer_t *player = (mmplayer_t *)hplayer;
9029 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9030 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9032 *bandwidth = player->adaptive_info.limit.bandwidth;
9033 *width = player->adaptive_info.limit.width;
9034 *height = player->adaptive_info.limit.height;
9036 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9043 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9045 int ret = MM_ERROR_NONE;
9046 mmplayer_t *player = (mmplayer_t *)hplayer;
9049 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9050 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9051 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9053 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9055 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9056 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9057 else /* live case */
9058 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9060 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9067 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9069 #define IDX_FIRST_SW_CODEC 0
9070 mmplayer_t *player = (mmplayer_t *)hplayer;
9071 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9072 const char *attr_name = NULL;
9073 const char *default_type = NULL;
9074 const char *element_hw = NULL;
9075 const char *element_sw = NULL;
9078 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9080 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9082 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9083 switch (stream_type) {
9084 case MM_PLAYER_STREAM_TYPE_AUDIO:
9085 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9086 default_type = player->ini.audiocodec_default_type;
9087 element_hw = player->ini.audiocodec_element_hw;
9088 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9090 case MM_PLAYER_STREAM_TYPE_VIDEO:
9091 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9092 default_type = player->ini.videocodec_default_type;
9093 element_hw = player->ini.videocodec_element_hw;
9094 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9097 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9098 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9102 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9104 if (!strcmp(default_type, "sw"))
9105 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9107 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9109 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9110 codec_type = default_codec_type;
9112 /* to support codec selection, codec info have to be added in ini file.
9113 in case of hw codec is selected, filter elements should be applied
9114 depending on the hw capabilities. */
9115 if (codec_type != default_codec_type) {
9116 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9117 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9118 LOGE("There is no codec for type %d", codec_type);
9119 return MM_ERROR_PLAYER_NO_OP;
9122 LOGD("sorting is required");
9123 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9124 player->need_audio_dec_sorting = TRUE;
9126 player->need_video_dec_sorting = TRUE;
9129 LOGD("update %s codec_type to %d", attr_name, codec_type);
9130 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9133 return MM_ERROR_NONE;
9137 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9139 mmplayer_t *player = (mmplayer_t *)hplayer;
9140 GstElement *rg_vol_element = NULL;
9144 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9146 player->sound.rg_enable = enabled;
9148 /* just hold rgvolume enable value if pipeline is not ready */
9149 if (!player->pipeline || !player->pipeline->audiobin) {
9150 LOGD("pipeline is not ready. holding rgvolume enable value");
9151 return MM_ERROR_NONE;
9154 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9156 if (!rg_vol_element) {
9157 LOGD("rgvolume element is not created");
9158 return MM_ERROR_PLAYER_INTERNAL;
9162 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9164 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9168 return MM_ERROR_NONE;
9172 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9174 mmplayer_t *player = (mmplayer_t *)hplayer;
9175 GstElement *rg_vol_element = NULL;
9176 gboolean enable = FALSE;
9180 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9181 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9183 /* just hold enable_rg value if pipeline is not ready */
9184 if (!player->pipeline || !player->pipeline->audiobin) {
9185 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9186 *enabled = player->sound.rg_enable;
9187 return MM_ERROR_NONE;
9190 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9192 if (!rg_vol_element) {
9193 LOGD("rgvolume element is not created");
9194 return MM_ERROR_PLAYER_INTERNAL;
9197 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9198 *enabled = (bool)enable;
9202 return MM_ERROR_NONE;
9206 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9208 mmplayer_t *player = (mmplayer_t *)hplayer;
9209 MMHandleType attrs = 0;
9211 int ret = MM_ERROR_NONE;
9215 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9217 attrs = MMPLAYER_GET_ATTRS(player);
9218 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9220 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9222 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9223 return MM_ERROR_PLAYER_INTERNAL;
9226 player->video_roi.scale_x = scale_x;
9227 player->video_roi.scale_y = scale_y;
9228 player->video_roi.scale_width = scale_width;
9229 player->video_roi.scale_height = scale_height;
9231 /* check video sinkbin is created */
9232 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9233 return MM_ERROR_NONE;
9235 if (!gst_video_overlay_set_video_roi_area(
9236 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9237 scale_x, scale_y, scale_width, scale_height))
9238 ret = MM_ERROR_PLAYER_INTERNAL;
9240 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9241 scale_x, scale_y, scale_width, scale_height);
9249 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9251 mmplayer_t *player = (mmplayer_t *)hplayer;
9252 int ret = MM_ERROR_NONE;
9256 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9257 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9259 *scale_x = player->video_roi.scale_x;
9260 *scale_y = player->video_roi.scale_y;
9261 *scale_width = player->video_roi.scale_width;
9262 *scale_height = player->video_roi.scale_height;
9264 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9265 *scale_x, *scale_y, *scale_width, *scale_height);
9271 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9273 mmplayer_t *player = (mmplayer_t *)hplayer;
9277 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9279 player->client_pid = pid;
9281 LOGD("client pid[%d] %p", pid, player);
9285 return MM_ERROR_NONE;
9289 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9291 mmplayer_t *player = (mmplayer_t *)hplayer;
9292 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9293 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9297 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9298 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9301 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9303 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9305 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9306 return MM_ERROR_NONE;
9308 /* in case of audio codec default type is HW */
9310 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9311 if (player->ini.support_audio_effect)
9312 return MM_ERROR_NONE;
9313 elem_id = MMPLAYER_A_FILTER;
9315 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9316 if (player->ini.support_replaygain_control)
9317 return MM_ERROR_NONE;
9318 elem_id = MMPLAYER_A_RGVOL;
9320 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9321 if (player->ini.support_pitch_control)
9322 return MM_ERROR_NONE;
9323 elem_id = MMPLAYER_A_PITCH;
9325 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9326 if (player->ini.support_audio_effect)
9327 return MM_ERROR_NONE;
9329 /* default case handling is not required */
9332 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9333 LOGW("audio control option [%d] is not available", opt);
9336 /* setting pcm exporting option is allowed before READY state */
9337 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9338 return MM_ERROR_PLAYER_INVALID_STATE;
9340 /* check whether the audio filter exist or not after READY state,
9341 because the sw codec could be added during auto-plugging in some cases */
9342 if (!player->pipeline ||
9343 !player->pipeline->audiobin ||
9344 !player->pipeline->audiobin[elem_id].gst) {
9345 LOGW("there is no audio elem [%d]", elem_id);
9350 LOGD("audio control opt %d, available %d", opt, *available);
9354 return MM_ERROR_NONE;
9358 __mmplayer_update_duration_value(mmplayer_t *player)
9360 gboolean ret = FALSE;
9361 gint64 dur_nsec = 0;
9362 LOGD("try to update duration");
9364 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9365 player->duration = dur_nsec;
9366 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9370 if (player->duration < 0) {
9371 LOGW("duration is Non-Initialized !!!");
9372 player->duration = 0;
9375 /* update streaming service type */
9376 player->streaming_type = _mmplayer_get_stream_service_type(player);
9378 /* check duration is OK */
9379 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9380 /* FIXIT : find another way to get duration here. */
9381 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9387 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9389 /* update audio params
9390 NOTE : We need original audio params and it can be only obtained from src pad of audio
9391 decoder. Below code only valid when we are not using 'resampler' just before
9392 'audioconverter'. */
9393 GstCaps *caps_a = NULL;
9395 gint samplerate = 0, channels = 0;
9396 GstStructure *p = NULL;
9397 GstElement *aconv = NULL;
9399 LOGD("try to update audio attrs");
9401 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9403 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9404 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9405 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9406 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9408 LOGE("there is no audio converter");
9412 pad = gst_element_get_static_pad(aconv, "sink");
9415 LOGW("failed to get pad from audio converter");
9419 caps_a = gst_pad_get_current_caps(pad);
9421 LOGW("not ready to get audio caps");
9422 gst_object_unref(pad);
9426 p = gst_caps_get_structure(caps_a, 0);
9427 gst_structure_get_int(p, "rate", &samplerate);
9428 gst_structure_get_int(p, "channels", &channels);
9430 mm_player_set_attribute((MMHandleType)player, NULL,
9431 "content_audio_samplerate", samplerate,
9432 "content_audio_channels", channels, NULL);
9434 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9436 gst_caps_unref(caps_a);
9437 gst_object_unref(pad);
9443 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9445 LOGD("try to update video attrs");
9447 GstCaps *caps_v = NULL;
9451 GstStructure *p = NULL;
9453 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9454 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9456 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9458 LOGD("no videosink sink pad");
9462 caps_v = gst_pad_get_current_caps(pad);
9463 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9464 if (!caps_v && player->v_stream_caps) {
9465 caps_v = player->v_stream_caps;
9466 gst_caps_ref(caps_v);
9470 LOGD("no negotiated caps from videosink");
9471 gst_object_unref(pad);
9475 p = gst_caps_get_structure(caps_v, 0);
9476 gst_structure_get_int(p, "width", &width);
9477 gst_structure_get_int(p, "height", &height);
9479 mm_player_set_attribute((MMHandleType)player, NULL,
9480 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9482 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9484 SECURE_LOGD("width : %d height : %d", width, height);
9486 gst_caps_unref(caps_v);
9487 gst_object_unref(pad);
9490 mm_player_set_attribute((MMHandleType)player, NULL,
9491 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9492 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9499 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9501 gboolean ret = FALSE;
9502 guint64 data_size = 0;
9506 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9507 if (!player->duration)
9510 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9511 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9512 if (stat(path, &sb) == 0)
9513 data_size = (guint64)sb.st_size;
9515 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9516 data_size = player->http_content_size;
9519 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9522 guint64 bitrate = 0;
9523 guint64 msec_dur = 0;
9525 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9527 bitrate = data_size * 8 * 1000 / msec_dur;
9528 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9529 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9530 mm_player_set_attribute((MMHandleType)player, NULL,
9531 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9534 LOGD("player duration is less than 0");
9538 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9539 if (player->total_bitrate) {
9540 mm_player_set_attribute((MMHandleType)player, NULL,
9541 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9550 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9552 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9553 data->uri_type = uri_type;
9557 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9559 int ret = MM_ERROR_PLAYER_INVALID_URI;
9561 char *buffer = NULL;
9562 char *seperator = strchr(path, ',');
9563 char ext[100] = {0,}, size[100] = {0,};
9566 if ((buffer = strstr(path, "ext="))) {
9567 buffer += strlen("ext=");
9569 if (strlen(buffer)) {
9570 strncpy(ext, buffer, 99);
9572 if ((seperator = strchr(ext, ','))
9573 || (seperator = strchr(ext, ' '))
9574 || (seperator = strchr(ext, '\0'))) {
9575 seperator[0] = '\0';
9580 if ((buffer = strstr(path, "size="))) {
9581 buffer += strlen("size=");
9583 if (strlen(buffer) > 0) {
9584 strncpy(size, buffer, 99);
9586 if ((seperator = strchr(size, ','))
9587 || (seperator = strchr(size, ' '))
9588 || (seperator = strchr(size, '\0'))) {
9589 seperator[0] = '\0';
9592 mem_size = atoi(size);
9597 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9599 if (mem_size && param) {
9600 if (data->input_mem.buf)
9601 free(data->input_mem.buf);
9602 data->input_mem.buf = malloc(mem_size);
9604 if (data->input_mem.buf) {
9605 memcpy(data->input_mem.buf, param, mem_size);
9606 data->input_mem.len = mem_size;
9607 ret = MM_ERROR_NONE;
9609 LOGE("failed to alloc mem %d", mem_size);
9610 ret = MM_ERROR_PLAYER_INTERNAL;
9613 data->input_mem.offset = 0;
9614 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9621 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9623 gchar *location = NULL;
9626 int ret = MM_ERROR_NONE;
9628 if ((path = strstr(uri, "file://"))) {
9629 location = g_filename_from_uri(uri, NULL, &err);
9630 if (!location || (err != NULL)) {
9631 LOGE("Invalid URI '%s' for filesrc: %s", path,
9632 (err != NULL) ? err->message : "unknown error");
9636 MMPLAYER_FREEIF(location);
9638 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9639 return MM_ERROR_PLAYER_INVALID_URI;
9641 LOGD("path from uri: %s", location);
9644 path = (location != NULL) ? (location) : ((char *)uri);
9647 ret = _mmplayer_exist_file_path(path);
9649 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9650 if (ret == MM_ERROR_NONE) {
9651 if (_mmplayer_is_sdp_file(path)) {
9652 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9653 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9654 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9656 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9657 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9659 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9660 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9662 LOGE("invalid uri, could not play..");
9663 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9666 MMPLAYER_FREEIF(location);
9671 static mmplayer_video_decoded_data_info_t *
9672 __mmplayer_create_stream_from_pad(GstPad *pad)
9674 GstCaps *caps = NULL;
9675 GstStructure *structure = NULL;
9676 unsigned int fourcc = 0;
9677 const gchar *string_format = NULL;
9678 mmplayer_video_decoded_data_info_t *stream = NULL;
9680 MMPixelFormatType format;
9683 caps = gst_pad_get_current_caps(pad);
9685 LOGE("Caps is NULL.");
9690 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9692 structure = gst_caps_get_structure(caps, 0);
9693 gst_structure_get_int(structure, "width", &width);
9694 gst_structure_get_int(structure, "height", &height);
9695 string_format = gst_structure_get_string(structure, "format");
9698 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9699 format = _mmplayer_get_pixtype(fourcc);
9700 gst_video_info_from_caps(&info, caps);
9701 gst_caps_unref(caps);
9704 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9705 LOGE("Wrong condition!!");
9709 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9711 LOGE("failed to alloc mem for video data");
9715 stream->width = width;
9716 stream->height = height;
9717 stream->format = format;
9718 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9724 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9726 unsigned int pitch = 0;
9727 unsigned int size = 0;
9729 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9732 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9733 bo = gst_tizen_memory_get_bos(mem, index);
9735 stream->bo[index] = tbm_bo_ref(bo);
9737 LOGE("failed to get bo for index %d", index);
9740 for (index = 0; index < stream->plane_num; index++) {
9741 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9742 stream->stride[index] = pitch;
9744 stream->elevation[index] = size / pitch;
9746 stream->elevation[index] = stream->height;
9751 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9753 if (stream->format == MM_PIXEL_FORMAT_I420) {
9754 int ret = TBM_SURFACE_ERROR_NONE;
9755 tbm_surface_h surface;
9756 tbm_surface_info_s info;
9758 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9760 ret = tbm_surface_get_info(surface, &info);
9761 if (ret != TBM_SURFACE_ERROR_NONE) {
9762 tbm_surface_destroy(surface);
9766 tbm_surface_destroy(surface);
9767 stream->stride[0] = info.planes[0].stride;
9768 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9769 stream->stride[1] = info.planes[1].stride;
9770 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9771 stream->stride[2] = info.planes[2].stride;
9772 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9773 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9774 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9775 stream->stride[0] = stream->width * 4;
9776 stream->elevation[0] = stream->height;
9777 stream->bo_size = stream->stride[0] * stream->height;
9779 LOGE("Not support format %d", stream->format);
9787 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9789 tbm_bo_handle thandle;
9791 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9792 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9793 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9797 unsigned char *src = NULL;
9798 unsigned char *dest = NULL;
9799 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9801 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9803 LOGE("fail to gst_memory_map");
9807 if (!mapinfo.data) {
9808 LOGE("data pointer is wrong");
9812 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9813 if (!stream->bo[0]) {
9814 LOGE("Fail to tbm_bo_alloc!!");
9818 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9820 LOGE("thandle pointer is wrong");
9824 if (stream->format == MM_PIXEL_FORMAT_I420) {
9825 src_stride[0] = GST_ROUND_UP_4(stream->width);
9826 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9827 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9828 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9831 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9832 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9834 for (i = 0; i < 3; i++) {
9835 src = mapinfo.data + src_offset[i];
9836 dest = thandle.ptr + dest_offset[i];
9841 for (j = 0; j < stream->height >> k; j++) {
9842 memcpy(dest, src, stream->width>>k);
9843 src += src_stride[i];
9844 dest += stream->stride[i];
9847 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9848 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9850 LOGE("Not support format %d", stream->format);
9854 tbm_bo_unmap(stream->bo[0]);
9855 gst_memory_unmap(mem, &mapinfo);
9861 tbm_bo_unmap(stream->bo[0]);
9864 gst_memory_unmap(mem, &mapinfo);
9870 __mmplayer_set_pause_state(mmplayer_t *player)
9872 if (player->sent_bos)
9875 /* rtsp case, get content attrs by GstMessage */
9876 if (MMPLAYER_IS_RTSP_STREAMING(player))
9879 /* it's first time to update all content attrs. */
9880 _mmplayer_update_content_attrs(player, ATTR_ALL);
9884 __mmplayer_set_playing_state(mmplayer_t *player)
9886 gchar *audio_codec = NULL;
9888 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9889 /* initialize because auto resume is done well. */
9890 player->resumed_by_rewind = FALSE;
9891 player->playback_rate = 1.0;
9894 if (player->sent_bos)
9897 /* try to get content metadata */
9899 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9900 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9901 * legacy mmfw-player api
9903 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9905 if ((player->cmd == MMPLAYER_COMMAND_START)
9906 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9907 __mmplayer_handle_missed_plugin(player);
9910 /* check audio codec field is set or not
9911 * we can get it from typefinder or codec's caps.
9913 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9915 /* The codec format can't be sent for audio only case like amr, mid etc.
9916 * Because, parser don't make related TAG.
9917 * So, if it's not set yet, fill it with found data.
9920 if (g_strrstr(player->type, "audio/midi"))
9921 audio_codec = "MIDI";
9922 else if (g_strrstr(player->type, "audio/x-amr"))
9923 audio_codec = "AMR";
9924 else if (g_strrstr(player->type, "audio/mpeg")
9925 && !g_strrstr(player->type, "mpegversion=(int)1"))
9926 audio_codec = "AAC";
9928 audio_codec = "unknown";
9930 if (mm_player_set_attribute((MMHandleType)player, NULL,
9931 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9932 LOGE("failed to set attribute");
9934 LOGD("set audio codec type with caps");