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 void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
160 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
161 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
162 static gpointer __mmplayer_gapless_play_thread(gpointer data);
163 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
164 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
165 static void __mmplayer_release_dump_list(GList *dump_list);
166 static int __mmplayer_gst_realize(mmplayer_t *player);
167 static int __mmplayer_gst_unrealize(mmplayer_t *player);
168 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
169 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
172 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
173 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
174 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
175 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
176 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
177 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
178 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
179 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
180 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
181 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
182 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
183 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
184 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
187 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
188 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
189 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
191 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
192 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
193 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
194 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
196 static void __mmplayer_set_pause_state(mmplayer_t *player);
197 static void __mmplayer_set_playing_state(mmplayer_t *player);
198 static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
199 /*===========================================================================================
201 | FUNCTION DEFINITIONS |
203 ========================================================================================== */
205 /* This function should be called after the pipeline goes PAUSED or higher
208 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
210 static gboolean has_duration = FALSE;
211 static gboolean has_video_attrs = FALSE;
212 static gboolean has_audio_attrs = FALSE;
213 static gboolean has_bitrate = FALSE;
214 gboolean missing_only = FALSE;
215 gboolean all = FALSE;
216 MMHandleType attrs = 0;
220 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
222 /* check player state here */
223 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
224 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
225 /* give warning now only */
226 LOGW("be careful. content attributes may not available in this state ");
229 /* get content attribute first */
230 attrs = MMPLAYER_GET_ATTRS(player);
232 LOGE("cannot get content attribute");
236 /* get update flag */
238 if (flag & ATTR_MISSING_ONLY) {
240 LOGD("updating missed attr only");
243 if (flag & ATTR_ALL) {
245 has_duration = FALSE;
246 has_video_attrs = FALSE;
247 has_audio_attrs = FALSE;
250 LOGD("updating all attrs");
253 if (missing_only && all) {
254 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
255 missing_only = FALSE;
258 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
259 has_duration = __mmplayer_update_duration_value(player);
261 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
262 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
264 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
265 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
267 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
268 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
276 _mmplayer_get_stream_service_type(mmplayer_t *player)
278 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
282 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
284 player->pipeline->mainbin &&
285 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
286 STREAMING_SERVICE_NONE);
288 /* streaming service type if streaming */
289 if (!MMPLAYER_IS_STREAMING(player))
290 return STREAMING_SERVICE_NONE;
292 streaming_type = (player->duration == 0) ?
293 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
295 switch (streaming_type) {
296 case STREAMING_SERVICE_LIVE:
297 LOGD("it's live streaming");
299 case STREAMING_SERVICE_VOD:
300 LOGD("it's vod streaming");
303 LOGE("should not get here");
309 return streaming_type;
312 /* this function sets the player state and also report
313 * it to application by calling callback function
316 _mmplayer_set_state(mmplayer_t *player, int state)
318 MMMessageParamType msg = {0, };
320 MMPLAYER_RETURN_IF_FAIL(player);
322 if (MMPLAYER_CURRENT_STATE(player) == state) {
323 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
324 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
328 /* update player states */
329 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
330 MMPLAYER_CURRENT_STATE(player) = state;
332 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
333 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
336 MMPLAYER_PRINT_STATE(player);
338 switch (MMPLAYER_CURRENT_STATE(player)) {
339 case MM_PLAYER_STATE_NULL:
340 case MM_PLAYER_STATE_READY:
342 case MM_PLAYER_STATE_PAUSED:
343 __mmplayer_set_pause_state(player);
345 case MM_PLAYER_STATE_PLAYING:
346 __mmplayer_set_playing_state(player);
348 case MM_PLAYER_STATE_NONE:
350 LOGW("invalid target state, there is nothing to do.");
355 /* post message to application */
356 if (MMPLAYER_TARGET_STATE(player) == state) {
357 /* fill the message with state of player */
358 msg.union_type = MM_MSG_UNION_STATE;
359 msg.state.previous = MMPLAYER_PREV_STATE(player);
360 msg.state.current = MMPLAYER_CURRENT_STATE(player);
362 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
364 /* state changed by resource callback */
365 if (player->interrupted_by_resource)
366 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
367 else /* state changed by usecase */
368 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
371 LOGD("intermediate state, do nothing.");
372 MMPLAYER_PRINT_STATE(player);
376 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
377 && !player->sent_bos) {
378 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
379 player->sent_bos = TRUE;
386 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
388 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
389 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
391 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
393 LOGD("incoming command : %d ", command);
395 current_state = MMPLAYER_CURRENT_STATE(player);
396 pending_state = MMPLAYER_PENDING_STATE(player);
398 MMPLAYER_PRINT_STATE(player);
401 case MMPLAYER_COMMAND_CREATE:
403 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
405 if (current_state == MM_PLAYER_STATE_NULL ||
406 current_state == MM_PLAYER_STATE_READY ||
407 current_state == MM_PLAYER_STATE_PAUSED ||
408 current_state == MM_PLAYER_STATE_PLAYING)
413 case MMPLAYER_COMMAND_DESTROY:
415 /* destroy can called anytime */
417 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
421 case MMPLAYER_COMMAND_REALIZE:
423 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
425 if (pending_state != MM_PLAYER_STATE_NONE) {
428 /* need ready state to realize */
429 if (current_state == MM_PLAYER_STATE_READY)
432 if (current_state != MM_PLAYER_STATE_NULL)
438 case MMPLAYER_COMMAND_UNREALIZE:
440 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
442 if (current_state == MM_PLAYER_STATE_NULL)
447 case MMPLAYER_COMMAND_START:
449 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
451 if (pending_state == MM_PLAYER_STATE_NONE) {
452 if (current_state == MM_PLAYER_STATE_PLAYING)
454 else if (current_state != MM_PLAYER_STATE_READY &&
455 current_state != MM_PLAYER_STATE_PAUSED)
457 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
459 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
460 LOGD("player is going to paused state, just change the pending state as playing");
467 case MMPLAYER_COMMAND_STOP:
469 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
471 if (current_state == MM_PLAYER_STATE_READY)
474 /* need playing/paused state to stop */
475 if (current_state != MM_PLAYER_STATE_PLAYING &&
476 current_state != MM_PLAYER_STATE_PAUSED)
481 case MMPLAYER_COMMAND_PAUSE:
483 if (MMPLAYER_IS_LIVE_STREAMING(player))
486 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
487 goto NOT_COMPLETED_SEEK;
489 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
491 if (pending_state == MM_PLAYER_STATE_NONE) {
492 if (current_state == MM_PLAYER_STATE_PAUSED)
494 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
496 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
499 if (current_state == MM_PLAYER_STATE_PAUSED)
500 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
507 case MMPLAYER_COMMAND_RESUME:
509 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
510 goto NOT_COMPLETED_SEEK;
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
514 if (pending_state == MM_PLAYER_STATE_NONE) {
515 if (current_state == MM_PLAYER_STATE_PLAYING)
517 else if (current_state != MM_PLAYER_STATE_PAUSED)
519 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
521 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
522 LOGD("player is going to paused state, just change the pending state as playing");
532 player->cmd = command;
534 return MM_ERROR_NONE;
537 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
538 MMPLAYER_STATE_GET_NAME(current_state), command);
539 return MM_ERROR_PLAYER_INVALID_STATE;
542 LOGW("not completed seek");
543 return MM_ERROR_PLAYER_DOING_SEEK;
546 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
547 return MM_ERROR_PLAYER_NO_OP;
550 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
551 return MM_ERROR_PLAYER_NO_OP;
554 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
556 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
557 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
560 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
561 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
563 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
564 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
566 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
567 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
570 LOGE("invalid mmplayer resource type %d", type);
571 return MM_ERROR_PLAYER_INTERNAL;
574 if (player->hw_resource[type] != NULL) {
575 LOGD("[%d type] resource was already acquired", type);
576 return MM_ERROR_NONE;
579 LOGD("mark for acquire [%d type] resource", type);
580 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
581 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
582 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
583 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
584 return MM_ERROR_PLAYER_INTERNAL;
587 LOGD("commit [%d type] resource", type);
588 rm_ret = mm_resource_manager_commit(player->resource_manager);
589 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
590 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
591 return MM_ERROR_PLAYER_INTERNAL;
595 return MM_ERROR_NONE;
598 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
600 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
602 MMPLAYER_RETURN_IF_FAIL(player);
603 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
605 rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
606 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
607 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
611 rm_ret = mm_resource_manager_commit(player->resource_manager);
612 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
613 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
616 /* de-initialize resource manager */
617 rm_ret = mm_resource_manager_destroy(player->resource_manager);
618 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
619 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
623 player->resource_manager = NULL;
625 LOGD("resource manager is destroyed");
628 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
630 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
634 if (player->hw_resource[type] == NULL) {
635 LOGD("there is no acquired [%d type] resource", type);
636 return MM_ERROR_NONE;
639 LOGD("mark for release [%d type] resource", type);
640 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
641 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
642 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
643 return MM_ERROR_PLAYER_INTERNAL;
646 player->hw_resource[type] = NULL;
648 LOGD("commit [%d type] resource", type);
649 rm_ret = mm_resource_manager_commit(player->resource_manager);
650 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
651 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
652 return MM_ERROR_PLAYER_INTERNAL;
656 return MM_ERROR_NONE;
660 __mmplayer_initialize_gapless_play(mmplayer_t *player)
666 player->smooth_streaming = FALSE;
667 player->videodec_linked = 0;
668 player->audiodec_linked = 0;
669 player->textsink_linked = 0;
670 player->is_external_subtitle_present = FALSE;
671 player->is_external_subtitle_added_now = FALSE;
672 player->not_supported_codec = MISSING_PLUGIN_NONE;
673 player->can_support_codec = FOUND_PLUGIN_NONE;
674 player->pending_seek.is_pending = false;
675 player->pending_seek.pos = 0;
676 player->msg_posted = FALSE;
677 player->has_many_types = FALSE;
678 player->no_more_pad = FALSE;
679 player->not_found_demuxer = 0;
680 player->seek_state = MMPLAYER_SEEK_NONE;
681 player->is_subtitle_force_drop = FALSE;
682 player->play_subtitle = FALSE;
683 player->adjust_subtitle_pos = 0;
685 player->total_bitrate = 0;
686 player->total_maximum_bitrate = 0;
688 _mmplayer_track_initialize(player);
689 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
691 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
692 player->bitrate[i] = 0;
693 player->maximum_bitrate[i] = 0;
696 if (player->v_stream_caps) {
697 gst_caps_unref(player->v_stream_caps);
698 player->v_stream_caps = NULL;
701 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
703 /* clean found audio decoders */
704 if (player->audio_decoders) {
705 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
706 player->audio_decoders = NULL;
709 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
714 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
716 LOGI("set pipeline reconfigure state %d", state);
717 MMPLAYER_RECONFIGURE_LOCK(player);
718 player->gapless.reconfigure = state;
719 if (!state) /* wake up the waiting job */
720 MMPLAYER_RECONFIGURE_SIGNAL(player);
721 MMPLAYER_RECONFIGURE_UNLOCK(player);
725 __mmplayer_gapless_play_thread(gpointer data)
727 mmplayer_t *player = (mmplayer_t *)data;
728 mmplayer_gst_element_t *mainbin = NULL;
730 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
732 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
733 while (!player->gapless_play_thread_exit) {
734 LOGD("gapless play thread started. waiting for signal.");
735 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
737 LOGD("reconfigure pipeline for gapless play.");
739 if (player->gapless_play_thread_exit) {
740 _mmplayer_set_reconfigure_state(player, FALSE);
741 LOGD("exiting gapless play thread");
745 mainbin = player->pipeline->mainbin;
747 if (MMPLAYER_USE_DECODEBIN(player)) {
748 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
749 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* decodebin */
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
753 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* uridecodebin */
754 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
755 mainbin[MMPLAYER_M_TYPEFIND].gst = NULL;
756 mainbin[MMPLAYER_M_SRC].gst = NULL;
759 /* Initialize Player values */
760 __mmplayer_initialize_gapless_play(player);
762 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
764 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
770 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
772 GSource *source = NULL;
776 source = g_main_context_find_source_by_id(context, source_id);
777 if (source != NULL) {
778 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
779 g_source_destroy(source);
786 _mmplayer_watcher_removed_notify(gpointer data)
788 mmplayer_t *player = (mmplayer_t *)data;
789 MMPLAYER_RETURN_IF_FAIL(player);
791 MMPLAYER_BUS_WATCHER_LOCK(player);
792 player->bus_watcher = 0;
793 MMPLAYER_BUS_WATCHER_SIGNAL(player);
794 MMPLAYER_BUS_WATCHER_UNLOCK(player);
798 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
800 mmplayer_t *player = (mmplayer_t *)hplayer;
803 MMPLAYER_RETURN_IF_FAIL(player);
805 /* disconnecting bus watch */
806 if (player->bus_watcher > 0) {
807 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
808 MMPLAYER_BUS_WATCHER_LOCK(player);
809 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
810 while (player->bus_watcher > 0) {
811 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
812 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
813 player->bus_watcher);
817 MMPLAYER_BUS_WATCHER_UNLOCK(player);
818 g_mutex_clear(&player->bus_watcher_mutex);
819 g_cond_clear(&player->bus_watcher_cond);
826 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
828 mmplayer_t *player = (mmplayer_t *)hplayer;
829 GstMessage *msg = NULL;
830 GQueue *queue = NULL;
833 MMPLAYER_RETURN_IF_FAIL(player);
835 /* destroy the gst bus msg thread */
836 if (player->bus_msg_thread) {
837 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
838 player->bus_msg_thread_exit = TRUE;
839 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
840 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
842 LOGD("gst bus msg thread exit.");
843 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
844 player->bus_msg_thread = NULL;
846 g_mutex_clear(&player->bus_msg_thread_mutex);
847 g_cond_clear(&player->bus_msg_thread_cond);
850 g_mutex_lock(&player->bus_msg_q_lock);
851 queue = player->bus_msg_q;
852 while (!g_queue_is_empty(queue)) {
853 msg = (GstMessage *)g_queue_pop_head(queue);
858 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
859 gst_message_unref(msg);
861 g_mutex_unlock(&player->bus_msg_q_lock);
867 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
869 GstElement *parent = NULL;
871 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
872 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
875 MMPLAYER_FSINK_LOCK(player);
877 /* get parent of fakesink */
878 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
880 LOGD("fakesink already removed");
884 gst_element_set_locked_state(fakesink->gst, TRUE);
886 /* setting the state to NULL never returns async
887 * so no need to wait for completion of state transition
889 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
890 LOGE("fakesink state change failure!");
891 /* FIXIT : should I return here? or try to proceed to next? */
894 /* remove fakesink from it's parent */
895 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
896 LOGE("failed to remove fakesink");
898 gst_object_unref(parent);
903 gst_object_unref(parent);
905 LOGD("state-holder removed");
907 gst_element_set_locked_state(fakesink->gst, FALSE);
909 MMPLAYER_FSINK_UNLOCK(player);
914 gst_element_set_locked_state(fakesink->gst, FALSE);
916 MMPLAYER_FSINK_UNLOCK(player);
920 static GstPadProbeReturn
921 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
923 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
924 return GST_PAD_PROBE_OK;
928 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
930 gint64 stop_running_time = 0;
931 gint64 position_running_time = 0;
935 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
936 if ((player->gapless.update_segment[idx] == TRUE) ||
937 !(player->track[idx].event_probe_id)) {
939 LOGW("[%d] skip", idx);
944 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
946 gst_segment_to_running_time(&player->gapless.segment[idx],
947 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
948 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
950 gst_segment_to_running_time(&player->gapless.segment[idx],
951 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
953 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
955 gst_segment_to_running_time(&player->gapless.segment[idx],
956 GST_FORMAT_TIME, player->duration);
959 position_running_time =
960 gst_segment_to_running_time(&player->gapless.segment[idx],
961 GST_FORMAT_TIME, player->gapless.segment[idx].position);
963 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
964 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
966 GST_TIME_ARGS(stop_running_time),
967 GST_TIME_ARGS(position_running_time),
968 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
969 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
971 position_running_time = MAX(position_running_time, stop_running_time);
972 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
973 GST_FORMAT_TIME, player->gapless.segment[idx].start);
974 position_running_time = MAX(0, position_running_time);
975 position = MAX(position, position_running_time);
979 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
980 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
981 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
983 player->gapless.start_time[stream_type] += position;
989 static GstPadProbeReturn
990 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
992 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
993 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
994 mmplayer_t *player = (mmplayer_t *)data;
995 GstCaps *caps = NULL;
996 GstStructure *str = NULL;
997 const gchar *name = NULL;
998 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
999 gboolean caps_ret = TRUE;
1001 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1002 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1003 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1004 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1005 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1008 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1012 if (strstr(name, "audio")) {
1013 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1014 } else if (strstr(name, "video")) {
1015 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1017 /* text track is not supportable */
1018 LOGE("invalid name %s", name);
1022 switch (GST_EVENT_TYPE(event)) {
1025 /* in case of gapless, drop eos event not to send it to sink */
1026 if (player->gapless.reconfigure && !player->msg_posted) {
1027 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1028 ret = GST_PAD_PROBE_DROP;
1032 case GST_EVENT_STREAM_START:
1034 __mmplayer_gst_selector_update_start_time(player, stream_type);
1037 case GST_EVENT_FLUSH_STOP:
1039 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1040 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1041 player->gapless.start_time[stream_type] = 0;
1044 case GST_EVENT_SEGMENT:
1049 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1050 gst_event_copy_segment(event, &segment);
1052 if (segment.format != GST_FORMAT_TIME)
1055 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1056 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1057 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1058 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1059 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1060 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1062 /* keep the all the segment ev to cover the seeking */
1063 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1064 player->gapless.update_segment[stream_type] = TRUE;
1066 if (!player->gapless.running)
1069 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1071 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1073 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1074 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1075 gst_event_unref(event);
1076 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1082 gdouble proportion = 0.0;
1083 GstClockTimeDiff diff = 0;
1084 GstClockTime timestamp = 0;
1085 gint64 running_time_diff = -1;
1086 GstQOSType type = 0;
1087 GstEvent *tmpev = NULL;
1089 running_time_diff = player->gapless.segment[stream_type].base;
1091 if (running_time_diff <= 0) /* don't need to adjust */
1094 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1095 gst_event_unref(event);
1097 if (timestamp < running_time_diff) {
1098 LOGW("QOS event from previous group");
1099 ret = GST_PAD_PROBE_DROP;
1104 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1105 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1106 stream_type, GST_TIME_ARGS(timestamp),
1107 GST_TIME_ARGS(running_time_diff),
1108 GST_TIME_ARGS(timestamp - running_time_diff));
1111 timestamp -= running_time_diff;
1113 /* That case is invalid for QoS events */
1114 if (diff < 0 && -diff > timestamp) {
1115 LOGW("QOS event from previous group");
1116 ret = GST_PAD_PROBE_DROP;
1120 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1121 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1131 gst_caps_unref(caps);
1135 /* create fakesink for audio or video path without audiobin or videobin */
1137 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1139 GstElement *pipeline = NULL;
1140 GstElement *fakesink = NULL;
1141 GstPad *sinkpad = NULL;
1144 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1146 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1149 fakesink = gst_element_factory_make("fakesink", NULL);
1150 if (fakesink == NULL) {
1151 LOGE("failed to create fakesink");
1155 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1156 LOGE("failed to add fakesink to pipeline");
1161 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1163 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1165 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1166 LOGE("failed to link fakesink");
1170 if (strstr(name, "video")) {
1171 if (player->v_stream_caps) {
1172 gst_caps_unref(player->v_stream_caps);
1173 player->v_stream_caps = NULL;
1175 if (player->ini.set_dump_element_flag)
1176 __mmplayer_add_dump_buffer_probe(player, fakesink);
1179 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1180 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1182 /* store it as it's sink element */
1183 __mmplayer_add_sink(player, fakesink, FALSE);
1186 gst_object_unref(GST_OBJECT(sinkpad));
1194 gst_object_unref(GST_OBJECT(sinkpad));
1197 gst_element_set_state(fakesink, GST_STATE_NULL);
1199 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1200 gst_object_unref(GST_OBJECT(fakesink));
1207 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1209 GstElement *pipeline = NULL;
1210 GstElement *concat = NULL;
1213 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1215 concat = gst_element_factory_make("concat", NULL);
1217 LOGE("failed to create concat");
1221 gst_element_set_state(concat, GST_STATE_PAUSED);
1223 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1224 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1225 LOGE("failed to add concat to pipeline");
1226 gst_element_set_state(concat, GST_STATE_NULL);
1227 gst_object_unref(GST_OBJECT(concat));
1231 LOGD("Create concat [%d] element", elem_idx);
1233 player->pipeline->mainbin[elem_idx].id = elem_idx;
1234 player->pipeline->mainbin[elem_idx].gst = concat;
1241 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1243 GstElement *pipeline = NULL;
1244 GstElement *selector = NULL;
1245 GstPad *srcpad = NULL;
1248 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1250 selector = gst_element_factory_make("input-selector", NULL);
1252 LOGE("failed to create input-selector");
1255 g_object_set(selector, "sync-streams", TRUE, NULL);
1257 srcpad = gst_element_get_static_pad(selector, "src");
1259 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1260 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1261 __mmplayer_gst_selector_blocked, NULL, NULL);
1262 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1263 __mmplayer_gst_selector_event_probe, player, NULL);
1265 gst_element_set_state(selector, GST_STATE_PAUSED);
1267 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1268 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1269 LOGE("failed to add selector to pipeline");
1271 if (player->track[stream_type].block_id != 0)
1272 gst_pad_remove_probe (srcpad, player->track[stream_type].block_id);
1273 player->track[stream_type].block_id = 0;
1275 if (player->track[stream_type].event_probe_id != 0)
1276 gst_pad_remove_probe (srcpad, player->track[stream_type].event_probe_id);
1277 player->track[stream_type].event_probe_id = 0;
1279 gst_object_unref(GST_OBJECT(srcpad));
1281 gst_element_set_state(selector, GST_STATE_NULL);
1282 gst_object_unref(GST_OBJECT(selector));
1286 gst_object_unref(GST_OBJECT(srcpad));
1288 player->pipeline->mainbin[elem_idx].id = elem_idx;
1289 player->pipeline->mainbin[elem_idx].gst = selector;
1296 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1298 mmplayer_t *player = (mmplayer_t *)data;
1299 GstElement *combiner = NULL;
1300 GstCaps *caps = NULL;
1301 GstStructure *str = NULL;
1302 const gchar *name = NULL;
1303 GstPad *sinkpad = NULL;
1304 gboolean first_track = FALSE;
1305 gboolean caps_ret = TRUE;
1307 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1308 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1311 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1312 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1314 LOGD("pad-added signal handling");
1316 /* get mimetype from caps */
1317 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1321 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1323 LOGD("detected mimetype : %s", name);
1326 if (strstr(name, "video")) {
1328 gchar *caps_str = NULL;
1330 caps_str = gst_caps_to_string(caps);
1331 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1332 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1333 player->set_mode.video_zc = true;
1335 MMPLAYER_FREEIF(caps_str);
1337 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1338 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1340 LOGD("surface type : %d", stype);
1342 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1343 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1347 /* in case of exporting video frame, it requires the 360 video filter.
1348 * it will be handled in _no_more_pads(). */
1349 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1350 __mmplayer_gst_make_fakesink(player, pad, name);
1354 if (MMPLAYER_USE_DECODEBIN(player)) {
1355 LOGD("video selector is required");
1356 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1358 LOGD("video concat is required");
1359 elem_idx = MMPLAYER_M_V_CONCAT;
1361 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1362 } else if (strstr(name, "audio")) {
1363 gint samplerate = 0;
1366 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1367 if (player->build_audio_offload)
1368 player->no_more_pad = TRUE; /* remove state holder */
1369 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1373 gst_structure_get_int(str, "rate", &samplerate);
1374 gst_structure_get_int(str, "channels", &channels);
1376 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1377 __mmplayer_gst_make_fakesink(player, pad, name);
1380 if (MMPLAYER_USE_DECODEBIN(player)) {
1381 LOGD("audio selector is required");
1382 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1384 LOGD("audio concat is required");
1385 elem_idx = MMPLAYER_M_A_CONCAT;
1387 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1389 } else if (strstr(name, "text")) {
1390 if (MMPLAYER_USE_DECODEBIN(player)) {
1391 LOGD("text selector is required");
1392 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1394 LOGD("text concat is required");
1395 elem_idx = MMPLAYER_M_T_CONCAT;
1397 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1399 LOGE("invalid caps info");
1403 /* check selector and create it */
1404 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1405 if (MMPLAYER_USE_DECODEBIN(player))
1406 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1408 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1414 LOGD("Combiner element is already created.");
1418 sinkpad = gst_element_request_pad_simple(combiner, "sink_%u");
1420 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1422 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1423 LOGE("failed to link combiner");
1424 gst_object_unref(GST_OBJECT(combiner));
1429 if (MMPLAYER_USE_DECODEBIN(player)) {
1430 LOGD("this track will be activated");
1431 g_object_set(combiner, "active-pad", sinkpad, NULL);
1435 if (MMPLAYER_USE_DECODEBIN(player)) {
1436 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1438 /* apply the text track information */
1439 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1440 mm_player_set_attribute((MMHandleType)player, NULL,
1441 "content_text_track_num", player->track[stream_type].total_track_num,
1442 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1443 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1450 gst_caps_unref(caps);
1453 gst_object_unref(GST_OBJECT(sinkpad));
1457 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1462 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1464 GstPad *srcpad = NULL;
1467 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1469 LOGD("type %d", type);
1472 LOGD("there is no %d track", type);
1476 srcpad = gst_element_get_static_pad(combiner, "src");
1478 LOGE("failed to get srcpad from combiner");
1482 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1484 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1486 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1487 if (player->track[type].block_id) {
1488 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1489 player->track[type].block_id = 0;
1493 gst_object_unref(GST_OBJECT(srcpad));
1502 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1504 gint active_index = 0;
1507 MMPLAYER_RETURN_IF_FAIL(player);
1509 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1511 /* change track to active pad */
1512 active_index = player->track[type].active_track_index;
1513 if ((active_index != DEFAULT_TRACK_INDEX) &&
1514 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1515 LOGW("failed to change %d type track to %d", type, active_index);
1516 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1520 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1521 mm_player_set_attribute((MMHandleType)player, NULL,
1522 "content_text_track_num", player->track[type].total_track_num,
1523 "current_text_track_index", player->track[type].active_track_index, NULL);
1530 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1533 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1535 if (!audio_selector) {
1536 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1538 /* in case the source is changed, output can be changed. */
1539 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1540 LOGD("remove previous audiobin if it exist");
1542 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1543 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1545 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1546 MMPLAYER_FREEIF(player->pipeline->audiobin);
1549 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1550 _mmplayer_pipeline_complete(NULL, player);
1555 /* apply the audio track information */
1556 if (MMPLAYER_USE_DECODEBIN(player))
1557 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1559 /* create audio sink path */
1560 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1561 LOGE("failed to create audio sink path");
1570 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1573 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1575 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1576 LOGD("text path is not supported");
1580 /* apply the text track information */
1581 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1583 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1584 player->has_closed_caption = TRUE;
1586 /* create text decode path */
1587 player->no_more_pad = TRUE;
1589 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1590 LOGE("failed to create text sink path");
1599 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1601 gint64 dur_bytes = 0L;
1604 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1605 player->pipeline->mainbin && player->streamer, FALSE);
1607 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1608 LOGE("fail to get duration.");
1610 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1611 * use file information was already set on Q2 when it was created. */
1612 _mm_player_streaming_set_queue2(player->streamer,
1613 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1614 TRUE, /* use_buffering */
1615 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1616 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1623 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1625 mmplayer_t *player = NULL;
1626 GstElement *video_selector = NULL;
1627 GstElement *audio_selector = NULL;
1628 GstElement *text_selector = NULL;
1631 player = (mmplayer_t *)data;
1633 LOGD("no-more-pad signal handling");
1635 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1636 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1637 LOGW("player is shutting down");
1641 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1642 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1643 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1644 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1645 LOGE("failed to set queue2 buffering");
1650 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1651 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1652 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1654 if (!video_selector && !audio_selector && !text_selector) {
1655 LOGW("there is no selector");
1656 player->no_more_pad = TRUE;
1660 /* create video path followed by video-select */
1661 if (video_selector && !audio_selector && !text_selector)
1662 player->no_more_pad = TRUE;
1664 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1667 /* create audio path followed by audio-select */
1668 if (audio_selector && !text_selector)
1669 player->no_more_pad = TRUE;
1671 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1674 /* create text path followed by text-select */
1675 __mmplayer_create_text_sink_path(player, text_selector);
1678 _mmplayer_set_reconfigure_state(player, FALSE);
1683 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1685 gboolean ret = FALSE;
1686 GstElement *pipeline = NULL;
1687 GstPad *sinkpad = NULL;
1690 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1691 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1693 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1695 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1697 LOGE("failed to get pad from sinkbin");
1703 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1704 LOGE("failed to link sinkbin for reusing");
1705 goto EXIT; /* exit either pass or fail */
1709 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1710 LOGE("failed to set state(READY) to sinkbin");
1715 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1716 LOGE("failed to add sinkbin to pipeline");
1721 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1722 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1727 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1728 LOGE("failed to set state(PAUSED) to sinkbin");
1737 gst_object_unref(GST_OBJECT(sinkpad));
1745 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1747 mmplayer_t *player = NULL;
1748 GstCaps *caps = NULL;
1749 gchar *caps_str = NULL;
1750 GstStructure *str = NULL;
1751 const gchar *name = NULL;
1752 GstElement *sinkbin = NULL;
1753 gboolean reusing = FALSE;
1754 gboolean caps_ret = TRUE;
1755 gchar *sink_pad_name = "sink";
1758 player = (mmplayer_t *)data;
1761 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1762 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1763 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1765 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1769 gst_caps_unref(caps);
1770 caps = gst_caps_ref(ref_caps);
1773 caps_str = gst_caps_to_string(caps);
1775 LOGD("detected mimetype : %s", name);
1777 if (strstr(name, "audio")) {
1778 if (player->pipeline->audiobin == NULL) {
1779 const gchar *audio_format = gst_structure_get_string(str, "format");
1781 LOGD("original audio format %s", audio_format);
1782 mm_player_set_attribute((MMHandleType)player, NULL,
1783 "content_audio_format", audio_format, strlen(audio_format), NULL);
1786 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1787 LOGE("failed to create audiobin. continuing without audio");
1791 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1792 LOGD("creating audiobin success");
1795 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1796 LOGD("reusing audiobin");
1797 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1799 } else if (strstr(name, "video")) {
1800 /* 1. zero copy is updated at _decode_pad_added()
1801 * 2. NULL surface type is handled in _decode_pad_added() */
1802 LOGD("zero copy %d", player->set_mode.video_zc);
1803 if (player->pipeline->videobin == NULL) {
1804 int surface_type = 0;
1805 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1806 LOGD("display_surface_type (%d)", surface_type);
1808 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1809 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1810 LOGE("failed to acquire video overlay resource");
1814 player->interrupted_by_resource = FALSE;
1816 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1817 LOGE("failed to create videobin. continuing without video");
1821 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1822 LOGD("creating videosink bin success");
1825 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1826 LOGD("re-using videobin");
1827 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1829 } else if (strstr(name, "text")) {
1830 if (player->pipeline->textbin == NULL) {
1831 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1832 LOGE("failed to create text sink bin. continuing without text");
1836 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1837 player->textsink_linked = 1;
1838 LOGD("creating textsink bin success");
1840 if (!player->textsink_linked) {
1841 LOGD("re-using textbin");
1843 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1844 player->textsink_linked = 1;
1846 /* linked textbin exist which means that the external subtitle path exist already */
1847 LOGW("ignoring internal subtitle since external subtitle is available");
1850 sink_pad_name = "text_sink";
1852 LOGW("unknown mime type %s, ignoring it", name);
1856 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1859 LOGD("[handle: %p] success to create and link sink bin", player);
1861 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1862 * streaming task. if the task blocked, then buffer will not flow to the next element
1863 *(autoplugging element). so this is special hack for streaming. please try to remove it
1865 /* dec stream count. we can remove fakesink if it's zero */
1866 if (player->num_dynamic_pad)
1867 player->num_dynamic_pad--;
1869 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1871 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1872 _mmplayer_pipeline_complete(NULL, player);
1876 MMPLAYER_FREEIF(caps_str);
1879 gst_caps_unref(caps);
1885 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1887 int required_angle = 0; /* Angle required for straight view */
1888 int rotation_angle = 0;
1890 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1891 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1893 /* Counter clockwise */
1894 switch (orientation) {
1899 required_angle = 270;
1902 required_angle = 180;
1905 required_angle = 90;
1909 rotation_angle = display_angle + required_angle;
1910 if (rotation_angle >= 360)
1911 rotation_angle -= 360;
1913 /* check if supported or not */
1914 if (rotation_angle % 90) {
1915 LOGD("not supported rotation angle = %d", rotation_angle);
1919 switch (rotation_angle) {
1921 *value = MM_DISPLAY_ROTATION_NONE;
1924 *value = MM_DISPLAY_ROTATION_90;
1927 *value = MM_DISPLAY_ROTATION_180;
1930 *value = MM_DISPLAY_ROTATION_270;
1934 LOGD("setting rotation property value : %d", *value);
1940 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1942 int display_rotation = 0;
1943 gchar *org_orient = NULL;
1944 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1947 LOGE("cannot get content attribute");
1948 return MM_ERROR_PLAYER_INTERNAL;
1951 if (display_angle) {
1952 /* update user rotation */
1953 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1955 /* Counter clockwise */
1956 switch (display_rotation) {
1957 case MM_DISPLAY_ROTATION_NONE:
1960 case MM_DISPLAY_ROTATION_90:
1961 *display_angle = 90;
1963 case MM_DISPLAY_ROTATION_180:
1964 *display_angle = 180;
1966 case MM_DISPLAY_ROTATION_270:
1967 *display_angle = 270;
1970 LOGW("wrong angle type : %d", display_rotation);
1973 LOGD("check user angle: %d", *display_angle);
1977 /* Counter clockwise */
1978 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1981 if (!strcmp(org_orient, "rotate-90"))
1983 else if (!strcmp(org_orient, "rotate-180"))
1985 else if (!strcmp(org_orient, "rotate-270"))
1988 LOGD("original rotation is %s", org_orient);
1990 LOGD("content_video_orientation get fail");
1993 LOGD("check orientation: %d", *orientation);
1996 return MM_ERROR_NONE;
1999 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
2001 int rotation_value = 0;
2002 int orientations = 0; // current supported angle values are 0, 90, 180, 270
2003 int display_angle = 0;
2006 /* check video sinkbin is created */
2007 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2010 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2012 /* get rotation value to set */
2013 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2014 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2015 LOGD("set video param : rotate %d", rotation_value);
2018 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2020 MMHandleType attrs = 0;
2024 /* check video sinkbin is created */
2025 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2026 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2029 attrs = MMPLAYER_GET_ATTRS(player);
2030 MMPLAYER_RETURN_IF_FAIL(attrs);
2032 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2033 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2034 LOGD("set video param : visible %d", visible);
2037 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2039 MMHandleType attrs = 0;
2040 int display_method = 0;
2043 /* check video sinkbin is created */
2044 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2047 attrs = MMPLAYER_GET_ATTRS(player);
2048 MMPLAYER_RETURN_IF_FAIL(attrs);
2050 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2051 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2052 LOGD("set video param : method %d", display_method);
2055 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2057 MMHandleType attrs = 0;
2061 /* check video sinkbin is created */
2062 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2065 attrs = MMPLAYER_GET_ATTRS(player);
2066 MMPLAYER_RETURN_IF_FAIL(attrs);
2068 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2069 MMPLAYER_RETURN_IF_FAIL(handle);
2071 gst_video_overlay_set_video_roi_area(
2072 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2073 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2074 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2075 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2078 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2080 MMHandleType attrs = 0;
2085 int win_roi_width = 0;
2086 int win_roi_height = 0;
2089 /* check video sinkbin is created */
2090 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2093 attrs = MMPLAYER_GET_ATTRS(player);
2094 MMPLAYER_RETURN_IF_FAIL(attrs);
2096 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2097 MMPLAYER_RETURN_IF_FAIL(handle);
2099 /* It should be set after setting window */
2100 mm_attrs_multiple_get(attrs, NULL,
2101 "display_win_roi_x", &win_roi_x,
2102 "display_win_roi_y", &win_roi_y,
2103 "display_win_roi_width", &win_roi_width,
2104 "display_win_roi_height", &win_roi_height, NULL);
2106 /* After setting window handle, set display roi area */
2107 gst_video_overlay_set_display_roi_area(
2108 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2109 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2110 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2111 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2114 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2116 MMHandleType attrs = 0;
2117 gchar *handle = NULL;
2119 /* check video sinkbin is created */
2120 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2123 attrs = MMPLAYER_GET_ATTRS(player);
2124 MMPLAYER_RETURN_IF_FAIL(attrs);
2126 /* common case if using overlay surface */
2127 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2128 MMPLAYER_RETURN_IF_FAIL(handle);
2130 gst_video_overlay_set_wl_window_exported_shell_handle(
2131 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2133 LOGD("set video param: exported_shell_handle (%s)", handle);
2136 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2138 MMHandleType attrs = 0;
2141 /* check video sinkbin is created */
2142 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2145 attrs = MMPLAYER_GET_ATTRS(player);
2146 MMPLAYER_RETURN_IF_FAIL(attrs);
2148 /* common case if using overlay surface */
2149 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2150 MMPLAYER_RETURN_IF_FAIL(handle);
2152 /* default is using wl_surface_id */
2153 LOGD("set video param : wl_surface_id %d", handle);
2154 gst_video_overlay_set_wl_window_wl_surface_id(
2155 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2160 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2162 gboolean update_all_param = FALSE;
2163 int curr_type = MM_DISPLAY_SURFACE_NUM;
2167 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2168 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2169 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2170 LOGW("videosink is not ready yet");
2171 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2174 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2176 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2177 LOGE("current type(%d) is wrong", curr_type);
2178 return MM_ERROR_PLAYER_INTERNAL;
2181 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2182 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2183 return MM_ERROR_PLAYER_INTERNAL;
2186 LOGD("param_name : %s", param_name);
2187 if (!g_strcmp0(param_name, "update_all_param"))
2188 update_all_param = TRUE;
2190 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2191 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2193 return MM_ERROR_NONE;
2195 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2196 __mmplayer_video_param_set_display_overlay(player);
2197 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2198 __mmplayer_video_param_set_display_method(player);
2199 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2200 __mmplayer_video_param_set_display_visible(player);
2201 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2202 __mmplayer_video_param_set_display_rotation(player);
2203 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2204 __mmplayer_video_param_set_roi_area(player);
2205 if (update_all_param)
2206 __mmplayer_video_param_set_video_roi_area(player);
2209 return MM_ERROR_NONE;
2212 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2214 gboolean disable_overlay = FALSE;
2217 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2218 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2219 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2221 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2222 LOGW("Display control is not supported");
2223 return MM_ERROR_PLAYER_INTERNAL;
2226 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2228 if (disable == (bool)disable_overlay) {
2229 LOGE("It's the same with current setting: (%d)", disable);
2230 return MM_ERROR_NONE;
2234 LOGE("disable overlay");
2235 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2237 /* release overlay resource */
2238 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2239 LOGE("failed to release overlay resource");
2240 return MM_ERROR_PLAYER_INTERNAL;
2243 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2244 LOGE("failed to acquire video overlay resource");
2245 return MM_ERROR_PLAYER_INTERNAL;
2247 player->interrupted_by_resource = FALSE;
2249 LOGD("enable overlay");
2250 __mmplayer_video_param_set_display_overlay(player);
2251 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2252 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2256 return MM_ERROR_NONE;
2260 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2262 int ret = MM_ERROR_NONE;
2263 mmplayer_t *player = (mmplayer_t *)hplayer;
2266 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2268 if (MMPLAYER_USE_DECODEBIN(player)) {
2269 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2274 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2275 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2276 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2278 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
2280 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2282 /* release decoder resource */
2283 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2284 LOGE("failed to release video decoder resources");
2285 return MM_ERROR_PLAYER_INTERNAL;
2287 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2289 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2293 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2300 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2302 GList *bucket = element_bucket;
2303 mmplayer_gst_element_t *element = NULL;
2304 mmplayer_gst_element_t *prv_element = NULL;
2305 GstElement *tee_element = NULL;
2306 gint successful_link_count = 0;
2310 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2312 prv_element = (mmplayer_gst_element_t *)bucket->data;
2313 bucket = bucket->next;
2315 for (; bucket; bucket = bucket->next) {
2316 element = (mmplayer_gst_element_t *)bucket->data;
2318 if (element && element->gst) {
2319 if (prv_element && prv_element->gst) {
2320 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2322 prv_element->gst = tee_element;
2324 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2325 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2326 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2330 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2331 LOGD("linking [%s] to [%s] success",
2332 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2333 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2334 successful_link_count++;
2335 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2336 LOGD("keep audio-tee element for next audio pipeline branch");
2337 tee_element = prv_element->gst;
2340 LOGD("linking [%s] to [%s] failed",
2341 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2342 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2348 prv_element = element;
2353 return successful_link_count;
2357 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2359 GList *bucket = element_bucket;
2360 mmplayer_gst_element_t *element = NULL;
2361 int successful_add_count = 0;
2365 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2366 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2368 for (; bucket; bucket = bucket->next) {
2369 element = (mmplayer_gst_element_t *)bucket->data;
2371 if (element && element->gst) {
2372 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2373 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2374 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2375 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2378 successful_add_count++;
2384 return successful_add_count;
2388 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2390 mmplayer_t *player = (mmplayer_t *)data;
2391 GstCaps *caps = NULL;
2392 GstStructure *str = NULL;
2394 gboolean caps_ret = TRUE;
2398 MMPLAYER_RETURN_IF_FAIL(pad);
2399 MMPLAYER_RETURN_IF_FAIL(unused);
2400 MMPLAYER_RETURN_IF_FAIL(data);
2402 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2406 LOGD("name = %s", name);
2408 if (strstr(name, "audio")) {
2409 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2411 if (player->audio_stream_changed_cb) {
2412 LOGE("call the audio stream changed cb");
2413 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2415 } else if (strstr(name, "video")) {
2416 if ((name = gst_structure_get_string(str, "format")))
2417 player->set_mode.video_zc = name[0] == 'S';
2419 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2420 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2422 LOGW("invalid caps info");
2427 gst_caps_unref(caps);
2435 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2440 MMPLAYER_RETURN_IF_FAIL(player);
2442 if (player->audio_stream_buff_list) {
2443 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2444 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2447 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2448 __mmplayer_audio_stream_send_data(player, tmp);
2450 MMPLAYER_FREEIF(tmp->pcm_data);
2451 MMPLAYER_FREEIF(tmp);
2454 g_list_free(player->audio_stream_buff_list);
2455 player->audio_stream_buff_list = NULL;
2462 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2464 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2467 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2469 audio_stream.bitrate = a_buffer->bitrate;
2470 audio_stream.channel = a_buffer->channel;
2471 audio_stream.channel_mask = a_buffer->channel_mask;
2472 audio_stream.data_size = a_buffer->data_size;
2473 audio_stream.data = a_buffer->pcm_data;
2474 audio_stream.pcm_format = a_buffer->pcm_format;
2476 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2478 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2484 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2486 mmplayer_t *player = (mmplayer_t *)data;
2487 const gchar *pcm_format = NULL;
2490 guint64 channel_mask = 0;
2491 void *a_data = NULL;
2493 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2494 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2498 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2500 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2501 a_data = mapinfo.data;
2502 a_size = mapinfo.size;
2504 GstCaps *caps = gst_pad_get_current_caps(pad);
2505 GstStructure *structure = gst_caps_get_structure(caps, 0);
2507 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2509 pcm_format = gst_structure_get_string(structure, "format");
2510 gst_structure_get_int(structure, "rate", &rate);
2511 gst_structure_get_int(structure, "channels", &channel);
2512 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2513 gst_caps_unref(GST_CAPS(caps));
2515 /* In case of the sync is false, use buffer list. *
2516 * The num of buffer list depends on the num of audio channels */
2517 if (player->audio_stream_buff_list) {
2518 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2519 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2521 if (channel_mask == tmp->channel_mask) {
2523 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2525 if (tmp->data_size + a_size < tmp->buff_size) {
2526 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2527 tmp->data_size += a_size;
2529 /* send data to client */
2530 __mmplayer_audio_stream_send_data(player, tmp);
2532 if (a_size > tmp->buff_size) {
2533 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2534 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2535 if (tmp->pcm_data == NULL) {
2536 LOGE("failed to realloc data.");
2539 tmp->buff_size = a_size;
2541 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2542 memcpy(tmp->pcm_data, a_data, a_size);
2543 tmp->data_size = a_size;
2548 LOGE("data is empty in list.");
2554 /* create new audio stream data for newly found audio channel */
2555 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2556 if (a_buffer == NULL) {
2557 LOGE("failed to alloc data.");
2560 a_buffer->bitrate = rate;
2561 a_buffer->channel = channel;
2562 a_buffer->channel_mask = channel_mask;
2563 a_buffer->data_size = a_size;
2564 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2566 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2567 /* If sync is FALSE, use buffer list to reduce the IPC. */
2568 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2569 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2570 if (a_buffer->pcm_data == NULL) {
2571 LOGE("failed to alloc data.");
2572 MMPLAYER_FREEIF(a_buffer);
2575 memcpy(a_buffer->pcm_data, a_data, a_size);
2577 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2579 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2581 /* If sync is TRUE, send data directly. */
2582 a_buffer->pcm_data = a_data;
2583 __mmplayer_audio_stream_send_data(player, a_buffer);
2584 MMPLAYER_FREEIF(a_buffer);
2588 gst_buffer_unmap(buffer, &mapinfo);
2593 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2595 mmplayer_t *player = (mmplayer_t *)data;
2596 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2597 GstPad *sinkpad = NULL;
2598 GstElement *queue = NULL, *sink = NULL;
2601 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2603 queue = gst_element_factory_make("queue", NULL);
2604 if (queue == NULL) {
2605 LOGD("fail make queue");
2609 sink = gst_element_factory_make("fakesink", NULL);
2611 LOGD("fail make fakesink");
2615 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2617 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2618 LOGW("failed to link queue & sink");
2622 sinkpad = gst_element_get_static_pad(queue, "sink");
2624 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2625 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2629 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2631 gst_object_unref(sinkpad);
2632 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2633 g_object_set(sink, "sync", TRUE, NULL);
2634 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2636 /* keep the first sink reference only */
2637 if (!audiobin[MMPLAYER_A_SINK].gst) {
2638 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2639 audiobin[MMPLAYER_A_SINK].gst = sink;
2643 _mmplayer_add_signal_connection(player,
2645 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2647 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2650 __mmplayer_add_sink(player, sink, FALSE);
2652 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2653 LOGE("failed to sync state");
2657 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2658 LOGE("failed to sync state");
2666 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2668 gst_object_unref(GST_OBJECT(queue));
2672 gst_object_unref(GST_OBJECT(sink));
2676 gst_object_unref(GST_OBJECT(sinkpad));
2684 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2686 mmplayer_t *player = (mmplayer_t *)data;
2689 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2691 player->no_more_pad = TRUE;
2692 _mmplayer_pipeline_complete(NULL, player);
2699 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2701 #define MAX_PROPS_LEN 128
2702 mmplayer_gst_element_t *audiobin = NULL;
2703 gint latency_mode = 0;
2704 gchar *stream_type = NULL;
2705 gchar *latency = NULL;
2707 gchar stream_props[MAX_PROPS_LEN] = {0,};
2708 GstStructure *props = NULL;
2711 * It should be set after player creation through attribute.
2712 * But, it can not be changed during playing.
2715 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2717 audiobin = player->pipeline->audiobin;
2719 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2720 if (player->sound.mute) {
2721 LOGD("mute enabled");
2722 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2725 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2726 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2729 snprintf(stream_props, sizeof(stream_props) - 1,
2730 "props,application.process.id.origin=%d", player->client_pid);
2732 snprintf(stream_props, sizeof(stream_props) - 1,
2733 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2734 stream_type, stream_id, player->client_pid);
2736 props = gst_structure_from_string(stream_props, NULL);
2737 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2738 LOGI("props result[%s].", stream_props);
2739 gst_structure_free(props);
2741 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2743 switch (latency_mode) {
2744 case AUDIO_LATENCY_MODE_LOW:
2745 latency = g_strdup("low");
2747 case AUDIO_LATENCY_MODE_MID:
2748 latency = g_strdup("mid");
2750 case AUDIO_LATENCY_MODE_HIGH:
2751 latency = g_strdup("high");
2754 latency = g_strdup("mid");
2758 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2760 LOGD("audiosink property - latency=%s", latency);
2762 MMPLAYER_FREEIF(latency);
2768 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2770 mmplayer_gst_element_t *audiobin = NULL;
2773 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2774 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2776 audiobin = player->pipeline->audiobin;
2778 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2779 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2780 LOGE("failed to create media stream info");
2781 return MM_ERROR_PLAYER_INTERNAL;
2784 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2786 if (player->video360_yaw_radians <= M_PI &&
2787 player->video360_yaw_radians >= -M_PI &&
2788 player->video360_pitch_radians <= M_PI_2 &&
2789 player->video360_pitch_radians >= -M_PI_2) {
2790 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2791 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2792 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2793 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2794 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2795 "source-orientation-y", player->video360_metadata.init_view_heading,
2796 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2800 return MM_ERROR_NONE;
2804 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2806 mmplayer_gst_element_t *audiobin = NULL;
2807 GstPad *sink_pad = NULL;
2808 GstCaps *acaps = NULL;
2810 int pitch_control = 0;
2811 double pitch_value = 1.0;
2814 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2815 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2817 audiobin = player->pipeline->audiobin;
2819 LOGD("make element for normal audio playback");
2821 /* audio bin structure for playback. {} means optional.
2822 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2824 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2825 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2828 /* for pitch control */
2829 mm_attrs_multiple_get(player->attrs, NULL,
2830 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2831 MM_PLAYER_PITCH_VALUE, &pitch_value,
2834 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2835 if (pitch_control && (player->videodec_linked == 0)) {
2836 GstElementFactory *factory;
2838 factory = gst_element_factory_find("pitch");
2840 gst_object_unref(factory);
2843 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2846 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2847 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2849 LOGW("there is no pitch element");
2854 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2856 /* replaygain volume */
2857 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2858 if (player->sound.rg_enable)
2859 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2861 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2864 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2866 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2867 /* currently, only openalsink uses volume element */
2868 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2869 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2871 if (player->sound.mute) {
2872 LOGD("mute enabled");
2873 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2877 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2879 /* audio effect element. if audio effect is enabled */
2880 if ((strcmp(player->ini.audioeffect_element, ""))
2882 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2883 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2885 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2887 if ((!player->bypass_audio_effect)
2888 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2889 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2890 if (!_mmplayer_audio_effect_custom_apply(player))
2891 LOGI("apply audio effect(custom) setting success");
2895 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2896 && (player->set_mode.rich_audio)) {
2897 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2901 /* create audio sink */
2902 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2903 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2904 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2906 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2907 if (player->is_360_feature_enabled &&
2908 player->is_content_spherical &&
2910 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2911 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2912 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2914 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2916 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2918 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2919 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2920 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2921 gst_caps_unref(acaps);
2923 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2925 player->is_openal_plugin_used = TRUE;
2927 if (player->is_360_feature_enabled && player->is_content_spherical)
2928 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2929 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2932 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2933 (player->videodec_linked && player->ini.use_system_clock)) {
2934 LOGD("system clock will be used.");
2935 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2938 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2939 __mmplayer_gst_set_pulsesink_property(player);
2940 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2941 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2946 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2947 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2949 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2950 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2951 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2952 gst_object_unref(GST_OBJECT(sink_pad));
2954 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2957 return MM_ERROR_NONE;
2959 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2961 return MM_ERROR_PLAYER_INTERNAL;
2965 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2967 mmplayer_gst_element_t *audiobin = NULL;
2968 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2970 gchar *dst_format = NULL;
2972 int dst_samplerate = 0;
2973 int dst_channels = 0;
2974 GstCaps *caps = NULL;
2975 char *caps_str = NULL;
2978 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2979 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2981 audiobin = player->pipeline->audiobin;
2983 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2985 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2987 [case 1] extract interleave audio pcm without playback
2988 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2989 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2991 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2993 [case 2] deinterleave for each channel without playback
2994 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2995 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2997 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2998 - fakesink (sync or not)
3001 [case 3] [case 1(sync only)] + playback
3002 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
3004 * src - ... - tee - queue1 - playback path
3005 - queue2 - [case1 pipeline with sync]
3007 [case 4] [case 2(sync only)] + playback
3008 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3010 * src - ... - tee - queue1 - playback path
3011 - queue2 - [case2 pipeline with sync]
3015 /* 1. create tee and playback path
3016 'tee' should be added at first to copy the decoded stream
3018 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3019 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3020 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3022 /* tee - path 1 : for playback path */
3023 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3024 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3026 /* tee - path 2 : for extract path */
3027 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3028 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3031 /* if there is tee, 'tee - path 2' is linked here */
3033 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3036 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3038 /* 2. decide the extract pcm format */
3039 mm_attrs_multiple_get(player->attrs, NULL,
3040 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3041 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3042 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3045 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3046 dst_format, dst_len, dst_samplerate, dst_channels);
3048 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3049 mm_attrs_multiple_get(player->attrs, NULL,
3050 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3051 "content_audio_samplerate", &dst_samplerate,
3052 "content_audio_channels", &dst_channels,
3055 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3056 dst_format, dst_len, dst_samplerate, dst_channels);
3058 /* If there is no enough information, set it to platform default value. */
3059 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3060 LOGD("set platform default format");
3061 dst_format = DEFAULT_PCM_OUT_FORMAT;
3063 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3064 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3067 /* 3. create capsfilter */
3068 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3069 caps = gst_caps_new_simple("audio/x-raw",
3070 "format", G_TYPE_STRING, dst_format,
3071 "rate", G_TYPE_INT, dst_samplerate,
3072 "channels", G_TYPE_INT, dst_channels,
3075 caps_str = gst_caps_to_string(caps);
3076 LOGD("new caps : %s", caps_str);
3078 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3081 gst_caps_unref(caps);
3082 MMPLAYER_FREEIF(caps_str);
3084 /* 4-1. create deinterleave to extract pcm for each channel */
3085 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3086 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3087 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3089 /* audiosink will be added after getting signal for each channel */
3090 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3091 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3092 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3093 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3094 player->no_more_pad = FALSE;
3096 /* 4-2. create fakesink to extract interleaved pcm */
3097 LOGD("add audio fakesink for interleaved audio");
3098 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3099 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3100 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3101 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3103 _mmplayer_add_signal_connection(player,
3104 G_OBJECT(audiobin[extract_sink_id].gst),
3105 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3107 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3110 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3114 return MM_ERROR_NONE;
3116 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3118 return MM_ERROR_PLAYER_INTERNAL;
3122 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3124 int ret = MM_ERROR_NONE;
3125 mmplayer_gst_element_t *audiobin = NULL;
3126 GList *element_bucket = NULL;
3129 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3130 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3132 audiobin = player->pipeline->audiobin;
3134 if (player->build_audio_offload) { /* skip all the audio filters */
3135 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3137 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3138 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3139 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3141 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3145 /* FIXME: need to mention the supportable condition at API reference */
3146 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3147 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3149 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3151 if (ret != MM_ERROR_NONE)
3154 LOGD("success to make audio bin element");
3155 *bucket = element_bucket;
3158 return MM_ERROR_NONE;
3161 LOGE("failed to make audio bin element");
3162 g_list_free(element_bucket);
3166 return MM_ERROR_PLAYER_INTERNAL;
3170 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3172 mmplayer_gst_element_t *first_element = NULL;
3173 mmplayer_gst_element_t *audiobin = NULL;
3175 GstPad *ghostpad = NULL;
3176 GList *element_bucket = NULL;
3180 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3183 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3185 LOGE("failed to allocate memory for audiobin");
3186 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3190 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3191 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3192 if (!audiobin[MMPLAYER_A_BIN].gst) {
3193 LOGE("failed to create audiobin");
3198 player->pipeline->audiobin = audiobin;
3200 /* create audio filters and audiosink */
3201 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3204 /* adding created elements to bin */
3205 LOGD("adding created elements to bin");
3206 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3209 /* linking elements in the bucket by added order. */
3210 LOGD("Linking elements in the bucket by added order.");
3211 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3214 /* get first element's sinkpad for creating ghostpad */
3215 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3216 if (!first_element) {
3217 LOGE("failed to get first elem");
3221 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3223 LOGE("failed to get pad from first element of audiobin");
3227 ghostpad = gst_ghost_pad_new("sink", pad);
3229 LOGE("failed to create ghostpad");
3233 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3234 LOGE("failed to add ghostpad to audiobin");
3238 gst_object_unref(pad);
3240 g_list_free(element_bucket);
3243 return MM_ERROR_NONE;
3246 LOGD("ERROR : releasing audiobin");
3249 gst_object_unref(GST_OBJECT(pad));
3252 gst_object_unref(GST_OBJECT(ghostpad));
3255 g_list_free(element_bucket);
3257 /* release element which are not added to bin */
3258 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3259 /* NOTE : skip bin */
3260 if (audiobin[i].gst) {
3261 GstObject *parent = NULL;
3262 parent = gst_element_get_parent(audiobin[i].gst);
3265 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3266 audiobin[i].gst = NULL;
3268 gst_object_unref(GST_OBJECT(parent));
3272 /* release audiobin with it's children */
3273 if (audiobin[MMPLAYER_A_BIN].gst)
3274 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3276 MMPLAYER_FREEIF(audiobin);
3278 player->pipeline->audiobin = NULL;
3280 return MM_ERROR_PLAYER_INTERNAL;
3284 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3286 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3290 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3292 int ret = MM_ERROR_NONE;
3294 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3295 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3297 MMPLAYER_VIDEO_BO_LOCK(player);
3299 if (player->video_bo_list) {
3300 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3301 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3302 if (tmp && tmp->bo == bo) {
3304 LOGD("release bo %p", bo);
3305 tbm_bo_unref(tmp->bo);
3306 MMPLAYER_VIDEO_BO_UNLOCK(player);
3307 MMPLAYER_VIDEO_BO_SIGNAL(player);
3312 /* hw codec is running or the list was reset for DRC. */
3313 LOGW("there is no bo list.");
3315 MMPLAYER_VIDEO_BO_UNLOCK(player);
3317 LOGW("failed to find bo %p", bo);
3321 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3327 tbm_bo_unref(tmp->bo);
3332 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3335 MMPLAYER_RETURN_IF_FAIL(player);
3337 MMPLAYER_VIDEO_BO_LOCK(player);
3338 if (player->video_bo_list) {
3339 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3340 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3341 player->video_bo_list = NULL;
3343 player->video_bo_size = 0;
3344 MMPLAYER_VIDEO_BO_UNLOCK(player);
3351 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3354 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3355 gboolean ret = TRUE;
3356 gint64 end_time = 0;
3358 /* check DRC, if it is, destroy the prev bo list to create again */
3359 if (player->video_bo_size != size) {
3360 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3361 __mmplayer_video_stream_destroy_bo_list(player);
3362 player->video_bo_size = size;
3365 MMPLAYER_VIDEO_BO_LOCK(player);
3367 if ((!player->video_bo_list) ||
3368 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3370 /* create bo list */
3372 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3374 if (player->video_bo_list) {
3375 /* if bo list did not created all, try it again. */
3376 idx = g_list_length(player->video_bo_list);
3377 LOGD("bo list exist(len: %d)", idx);
3380 for (; idx < player->ini.num_of_video_bo; idx++) {
3381 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3383 LOGE("Fail to alloc bo_info.");
3386 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3388 LOGE("Fail to tbm_bo_alloc.");
3389 MMPLAYER_FREEIF(bo_info);
3392 bo_info->used = FALSE;
3393 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3396 /* update video num buffers */
3397 LOGD("video_num_buffers : %d", idx);
3398 mm_player_set_attribute((MMHandleType)player, NULL,
3399 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3400 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3404 MMPLAYER_VIDEO_BO_UNLOCK(player);
3409 if (player->ini.video_bo_timeout > 0)
3410 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3413 /* get bo from list*/
3414 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3415 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3416 if (tmp && (tmp->used == FALSE)) {
3417 LOGD("found bo %p to use", tmp->bo);
3419 MMPLAYER_VIDEO_BO_UNLOCK(player);
3420 return tbm_bo_ref(tmp->bo);
3424 if (player->ini.video_bo_timeout <= 0) {
3425 MMPLAYER_VIDEO_BO_WAIT(player);
3427 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3429 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3435 MMPLAYER_VIDEO_BO_UNLOCK(player);
3440 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3442 mmplayer_t *player = (mmplayer_t *)data;
3444 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3446 /* send prerolled pkt */
3447 player->video_stream_prerolled = false;
3449 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3451 /* not to send prerolled pkt again */
3452 player->video_stream_prerolled = true;
3456 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3458 mmplayer_t *player = (mmplayer_t *)data;
3459 mmplayer_video_decoded_data_info_t *stream = NULL;
3460 GstMemory *mem = NULL;
3463 MMPLAYER_RETURN_IF_FAIL(player);
3464 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3466 if (player->video_stream_prerolled) {
3467 player->video_stream_prerolled = false;
3468 LOGD("skip the prerolled pkt not to send it again");
3472 /* clear stream data structure */
3473 stream = __mmplayer_create_stream_from_pad(pad);
3475 LOGE("failed to alloc stream");
3479 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3481 /* set size and timestamp */
3482 mem = gst_buffer_peek_memory(buffer, 0);
3483 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3484 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3486 /* check zero-copy */
3487 if (player->set_mode.video_zc &&
3488 player->set_mode.video_export &&
3489 gst_is_tizen_memory(mem)) {
3490 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3491 stream->internal_buffer = gst_buffer_ref(buffer);
3492 } else { /* sw codec */
3493 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3496 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3500 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3501 LOGE("failed to send video decoded data.");
3508 LOGE("release video stream resource.");
3509 if (gst_is_tizen_memory(mem)) {
3511 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3513 tbm_bo_unref(stream->bo[i]);
3516 /* unref gst buffer */
3517 if (stream->internal_buffer)
3518 gst_buffer_unref(stream->internal_buffer);
3521 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3523 MMPLAYER_FREEIF(stream);
3528 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3530 mmplayer_gst_element_t *videobin = NULL;
3533 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3535 videobin = player->pipeline->videobin;
3537 /* Set spatial media metadata and/or user settings to the element.
3539 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3540 "projection-type", player->video360_metadata.projection_type, NULL);
3542 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3543 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3545 if (player->video360_metadata.full_pano_width_pixels &&
3546 player->video360_metadata.full_pano_height_pixels &&
3547 player->video360_metadata.cropped_area_image_width &&
3548 player->video360_metadata.cropped_area_image_height) {
3549 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3550 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3551 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3552 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3553 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3554 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3555 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3559 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3560 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3561 "horizontal-fov", player->video360_horizontal_fov,
3562 "vertical-fov", player->video360_vertical_fov, NULL);
3565 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3566 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3567 "zoom", 1.0f / player->video360_zoom, NULL);
3570 if (player->video360_yaw_radians <= M_PI &&
3571 player->video360_yaw_radians >= -M_PI &&
3572 player->video360_pitch_radians <= M_PI_2 &&
3573 player->video360_pitch_radians >= -M_PI_2) {
3574 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3575 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3576 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3577 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3578 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3579 "pose-yaw", player->video360_metadata.init_view_heading,
3580 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3583 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3584 "passthrough", !player->is_video360_enabled, NULL);
3591 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3593 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3594 GList *element_bucket = NULL;
3597 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3599 /* create video360 filter */
3600 if (player->is_360_feature_enabled && player->is_content_spherical) {
3601 LOGD("create video360 element");
3602 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3603 __mmplayer_gst_set_video360_property(player);
3607 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3608 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3609 player->set_mode.video_zc) {
3610 LOGD("skip creating the videoconv and rotator");
3611 return MM_ERROR_NONE;
3614 /* in case of sw codec & overlay surface type, except 360 playback.
3615 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3616 LOGD("create video converter: %s", video_csc);
3617 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3620 *bucket = element_bucket;
3622 return MM_ERROR_NONE;
3624 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3625 g_list_free(element_bucket);
3629 return MM_ERROR_PLAYER_INTERNAL;
3633 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3635 gchar *factory_name = NULL;
3637 switch (surface_type) {
3638 case MM_DISPLAY_SURFACE_OVERLAY:
3640 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3641 if (strlen(player->ini.videosink_element_overlay) > 0)
3642 factory_name = player->ini.videosink_element_overlay;
3644 case MM_DISPLAY_SURFACE_REMOTE:
3646 case MM_DISPLAY_SURFACE_NULL:
3647 if (strlen(player->ini.videosink_element_fake) > 0)
3648 factory_name = player->ini.videosink_element_fake;
3651 LOGE("unidentified surface type");
3655 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3656 return factory_name;
3660 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3662 gchar *factory_name = NULL;
3663 mmplayer_gst_element_t *videobin = NULL;
3668 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3670 videobin = player->pipeline->videobin;
3671 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3673 attrs = MMPLAYER_GET_ATTRS(player);
3675 LOGE("cannot get content attribute");
3676 return MM_ERROR_PLAYER_INTERNAL;
3679 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3680 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3681 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3682 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3683 "use-tbm", use_tbm, NULL);
3686 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3687 return MM_ERROR_PLAYER_INTERNAL;
3689 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3692 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3693 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3696 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3698 LOGD("disable last-sample");
3699 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3702 if (player->set_mode.video_export) {
3704 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3705 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3706 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3708 _mmplayer_add_signal_connection(player,
3709 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3710 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3712 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3715 _mmplayer_add_signal_connection(player,
3716 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3717 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3719 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3723 if (videobin[MMPLAYER_V_SINK].gst) {
3724 GstPad *sink_pad = NULL;
3725 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3727 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3728 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3729 gst_object_unref(GST_OBJECT(sink_pad));
3731 LOGE("failed to get sink pad from videosink");
3735 return MM_ERROR_NONE;
3740 * - video overlay surface(arm/x86) : tizenwlsink
3743 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3746 GList *element_bucket = NULL;
3747 mmplayer_gst_element_t *first_element = NULL;
3748 mmplayer_gst_element_t *videobin = NULL;
3749 gchar *videosink_factory_name = NULL;
3752 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3755 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3757 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3759 player->pipeline->videobin = videobin;
3762 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3763 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3764 if (!videobin[MMPLAYER_V_BIN].gst) {
3765 LOGE("failed to create videobin");
3769 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3772 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3773 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3775 /* additional setting for sink plug-in */
3776 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3777 LOGE("failed to set video property");
3781 /* store it as it's sink element */
3782 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3784 /* adding created elements to bin */
3785 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3786 LOGE("failed to add elements");
3790 /* Linking elements in the bucket by added order */
3791 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3792 LOGE("failed to link elements");
3796 /* get first element's sinkpad for creating ghostpad */
3797 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3798 if (!first_element) {
3799 LOGE("failed to get first element from bucket");
3803 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3805 LOGE("failed to get pad from first element");
3809 /* create ghostpad */
3810 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3811 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3812 LOGE("failed to add ghostpad to videobin");
3815 gst_object_unref(pad);
3817 /* done. free allocated variables */
3818 g_list_free(element_bucket);
3822 return MM_ERROR_NONE;
3825 LOGE("ERROR : releasing videobin");
3826 g_list_free(element_bucket);
3829 gst_object_unref(GST_OBJECT(pad));
3831 /* release videobin with it's children */
3832 if (videobin[MMPLAYER_V_BIN].gst)
3833 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3835 MMPLAYER_FREEIF(videobin);
3836 player->pipeline->videobin = NULL;
3838 return MM_ERROR_PLAYER_INTERNAL;
3842 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3844 GList *element_bucket = NULL;
3845 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3847 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3848 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3849 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3850 "signal-handoffs", FALSE,
3853 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3854 _mmplayer_add_signal_connection(player,
3855 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3856 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3858 G_CALLBACK(__mmplayer_update_subtitle),
3861 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3862 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3864 if (!player->play_subtitle) {
3865 LOGD("add textbin sink as sink element of whole pipeline.");
3866 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3869 /* adding created elements to bin */
3870 LOGD("adding created elements to bin");
3871 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3872 LOGE("failed to add elements");
3876 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3877 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3878 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3880 /* linking elements in the bucket by added order. */
3881 LOGD("Linking elements in the bucket by added order.");
3882 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3883 LOGE("failed to link elements");
3887 if (textbin[MMPLAYER_T_QUEUE].gst) {
3889 GstPad *ghostpad = NULL;
3891 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3893 LOGE("failed to get sink pad of text queue");
3897 ghostpad = gst_ghost_pad_new("text_sink", pad);
3898 gst_object_unref(pad);
3901 LOGE("failed to create ghostpad of textbin");
3905 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3906 LOGE("failed to add ghostpad to textbin");
3907 gst_object_unref(ghostpad);
3912 g_list_free(element_bucket);
3914 return MM_ERROR_NONE;
3918 g_list_free(element_bucket);
3920 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3921 LOGE("remove textbin sink from sink list");
3922 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3925 /* release element at __mmplayer_gst_create_text_sink_bin */
3926 return MM_ERROR_PLAYER_INTERNAL;
3930 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3932 mmplayer_gst_element_t *textbin = NULL;
3933 int surface_type = 0;
3938 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3941 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3943 LOGE("failed to allocate memory for textbin");
3944 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3948 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3949 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3950 if (!textbin[MMPLAYER_T_BIN].gst) {
3951 LOGE("failed to create textbin");
3956 player->pipeline->textbin = textbin;
3959 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3960 LOGD("surface type for subtitle : %d", surface_type);
3961 switch (surface_type) {
3962 case MM_DISPLAY_SURFACE_OVERLAY:
3963 case MM_DISPLAY_SURFACE_NULL:
3964 case MM_DISPLAY_SURFACE_REMOTE:
3965 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3966 LOGE("failed to make plain text elements");
3977 return MM_ERROR_NONE;
3981 LOGD("ERROR : releasing textbin");
3983 /* release signal */
3984 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3986 /* release element which are not added to bin */
3987 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3988 /* NOTE : skip bin */
3989 if (textbin[i].gst) {
3990 GstObject *parent = NULL;
3991 parent = gst_element_get_parent(textbin[i].gst);
3994 gst_object_unref(GST_OBJECT(textbin[i].gst));
3995 textbin[i].gst = NULL;
3997 gst_object_unref(GST_OBJECT(parent));
4002 /* release textbin with it's children */
4003 if (textbin[MMPLAYER_T_BIN].gst)
4004 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4006 MMPLAYER_FREEIF(textbin);
4007 player->pipeline->textbin = NULL;
4010 return MM_ERROR_PLAYER_INTERNAL;
4014 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4016 mmplayer_gst_element_t *mainbin = NULL;
4017 mmplayer_gst_element_t *textbin = NULL;
4018 MMHandleType attrs = 0;
4019 GstElement *subsrc = NULL;
4020 GstElement *subparse = NULL;
4021 gchar *subtitle_uri = NULL;
4022 const gchar *charset = NULL;
4028 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4030 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4032 mainbin = player->pipeline->mainbin;
4034 attrs = MMPLAYER_GET_ATTRS(player);
4036 LOGE("cannot get content attribute");
4037 return MM_ERROR_PLAYER_INTERNAL;
4040 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4041 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4042 LOGE("subtitle uri is not proper filepath.");
4043 return MM_ERROR_PLAYER_INVALID_URI;
4046 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4047 LOGE("failed to get storage info of subtitle path");
4048 return MM_ERROR_PLAYER_INVALID_URI;
4051 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4053 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4054 player->subtitle_language_list = NULL;
4055 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4057 /* create the subtitle source */
4058 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4060 LOGE("failed to create filesrc element");
4063 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4065 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4066 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4068 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4069 LOGW("failed to add queue");
4070 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4071 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4072 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4077 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4079 LOGE("failed to create subparse element");
4083 charset = _mmplayer_get_charset(subtitle_uri);
4085 LOGD("detected charset is %s", charset);
4086 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4089 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4090 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4092 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4093 LOGW("failed to add subparse");
4094 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4095 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4096 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4100 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4101 LOGW("failed to link subsrc and subparse");
4105 player->play_subtitle = TRUE;
4106 player->adjust_subtitle_pos = 0;
4108 LOGD("play subtitle using subtitle file");
4110 if (player->pipeline->textbin == NULL) {
4111 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4112 LOGE("failed to create text sink bin. continuing without text");
4116 textbin = player->pipeline->textbin;
4118 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4119 LOGW("failed to add textbin");
4121 /* release signal */
4122 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4124 /* release textbin with it's children */
4125 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4126 MMPLAYER_FREEIF(player->pipeline->textbin);
4127 player->pipeline->textbin = textbin = NULL;
4131 LOGD("link text input selector and textbin ghost pad");
4133 player->textsink_linked = 1;
4134 player->external_text_idx = 0;
4135 LOGI("textsink is linked");
4137 textbin = player->pipeline->textbin;
4138 LOGD("text bin has been created. reuse it.");
4139 player->external_text_idx = 1;
4142 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4143 LOGW("failed to link subparse and textbin");
4147 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4149 LOGE("failed to get sink pad from textsink to probe data");
4153 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4154 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4156 gst_object_unref(pad);
4159 /* create dot. for debugging */
4160 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4163 return MM_ERROR_NONE;
4166 /* release text pipeline resource */
4167 player->textsink_linked = 0;
4169 /* release signal */
4170 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4172 if (player->pipeline->textbin) {
4173 LOGE("remove textbin");
4175 /* release textbin with it's children */
4176 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4177 MMPLAYER_FREEIF(player->pipeline->textbin);
4178 player->pipeline->textbin = NULL;
4182 /* release subtitle elem */
4183 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4184 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4186 return MM_ERROR_PLAYER_INTERNAL;
4190 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4192 mmplayer_t *player = (mmplayer_t *)data;
4193 MMMessageParamType msg = {0, };
4194 GstClockTime duration = 0;
4195 gpointer text = NULL;
4196 guint text_size = 0;
4197 gboolean ret = TRUE;
4198 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4202 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4203 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4205 if (player->is_subtitle_force_drop) {
4206 LOGW("subtitle is dropped forcedly.");
4210 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4211 text = mapinfo.data;
4212 text_size = mapinfo.size;
4214 if (player->set_mode.subtitle_off) {
4215 LOGD("subtitle is OFF.");
4219 if (!text || (text_size == 0)) {
4220 LOGD("There is no subtitle to be displayed.");
4224 msg.data = (void *)text;
4226 duration = GST_BUFFER_DURATION(buffer);
4228 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4229 if (player->duration > GST_BUFFER_PTS(buffer))
4230 duration = player->duration - GST_BUFFER_PTS(buffer);
4233 LOGI("subtitle duration is invalid, subtitle duration change "
4234 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4236 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4238 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4240 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4241 gst_buffer_unmap(buffer, &mapinfo);
4248 static GstPadProbeReturn
4249 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4251 mmplayer_t *player = (mmplayer_t *)u_data;
4252 GstClockTime cur_timestamp = 0;
4253 gint64 adjusted_timestamp = 0;
4254 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4256 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4258 if (player->set_mode.subtitle_off) {
4259 LOGD("subtitle is OFF.");
4263 if (player->adjust_subtitle_pos == 0) {
4264 LOGD("nothing to do");
4268 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4269 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4271 if (adjusted_timestamp < 0) {
4272 LOGD("adjusted_timestamp under zero");
4277 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4278 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4279 GST_TIME_ARGS(cur_timestamp),
4280 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4282 return GST_PAD_PROBE_OK;
4286 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4290 /* check player and subtitlebin are created */
4291 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4292 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4294 if (position == 0) {
4295 LOGD("nothing to do");
4297 return MM_ERROR_NONE;
4300 /* check current position */
4301 player->adjust_subtitle_pos = position;
4303 LOGD("save adjust_subtitle_pos in player");
4307 return MM_ERROR_NONE;
4311 * This function is to create audio or video pipeline for playing.
4313 * @param player [in] handle of player
4315 * @return This function returns zero on success.
4320 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4322 int ret = MM_ERROR_NONE;
4323 mmplayer_gst_element_t *mainbin = NULL;
4324 MMHandleType attrs = 0;
4327 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4329 /* get profile attribute */
4330 attrs = MMPLAYER_GET_ATTRS(player);
4332 LOGE("failed to get content attribute");
4336 /* create pipeline handles */
4337 if (player->pipeline) {
4338 LOGE("pipeline should be released before create new one");
4342 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4344 /* create mainbin */
4345 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4346 if (mainbin == NULL)
4349 /* create pipeline */
4350 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4351 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4352 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4353 LOGE("failed to create pipeline");
4358 player->pipeline->mainbin = mainbin;
4360 /* create the source and decoder elements */
4361 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4362 ret = _mmplayer_gst_build_es_pipeline(player);
4364 if (MMPLAYER_USE_DECODEBIN(player))
4365 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4367 ret = _mmplayer_gst_build_pipeline_with_src(player);
4370 if (ret != MM_ERROR_NONE) {
4371 LOGE("failed to create some elements");
4375 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4376 if (__mmplayer_check_subtitle(player)
4377 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4378 LOGE("failed to create text pipeline");
4381 ret = _mmplayer_gst_add_bus_watch(player);
4382 if (ret != MM_ERROR_NONE) {
4383 LOGE("failed to add bus watch");
4388 return MM_ERROR_NONE;
4391 _mmplayer_bus_watcher_remove(player);
4392 __mmplayer_gst_destroy_pipeline(player);
4393 return MM_ERROR_PLAYER_INTERNAL;
4397 __mmplayer_reset_gapless_state(mmplayer_t *player)
4400 MMPLAYER_RETURN_IF_FAIL(player
4402 && player->pipeline->audiobin
4403 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4405 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4412 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4415 int ret = MM_ERROR_NONE;
4419 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4421 /* cleanup stuffs */
4422 MMPLAYER_FREEIF(player->type);
4423 player->no_more_pad = FALSE;
4424 player->num_dynamic_pad = 0;
4426 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4427 player->subtitle_language_list = NULL;
4428 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4430 MMPLAYER_RECONFIGURE_LOCK(player);
4431 __mmplayer_reset_gapless_state(player);
4432 MMPLAYER_RECONFIGURE_UNLOCK(player);
4434 if (player->streamer) {
4435 _mm_player_streaming_initialize(player->streamer, FALSE);
4436 _mm_player_streaming_destroy(player->streamer);
4437 player->streamer = NULL;
4440 /* cleanup unlinked mime type */
4441 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4442 MMPLAYER_FREEIF(player->unlinked_video_mime);
4443 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4445 /* cleanup running stuffs */
4446 _mmplayer_cancel_eos_timer(player);
4448 /* cleanup gst stuffs */
4449 if (player->pipeline) {
4450 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4451 GstTagList *tag_list = player->pipeline->tag_list;
4453 /* first we need to disconnect all signal hander */
4454 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4457 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4458 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4459 gst_object_unref(bus);
4461 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4462 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4463 if (ret != MM_ERROR_NONE) {
4464 LOGE("fail to change state to NULL");
4465 return MM_ERROR_PLAYER_INTERNAL;
4468 LOGW("succeeded in changing state to NULL");
4470 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4473 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4474 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4476 MMPLAYER_FREEIF(player->pipeline->audiobin);
4477 MMPLAYER_FREEIF(player->pipeline->videobin);
4478 MMPLAYER_FREEIF(player->pipeline->textbin);
4479 MMPLAYER_FREEIF(mainbin);
4483 gst_tag_list_unref(tag_list);
4485 MMPLAYER_FREEIF(player->pipeline);
4487 MMPLAYER_FREEIF(player->album_art);
4489 if (player->type_caps) {
4490 gst_caps_unref(player->type_caps);
4491 player->type_caps = NULL;
4494 if (player->v_stream_caps) {
4495 gst_caps_unref(player->v_stream_caps);
4496 player->v_stream_caps = NULL;
4499 if (player->a_stream_caps) {
4500 gst_caps_unref(player->a_stream_caps);
4501 player->a_stream_caps = NULL;
4504 if (player->s_stream_caps) {
4505 gst_caps_unref(player->s_stream_caps);
4506 player->s_stream_caps = NULL;
4508 _mmplayer_track_destroy(player);
4510 if (player->sink_elements)
4511 g_list_free(player->sink_elements);
4512 player->sink_elements = NULL;
4514 if (player->bufmgr) {
4515 tbm_bufmgr_deinit(player->bufmgr);
4516 player->bufmgr = NULL;
4519 LOGW("finished destroy pipeline");
4527 __mmplayer_gst_realize(mmplayer_t *player)
4530 int ret = MM_ERROR_NONE;
4534 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4536 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4538 ret = __mmplayer_gst_create_pipeline(player);
4540 LOGE("failed to create pipeline");
4544 /* set pipeline state to READY */
4545 /* NOTE : state change to READY must be performed sync. */
4546 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4547 ret = _mmplayer_gst_set_state(player,
4548 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4550 if (ret != MM_ERROR_NONE) {
4551 /* return error if failed to set state */
4552 LOGE("failed to set READY state");
4556 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4558 /* create dot before error-return. for debugging */
4559 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4567 __mmplayer_gst_unrealize(mmplayer_t *player)
4569 int ret = MM_ERROR_NONE;
4573 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4575 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4576 MMPLAYER_PRINT_STATE(player);
4578 /* release miscellaneous information */
4579 __mmplayer_release_misc(player);
4581 /* destroy pipeline */
4582 ret = __mmplayer_gst_destroy_pipeline(player);
4583 if (ret != MM_ERROR_NONE) {
4584 LOGE("failed to destroy pipeline");
4588 /* release miscellaneous information.
4589 these info needs to be released after pipeline is destroyed. */
4590 __mmplayer_release_misc_post(player);
4592 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4600 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4605 LOGW("set_message_callback is called with invalid player handle");
4606 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4609 player->msg_cb = callback;
4610 player->msg_cb_param = user_param;
4612 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4616 return MM_ERROR_NONE;
4620 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4622 int ret = MM_ERROR_NONE;
4627 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4628 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4629 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4631 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4633 if (strstr(uri, "es_buff://")) {
4634 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4635 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4636 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4637 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4639 tmp = g_ascii_strdown(uri, strlen(uri));
4640 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4641 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4643 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4645 } else if (strstr(uri, "mms://")) {
4646 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4647 } else if ((path = strstr(uri, "mem://"))) {
4648 ret = __mmplayer_set_mem_uri(data, path, param);
4650 ret = __mmplayer_set_file_uri(data, uri);
4653 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4654 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4655 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4656 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4658 /* dump parse result */
4659 SECURE_LOGW("incoming uri : %s", uri);
4660 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4661 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4669 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4672 mmplayer_t *player = NULL;
4673 MMMessageParamType msg = {0, };
4675 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4680 LOGE("user_data is null");
4684 player = (mmplayer_t *)user_data;
4686 if (!player->pipeline || !player->attrs) {
4687 LOGW("not initialized");
4691 LOGD("cmd lock player, cmd state : %d", player->cmd);
4692 MMPLAYER_CMD_LOCK(player);
4693 LOGD("cmd locked player");
4695 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4696 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4697 LOGW("player already destroyed");
4698 MMPLAYER_CMD_UNLOCK(player);
4702 player->interrupted_by_resource = TRUE;
4704 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4706 /* get last play position */
4707 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4708 msg.union_type = MM_MSG_UNION_TIME;
4709 msg.time.elapsed = pos;
4710 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4712 LOGW("failed to get play position.");
4715 LOGD("video resource conflict so, resource will be freed by unrealizing");
4716 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4717 LOGE("failed to unrealize");
4719 MMPLAYER_CMD_UNLOCK(player);
4721 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4722 player->hw_resource[res_idx] = NULL;
4726 return TRUE; /* release all the resources */
4730 __mmplayer_initialize_video_roi(mmplayer_t *player)
4732 player->video_roi.scale_x = 0.0;
4733 player->video_roi.scale_y = 0.0;
4734 player->video_roi.scale_width = 1.0;
4735 player->video_roi.scale_height = 1.0;
4739 _mmplayer_create_player(MMHandleType handle)
4741 int ret = MM_ERROR_PLAYER_INTERNAL;
4742 bool enabled = false;
4744 mmplayer_t *player = MM_PLAYER_CAST(handle);
4748 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4750 /* initialize player state */
4751 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4752 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4753 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4754 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4756 /* check current state */
4757 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4759 /* construct attributes */
4760 player->attrs = _mmplayer_construct_attribute(handle);
4762 if (!player->attrs) {
4763 LOGE("Failed to construct attributes");
4767 /* initialize gstreamer with configured parameter */
4768 if (!__mmplayer_init_gstreamer(player)) {
4769 LOGE("Initializing gstreamer failed");
4770 _mmplayer_deconstruct_attribute(handle);
4774 /* create lock. note that g_tread_init() has already called in gst_init() */
4775 g_mutex_init(&player->fsink_lock);
4777 /* create update tag lock */
4778 g_mutex_init(&player->update_tag_lock);
4780 /* create gapless play mutex */
4781 g_mutex_init(&player->gapless_play_thread_mutex);
4783 /* create gapless play cond */
4784 g_cond_init(&player->gapless_play_thread_cond);
4786 /* create gapless play thread */
4787 player->gapless_play_thread =
4788 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4789 if (!player->gapless_play_thread) {
4790 LOGE("failed to create gapless play thread");
4791 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4792 g_mutex_clear(&player->gapless_play_thread_mutex);
4793 g_cond_clear(&player->gapless_play_thread_cond);
4797 player->bus_msg_q = g_queue_new();
4798 if (!player->bus_msg_q) {
4799 LOGE("failed to create queue for bus_msg");
4800 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4804 ret = _mmplayer_initialize_video_capture(player);
4805 if (ret != MM_ERROR_NONE) {
4806 LOGW("video capture is not supported");
4807 /* do not handle as error for headless profile */
4810 /* initialize resource manager */
4811 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4812 __resource_release_cb, player, &player->resource_manager)
4813 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4814 LOGE("failed to create resource manager");
4815 ret = MM_ERROR_PLAYER_INTERNAL;
4819 /* create video bo lock and cond */
4820 g_mutex_init(&player->video_bo_mutex);
4821 g_cond_init(&player->video_bo_cond);
4823 /* create subtitle info lock and cond */
4824 g_mutex_init(&player->subtitle_info_mutex);
4825 g_cond_init(&player->subtitle_info_cond);
4827 player->streaming_type = STREAMING_SERVICE_NONE;
4829 /* give default value of audio effect setting */
4830 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4831 player->sound.rg_enable = false;
4832 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4834 player->play_subtitle = FALSE;
4835 player->has_closed_caption = FALSE;
4836 player->pending_resume = FALSE;
4837 if (player->ini.dump_element_keyword[0][0] == '\0')
4838 player->ini.set_dump_element_flag = FALSE;
4840 player->ini.set_dump_element_flag = TRUE;
4842 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4843 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4844 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4846 /* Set video360 settings to their defaults for just-created player.
4849 player->is_360_feature_enabled = FALSE;
4850 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4851 LOGI("spherical feature info: %d", enabled);
4853 player->is_360_feature_enabled = TRUE;
4855 LOGE("failed to get spherical feature info");
4858 player->is_content_spherical = FALSE;
4859 player->is_video360_enabled = TRUE;
4860 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4861 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4862 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4863 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4864 player->video360_zoom = 1.0f;
4865 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4866 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4868 __mmplayer_initialize_video_roi(player);
4870 /* set player state to null */
4871 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4872 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4876 return MM_ERROR_NONE;
4880 g_mutex_clear(&player->fsink_lock);
4881 /* free update tag lock */
4882 g_mutex_clear(&player->update_tag_lock);
4883 g_queue_free(player->bus_msg_q);
4884 player->bus_msg_q = NULL;
4885 /* free gapless play thread */
4886 if (player->gapless_play_thread) {
4887 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4888 player->gapless_play_thread_exit = TRUE;
4889 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4890 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4892 g_thread_join(player->gapless_play_thread);
4893 player->gapless_play_thread = NULL;
4895 g_mutex_clear(&player->gapless_play_thread_mutex);
4896 g_cond_clear(&player->gapless_play_thread_cond);
4899 /* release attributes */
4900 _mmplayer_deconstruct_attribute(handle);
4908 __mmplayer_init_gstreamer(mmplayer_t *player)
4910 static gboolean initialized = FALSE;
4911 static const int max_argc = 50;
4913 gchar **argv = NULL;
4914 gchar **argv2 = NULL;
4920 LOGD("gstreamer already initialized.");
4925 argc = malloc(sizeof(int));
4926 argv = malloc(sizeof(gchar *) * max_argc);
4927 argv2 = malloc(sizeof(gchar *) * max_argc);
4929 if (!argc || !argv || !argv2)
4932 memset(argv, 0, sizeof(gchar *) * max_argc);
4933 memset(argv2, 0, sizeof(gchar *) * max_argc);
4937 argv[0] = g_strdup("mmplayer");
4940 for (i = 0; i < 5; i++) {
4941 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4942 if (strlen(player->ini.gst_param[i]) > 0) {
4943 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4948 /* we would not do fork for scanning plugins */
4949 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4952 /* check disable registry scan */
4953 if (player->ini.skip_rescan) {
4954 argv[*argc] = g_strdup("--gst-disable-registry-update");
4958 /* check disable segtrap */
4959 if (player->ini.disable_segtrap) {
4960 argv[*argc] = g_strdup("--gst-disable-segtrap");
4964 LOGD("initializing gstreamer with following parameter");
4965 LOGD("argc : %d", *argc);
4968 for (i = 0; i < arg_count; i++) {
4970 LOGD("argv[%d] : %s", i, argv2[i]);
4973 /* initializing gstreamer */
4974 if (!gst_init_check(argc, &argv, &err)) {
4975 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4982 for (i = 0; i < arg_count; i++) {
4984 LOGD("release - argv[%d] : %s", i, argv2[i]);
4986 MMPLAYER_FREEIF(argv2[i]);
4989 MMPLAYER_FREEIF(argv);
4990 MMPLAYER_FREEIF(argv2);
4991 MMPLAYER_FREEIF(argc);
5001 for (i = 0; i < arg_count; i++) {
5002 LOGD("free[%d] : %s", i, argv2[i]);
5003 MMPLAYER_FREEIF(argv2[i]);
5006 MMPLAYER_FREEIF(argv);
5007 MMPLAYER_FREEIF(argv2);
5008 MMPLAYER_FREEIF(argc);
5014 __mmplayer_check_async_state_transition(mmplayer_t *player)
5016 GstState element_state = GST_STATE_VOID_PENDING;
5017 GstState element_pending_state = GST_STATE_VOID_PENDING;
5018 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5019 GstElement *element = NULL;
5020 gboolean async = FALSE;
5022 /* check player handle */
5023 MMPLAYER_RETURN_IF_FAIL(player &&
5025 player->pipeline->mainbin &&
5026 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5029 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5031 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5032 LOGD("don't need to check the pipeline state");
5036 MMPLAYER_PRINT_STATE(player);
5038 /* wait for state transition */
5039 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5040 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5042 if (ret == GST_STATE_CHANGE_FAILURE) {
5043 LOGE(" [%s] state : %s pending : %s",
5044 GST_ELEMENT_NAME(element),
5045 gst_element_state_get_name(element_state),
5046 gst_element_state_get_name(element_pending_state));
5048 /* dump state of all element */
5049 _mmplayer_dump_pipeline_state(player);
5054 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5059 _mmplayer_destroy(MMHandleType handle)
5061 mmplayer_t *player = MM_PLAYER_CAST(handle);
5065 /* check player handle */
5066 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5068 /* destroy can called at anytime */
5069 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5071 /* check async state transition */
5072 __mmplayer_check_async_state_transition(player);
5074 /* release gapless play thread */
5075 if (player->gapless_play_thread) {
5076 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5077 player->gapless_play_thread_exit = TRUE;
5078 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5079 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5081 LOGD("waiting for gapless play thread exit");
5082 g_thread_join(player->gapless_play_thread);
5083 g_mutex_clear(&player->gapless_play_thread_mutex);
5084 g_cond_clear(&player->gapless_play_thread_cond);
5085 LOGD("gapless play thread released");
5088 _mmplayer_release_video_capture(player);
5090 /* release miscellaneous information */
5091 __mmplayer_release_misc(player);
5093 /* release pipeline */
5094 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5095 LOGE("failed to destroy pipeline");
5096 return MM_ERROR_PLAYER_INTERNAL;
5099 __mmplayer_destroy_hw_resource(player);
5101 g_queue_free(player->bus_msg_q);
5103 /* release subtitle info lock and cond */
5104 g_mutex_clear(&player->subtitle_info_mutex);
5105 g_cond_clear(&player->subtitle_info_cond);
5107 __mmplayer_release_dump_list(player->dump_list);
5109 /* release miscellaneous information.
5110 these info needs to be released after pipeline is destroyed. */
5111 __mmplayer_release_misc_post(player);
5113 /* release attributes */
5114 _mmplayer_deconstruct_attribute(handle);
5116 if (player->uri_info.uri_list) {
5117 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5118 player->uri_info.uri_list = NULL;
5122 g_mutex_clear(&player->fsink_lock);
5125 g_mutex_clear(&player->update_tag_lock);
5127 /* release video bo lock and cond */
5128 g_mutex_clear(&player->video_bo_mutex);
5129 g_cond_clear(&player->video_bo_cond);
5133 return MM_ERROR_NONE;
5137 _mmplayer_realize(MMHandleType hplayer)
5139 mmplayer_t *player = (mmplayer_t *)hplayer;
5140 int ret = MM_ERROR_NONE;
5143 MMHandleType attrs = 0;
5147 /* check player handle */
5148 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5150 /* check current state */
5151 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5153 attrs = MMPLAYER_GET_ATTRS(player);
5155 LOGE("fail to get attributes.");
5156 return MM_ERROR_PLAYER_INTERNAL;
5158 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5159 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5161 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5162 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5164 if (ret != MM_ERROR_NONE) {
5165 LOGE("failed to parse profile");
5170 if (uri && (strstr(uri, "es_buff://"))) {
5171 if (strstr(uri, "es_buff://push_mode"))
5172 player->es_player_push_mode = TRUE;
5174 player->es_player_push_mode = FALSE;
5177 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5178 LOGW("mms protocol is not supported format.");
5179 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5182 if (MMPLAYER_IS_STREAMING(player))
5183 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5185 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5187 player->smooth_streaming = FALSE;
5188 player->videodec_linked = 0;
5189 player->audiodec_linked = 0;
5190 player->textsink_linked = 0;
5191 player->is_external_subtitle_present = FALSE;
5192 player->is_external_subtitle_added_now = FALSE;
5193 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5194 player->video360_metadata.is_spherical = -1;
5195 player->is_openal_plugin_used = FALSE;
5196 player->subtitle_language_list = NULL;
5197 player->is_subtitle_force_drop = FALSE;
5199 _mmplayer_track_initialize(player);
5200 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5202 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5203 gint prebuffer_ms = 0, rebuffer_ms = 0;
5205 player->streamer = _mm_player_streaming_create();
5206 _mm_player_streaming_initialize(player->streamer, TRUE);
5208 mm_attrs_multiple_get(player->attrs, NULL,
5209 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5210 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5212 if (prebuffer_ms > 0) {
5213 prebuffer_ms = MAX(prebuffer_ms, 1000);
5214 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5217 if (rebuffer_ms > 0) {
5218 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5219 rebuffer_ms = MAX(rebuffer_ms, 1000);
5220 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5223 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5224 player->streamer->buffering_req.rebuffer_time);
5227 /* realize pipeline */
5228 ret = __mmplayer_gst_realize(player);
5229 if (ret != MM_ERROR_NONE)
5230 LOGE("fail to realize the player.");
5232 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5240 _mmplayer_unrealize(MMHandleType hplayer)
5242 mmplayer_t *player = (mmplayer_t *)hplayer;
5243 int ret = MM_ERROR_NONE;
5244 int rm_ret = MM_ERROR_NONE;
5245 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5249 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5251 MMPLAYER_CMD_UNLOCK(player);
5252 _mmplayer_bus_watcher_remove(player);
5253 /* destroy the gst bus msg thread which is created during realize.
5254 this funct have to be called before getting cmd lock. */
5255 _mmplayer_bus_msg_thread_destroy(player);
5256 MMPLAYER_CMD_LOCK(player);
5258 /* check current state */
5259 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5261 /* check async state transition */
5262 __mmplayer_check_async_state_transition(player);
5264 /* unrealize pipeline */
5265 ret = __mmplayer_gst_unrealize(player);
5267 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5268 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5269 if (rm_ret != MM_ERROR_NONE)
5270 LOGE("failed to release [%d] resources", res_idx);
5273 player->interrupted_by_resource = FALSE;
5280 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5282 mmplayer_t *player = (mmplayer_t *)hplayer;
5284 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5286 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5290 _mmplayer_get_state(MMHandleType hplayer, int *state)
5292 mmplayer_t *player = (mmplayer_t *)hplayer;
5294 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5296 *state = MMPLAYER_CURRENT_STATE(player);
5298 return MM_ERROR_NONE;
5302 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5304 GstElement *vol_element = NULL;
5305 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5308 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5309 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5311 /* check pipeline handle */
5312 if (!player->pipeline || !player->pipeline->audiobin) {
5313 LOGD("'%s' will be applied when audiobin is created", prop_name);
5315 /* NOTE : stored value will be used in create_audiobin
5316 * returning MM_ERROR_NONE here makes application to able to
5317 * set audio volume or mute at anytime.
5319 return MM_ERROR_NONE;
5322 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5323 volume_elem_id = MMPLAYER_A_SINK;
5325 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5327 LOGE("failed to get vol element %d", volume_elem_id);
5328 return MM_ERROR_PLAYER_INTERNAL;
5331 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5333 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5334 LOGE("there is no '%s' property", prop_name);
5335 return MM_ERROR_PLAYER_INTERNAL;
5338 if (!strcmp(prop_name, "volume")) {
5339 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5340 } else if (!strcmp(prop_name, "mute")) {
5341 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5343 LOGE("invalid property %s", prop_name);
5344 return MM_ERROR_PLAYER_INTERNAL;
5347 return MM_ERROR_NONE;
5351 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5353 int ret = MM_ERROR_NONE;
5354 mmplayer_t *player = (mmplayer_t *)hplayer;
5357 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5359 LOGD("volume = %f", volume);
5361 /* invalid factor range or not */
5362 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5363 LOGE("Invalid volume value");
5364 return MM_ERROR_INVALID_ARGUMENT;
5367 player->sound.volume = volume;
5369 ret = __mmplayer_gst_set_volume_property(player, "volume");
5376 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5378 mmplayer_t *player = (mmplayer_t *)hplayer;
5382 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5383 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5385 *volume = player->sound.volume;
5387 LOGD("current vol = %f", *volume);
5390 return MM_ERROR_NONE;
5394 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5396 int ret = MM_ERROR_NONE;
5397 mmplayer_t *player = (mmplayer_t *)hplayer;
5400 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5402 LOGD("mute = %d", mute);
5404 player->sound.mute = mute;
5406 ret = __mmplayer_gst_set_volume_property(player, "mute");
5413 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5415 mmplayer_t *player = (mmplayer_t *)hplayer;
5419 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5420 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5422 *mute = player->sound.mute;
5424 LOGD("current mute = %d", *mute);
5428 return MM_ERROR_NONE;
5432 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5434 mmplayer_t *player = (mmplayer_t *)hplayer;
5438 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5440 player->audio_stream_changed_cb = callback;
5441 player->audio_stream_changed_cb_user_param = user_param;
5442 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5446 return MM_ERROR_NONE;
5450 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5452 mmplayer_t *player = (mmplayer_t *)hplayer;
5456 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5458 player->audio_decoded_cb = callback;
5459 player->audio_decoded_cb_user_param = user_param;
5460 player->audio_extract_opt = opt;
5461 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5465 return MM_ERROR_NONE;
5469 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5471 mmplayer_t *player = (mmplayer_t *)hplayer;
5475 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5477 if (callback && !player->bufmgr)
5478 player->bufmgr = tbm_bufmgr_init(-1);
5480 player->set_mode.video_export = (callback) ? true : false;
5481 player->video_decoded_cb = callback;
5482 player->video_decoded_cb_user_param = user_param;
5484 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5488 return MM_ERROR_NONE;
5492 _mmplayer_start(MMHandleType hplayer)
5494 mmplayer_t *player = (mmplayer_t *)hplayer;
5495 gint ret = MM_ERROR_NONE;
5499 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5501 /* check current state */
5502 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5504 /* start pipeline */
5505 ret = _mmplayer_gst_start(player);
5506 if (ret != MM_ERROR_NONE)
5507 LOGE("failed to start player.");
5509 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5510 LOGD("force playing start even during buffering");
5511 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5519 /* NOTE: post "not supported codec message" to application
5520 * when one codec is not found during AUTOPLUGGING in MSL.
5521 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5522 * And, if any codec is not found, don't send message here.
5523 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5526 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5528 MMMessageParamType msg_param;
5529 memset(&msg_param, 0, sizeof(MMMessageParamType));
5530 gboolean post_msg_direct = FALSE;
5534 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5536 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5537 player->not_supported_codec, player->can_support_codec);
5539 if (player->not_found_demuxer) {
5540 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5541 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5543 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5544 MMPLAYER_FREEIF(msg_param.data);
5546 return MM_ERROR_NONE;
5549 if (player->not_supported_codec) {
5550 if (player->can_support_codec) {
5551 // There is one codec to play
5552 post_msg_direct = TRUE;
5554 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5555 post_msg_direct = TRUE;
5558 if (post_msg_direct) {
5559 MMMessageParamType msg_param;
5560 memset(&msg_param, 0, sizeof(MMMessageParamType));
5562 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5563 LOGW("not found AUDIO codec, posting error code to application.");
5565 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5566 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5567 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5568 LOGW("not found VIDEO codec, posting error code to application.");
5570 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5571 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5574 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5576 MMPLAYER_FREEIF(msg_param.data);
5578 return MM_ERROR_NONE;
5580 // no any supported codec case
5581 LOGW("not found any codec, posting error code to application.");
5583 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5584 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5585 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5587 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5588 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5591 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5593 MMPLAYER_FREEIF(msg_param.data);
5599 return MM_ERROR_NONE;
5602 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5604 GstState element_state = GST_STATE_VOID_PENDING;
5605 GstState element_pending_state = GST_STATE_VOID_PENDING;
5606 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5607 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5609 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5611 MMPLAYER_RECONFIGURE_LOCK(player);
5612 if (!player->gapless.reconfigure) {
5613 MMPLAYER_RECONFIGURE_UNLOCK(player);
5617 LOGI("reconfigure is under process");
5618 MMPLAYER_RECONFIGURE_WAIT(player);
5619 MMPLAYER_RECONFIGURE_UNLOCK(player);
5620 LOGI("reconfigure is completed.");
5622 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5623 &element_state, &element_pending_state, timeout * GST_SECOND);
5624 if (result == GST_STATE_CHANGE_FAILURE)
5625 LOGW("failed to get pipeline state in %d sec", timeout);
5630 /* NOTE : it should be able to call 'stop' anytime*/
5632 _mmplayer_stop(MMHandleType hplayer)
5634 mmplayer_t *player = (mmplayer_t *)hplayer;
5635 int ret = MM_ERROR_NONE;
5639 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5641 /* check current state */
5642 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5644 /* need to wait till the rebuilding pipeline is completed */
5645 __mmplayer_check_pipeline_reconfigure_state(player);
5646 MMPLAYER_RECONFIGURE_LOCK(player);
5647 __mmplayer_reset_gapless_state(player);
5648 MMPLAYER_RECONFIGURE_UNLOCK(player);
5650 /* NOTE : application should not wait for EOS after calling STOP */
5651 _mmplayer_cancel_eos_timer(player);
5654 player->seek_state = MMPLAYER_SEEK_NONE;
5657 ret = _mmplayer_gst_stop(player);
5659 if (ret != MM_ERROR_NONE)
5660 LOGE("failed to stop player.");
5668 _mmplayer_pause(MMHandleType hplayer)
5670 mmplayer_t *player = (mmplayer_t *)hplayer;
5671 gint64 pos_nsec = 0;
5672 gboolean async = FALSE;
5673 gint ret = MM_ERROR_NONE;
5677 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5679 /* check current state */
5680 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5682 /* check pipeline reconfigure state */
5683 __mmplayer_check_pipeline_reconfigure_state(player);
5685 switch (MMPLAYER_CURRENT_STATE(player)) {
5686 case MM_PLAYER_STATE_READY:
5688 /* check prepare async or not.
5689 * In the case of streaming playback, it's recommended to avoid blocking wait.
5691 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5692 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5694 /* Changing back sync of rtspsrc to async */
5695 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5696 LOGD("async prepare working mode for rtsp");
5702 case MM_PLAYER_STATE_PLAYING:
5704 /* NOTE : store current point to overcome some bad operation
5705 *(returning zero when getting current position in paused state) of some
5708 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5709 LOGW("getting current position failed in paused");
5711 player->last_position = pos_nsec;
5713 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5714 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5715 This causes problem is position calculation during normal pause resume scenarios also.
5716 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5717 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5718 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5719 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5725 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5726 LOGD("doing async pause in case of ms buff src");
5730 /* pause pipeline */
5731 ret = _mmplayer_gst_pause(player, async);
5732 if (ret != MM_ERROR_NONE) {
5733 LOGE("failed to pause player. ret : 0x%x", ret);
5734 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5738 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5739 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5740 LOGE("failed to update display_rotation");
5744 return MM_ERROR_NONE;
5747 /* in case of streaming, pause could take long time.*/
5749 _mmplayer_abort_pause(MMHandleType hplayer)
5751 mmplayer_t *player = (mmplayer_t *)hplayer;
5752 int ret = MM_ERROR_NONE;
5756 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5758 player->pipeline->mainbin,
5759 MM_ERROR_PLAYER_NOT_INITIALIZED);
5761 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5762 LOGD("set the videobin state to READY");
5763 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5764 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5768 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5769 LOGD("set the audiobin state to READY");
5770 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5771 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5775 LOGD("set the pipeline state to READY");
5776 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5777 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5779 if (ret != MM_ERROR_NONE) {
5780 LOGE("fail to change state to READY");
5781 return MM_ERROR_PLAYER_INTERNAL;
5784 LOGD("succeeded in changing state to READY");
5789 _mmplayer_resume(MMHandleType hplayer)
5791 mmplayer_t *player = (mmplayer_t *)hplayer;
5792 int ret = MM_ERROR_NONE;
5793 gboolean async = FALSE;
5797 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5799 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5800 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5801 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5805 /* Changing back sync mode rtspsrc to async */
5806 LOGD("async resume for rtsp case");
5810 /* check current state */
5811 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5813 ret = _mmplayer_gst_resume(player, async);
5814 if (ret != MM_ERROR_NONE)
5815 LOGE("failed to resume player.");
5817 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5818 LOGD("force resume even during buffering");
5819 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5828 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5830 mmplayer_t *player = (mmplayer_t *)hplayer;
5831 gint64 pos_nsec = 0;
5832 int ret = MM_ERROR_NONE;
5834 signed long long start = 0, stop = 0;
5835 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5838 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5839 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5841 /* The sound of video is not supported under 0.0 and over 2.0. */
5842 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5843 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5846 _mmplayer_set_mute(hplayer, mute);
5848 if (player->playback_rate == rate)
5849 return MM_ERROR_NONE;
5851 /* If the position is reached at start potion during fast backward, EOS is posted.
5852 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5854 player->playback_rate = rate;
5856 current_state = MMPLAYER_CURRENT_STATE(player);
5858 if (current_state != MM_PLAYER_STATE_PAUSED)
5859 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5861 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5863 if ((current_state == MM_PLAYER_STATE_PAUSED)
5864 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5865 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5866 pos_nsec = player->last_position;
5871 stop = GST_CLOCK_TIME_NONE;
5873 start = GST_CLOCK_TIME_NONE;
5877 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5878 player->playback_rate,
5880 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5881 GST_SEEK_TYPE_SET, start,
5882 GST_SEEK_TYPE_SET, stop)) {
5883 LOGE("failed to set speed playback");
5884 return MM_ERROR_PLAYER_SEEK;
5887 LOGD("succeeded to set speed playback as %0.1f", rate);
5891 return MM_ERROR_NONE;;
5895 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5897 mmplayer_t *player = (mmplayer_t *)hplayer;
5898 int ret = MM_ERROR_NONE;
5902 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5904 /* check pipeline reconfigure state */
5905 __mmplayer_check_pipeline_reconfigure_state(player);
5907 ret = _mmplayer_gst_set_position(player, position, FALSE);
5915 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5917 mmplayer_t *player = (mmplayer_t *)hplayer;
5918 int ret = MM_ERROR_NONE;
5920 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5921 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5923 if (g_strrstr(player->type, "video/mpegts"))
5924 __mmplayer_update_duration_value(player);
5926 *duration = player->duration;
5931 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5933 mmplayer_t *player = (mmplayer_t *)hplayer;
5934 int ret = MM_ERROR_NONE;
5936 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5938 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5944 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5946 mmplayer_t *player = (mmplayer_t *)hplayer;
5947 int ret = MM_ERROR_NONE;
5951 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5953 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5961 __mmplayer_is_midi_type(gchar *str_caps)
5963 if ((g_strrstr(str_caps, "audio/midi")) ||
5964 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5965 (g_strrstr(str_caps, "application/x-smaf")) ||
5966 (g_strrstr(str_caps, "audio/x-imelody")) ||
5967 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5968 (g_strrstr(str_caps, "audio/xmf")) ||
5969 (g_strrstr(str_caps, "audio/mxmf"))) {
5978 __mmplayer_is_only_mp3_type(gchar *str_caps)
5980 if (g_strrstr(str_caps, "application/x-id3") ||
5981 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5987 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5989 GstStructure *caps_structure = NULL;
5990 gint samplerate = 0;
5994 MMPLAYER_RETURN_IF_FAIL(player && caps);
5996 caps_structure = gst_caps_get_structure(caps, 0);
5998 /* set stream information */
5999 gst_structure_get_int(caps_structure, "rate", &samplerate);
6000 gst_structure_get_int(caps_structure, "channels", &channels);
6002 mm_player_set_attribute((MMHandleType)player, NULL,
6003 "content_audio_samplerate", samplerate,
6004 "content_audio_channels", channels, NULL);
6006 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6010 __mmplayer_update_content_type_info(mmplayer_t *player)
6013 MMPLAYER_RETURN_IF_FAIL(player && player->type);
6015 if (__mmplayer_is_midi_type(player->type)) {
6016 player->bypass_audio_effect = TRUE;
6020 if (!player->streamer) {
6021 LOGD("no need to check streaming type");
6025 if (g_strrstr(player->type, "application/x-hls")) {
6026 /* If it can't know exact type when it parses uri because of redirection case,
6027 * it will be fixed by typefinder or when doing autoplugging.
6029 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6030 player->streamer->is_adaptive_streaming = TRUE;
6031 } else if (g_strrstr(player->type, "application/dash+xml")) {
6032 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6033 player->streamer->is_adaptive_streaming = TRUE;
6036 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6037 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
6038 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6040 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6041 if (player->streamer->is_adaptive_streaming)
6042 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6044 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6048 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6053 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6054 GstCaps *caps, gpointer data)
6056 mmplayer_t *player = (mmplayer_t *)data;
6060 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6062 /* store type string */
6063 if (player->type_caps) {
6064 gst_caps_unref(player->type_caps);
6065 player->type_caps = NULL;
6068 player->type_caps = gst_caps_copy(caps);
6069 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
6071 MMPLAYER_FREEIF(player->type);
6072 player->type = gst_caps_to_string(caps);
6074 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6075 player, player->type, probability, gst_caps_get_size(caps));
6077 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6078 (g_strrstr(player->type, "audio/x-raw-int"))) {
6079 LOGE("not support media format");
6081 if (player->msg_posted == FALSE) {
6082 MMMessageParamType msg_param;
6083 memset(&msg_param, 0, sizeof(MMMessageParamType));
6085 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6086 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6088 /* don't post more if one was sent already */
6089 player->msg_posted = TRUE;
6094 __mmplayer_update_content_type_info(player);
6096 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6099 pad = gst_element_get_static_pad(tf, "src");
6101 LOGE("fail to get typefind src pad.");
6105 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6106 gboolean async = FALSE;
6107 LOGE("failed to autoplug %s", player->type);
6109 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6111 if (async && player->msg_posted == FALSE)
6112 __mmplayer_handle_missed_plugin(player);
6114 gst_object_unref(GST_OBJECT(pad));
6121 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6123 GstElement *decodebin = NULL;
6127 /* create decodebin */
6128 decodebin = gst_element_factory_make("decodebin", NULL);
6131 LOGE("fail to create decodebin");
6135 /* raw pad handling signal */
6136 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6137 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6139 /* no-more-pad pad handling signal */
6140 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6141 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6143 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6144 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6146 /* This signal is emitted when a pad for which there is no further possible
6147 decoding is added to the decodebin.*/
6148 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6149 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6151 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6152 before looking for any elements that can handle that stream.*/
6153 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6154 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6156 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6157 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6158 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6160 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6161 before looking for any elements that can handle that stream.*/
6162 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6163 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6165 /* This signal is emitted once decodebin has finished decoding all the data.*/
6166 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6167 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6169 /* This signal is emitted when a element is added to the bin.*/
6170 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6171 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6178 __mmplayer_gst_make_queue2(mmplayer_t *player)
6180 GstElement *queue2 = NULL;
6181 gint64 dur_bytes = 0L;
6182 mmplayer_gst_element_t *mainbin = NULL;
6183 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6186 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6188 mainbin = player->pipeline->mainbin;
6190 queue2 = gst_element_factory_make("queue2", "queue2");
6192 LOGE("failed to create buffering queue element");
6196 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6197 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6199 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6201 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6202 * skip the pull mode(file or ring buffering) setting. */
6203 if (dur_bytes > 0) {
6204 if (!g_strrstr(player->type, "video/mpegts")) {
6205 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6206 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6212 _mm_player_streaming_set_queue2(player->streamer,
6216 (guint64)dur_bytes); /* no meaning at the moment */
6222 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6224 mmplayer_gst_element_t *mainbin = NULL;
6225 GstElement *decodebin = NULL;
6226 GstElement *queue2 = NULL;
6227 GstPad *sinkpad = NULL;
6228 GstPad *qsrcpad = NULL;
6231 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6233 mainbin = player->pipeline->mainbin;
6235 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6237 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6238 LOGW("need to check: muxed buffer is not null");
6241 queue2 = __mmplayer_gst_make_queue2(player);
6243 LOGE("failed to make queue2");
6247 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6248 LOGE("failed to add buffering queue");
6252 sinkpad = gst_element_get_static_pad(queue2, "sink");
6253 qsrcpad = gst_element_get_static_pad(queue2, "src");
6255 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6256 LOGE("failed to link [%s:%s]-[%s:%s]",
6257 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6261 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6262 LOGE("failed to sync queue2 state with parent");
6266 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6267 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6271 gst_object_unref(GST_OBJECT(sinkpad));
6275 /* create decodebin */
6276 decodebin = _mmplayer_gst_make_decodebin(player);
6278 LOGE("failed to make decodebin");
6282 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6283 LOGE("failed to add decodebin");
6287 /* to force caps on the decodebin element and avoid reparsing stuff by
6288 * typefind. It also avoids a deadlock in the way typefind activates pads in
6289 * the state change */
6290 g_object_set(decodebin, "sink-caps", caps, NULL);
6292 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6294 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6295 LOGE("failed to link [%s:%s]-[%s:%s]",
6296 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6300 gst_object_unref(GST_OBJECT(sinkpad));
6302 gst_object_unref(GST_OBJECT(qsrcpad));
6305 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6306 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6308 /* set decodebin property about buffer in streaming playback. *
6309 * in case of HLS/DASH, it does not need to have big buffer *
6310 * because it is kind of adaptive streaming. */
6311 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6312 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6313 gint high_percent = 0;
6315 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6316 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6318 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6320 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6322 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6323 "high-percent", high_percent,
6324 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6325 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6326 "max-size-buffers", 0, NULL); // disable or automatic
6329 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6330 LOGE("failed to sync decodebin state with parent");
6341 gst_object_unref(GST_OBJECT(sinkpad));
6344 gst_object_unref(GST_OBJECT(qsrcpad));
6347 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6348 * You need to explicitly set elements to the NULL state before
6349 * dropping the final reference, to allow them to clean up.
6351 gst_element_set_state(queue2, GST_STATE_NULL);
6353 /* And, it still has a parent "player".
6354 * You need to let the parent manage the object instead of unreffing the object directly.
6356 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6357 LOGE("failed to remove queue2");
6358 gst_object_unref(queue2);
6364 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6365 * You need to explicitly set elements to the NULL state before
6366 * dropping the final reference, to allow them to clean up.
6368 gst_element_set_state(decodebin, GST_STATE_NULL);
6370 /* And, it still has a parent "player".
6371 * You need to let the parent manage the object instead of unreffing the object directly.
6374 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6375 LOGE("failed to remove decodebin");
6376 gst_object_unref(decodebin);
6385 _mmplayer_update_not_supported_codec_info(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6389 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6390 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6392 LOGD("class : %s, mime : %s", factory_class, mime);
6394 /* add missing plugin */
6395 /* NOTE : msl should check missing plugin for image mime type.
6396 * Some motion jpeg clips can have playable audio track.
6397 * So, msl have to play audio after displaying popup written video format not supported.
6399 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6400 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6401 LOGD("not found demuxer");
6402 player->not_found_demuxer = TRUE;
6403 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6409 if (!g_strrstr(factory_class, "Demuxer")) {
6410 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6411 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6412 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6414 /* check that clip have multi tracks or not */
6415 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6416 LOGD("video plugin is already linked");
6418 LOGW("add VIDEO to missing plugin");
6419 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6420 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6422 } else if (g_str_has_prefix(mime, "audio")) {
6423 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6424 LOGD("audio plugin is already linked");
6426 LOGW("add AUDIO to missing plugin");
6427 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6428 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6436 return MM_ERROR_NONE;
6440 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6442 mmplayer_t *player = (mmplayer_t *)data;
6446 MMPLAYER_RETURN_IF_FAIL(player);
6448 /* remove fakesink. */
6449 if (!_mmplayer_gst_remove_fakesink(player,
6450 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6451 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6452 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6453 * source element are not same. To overcome this situation, this function will called
6454 * several places and several times. Therefore, this is not an error case.
6459 LOGD("[handle: %p] pipeline has completely constructed", player);
6461 if ((player->msg_posted == FALSE) &&
6462 (player->cmd >= MMPLAYER_COMMAND_START))
6463 __mmplayer_handle_missed_plugin(player);
6465 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6469 __mmplayer_check_profile(void)
6472 static int profile_tv = -1;
6474 if (__builtin_expect(profile_tv != -1, 1))
6477 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6478 switch (*profileName) {
6493 __mmplayer_get_next_uri(mmplayer_t *player)
6495 mmplayer_parse_profile_t profile;
6497 guint num_of_list = 0;
6500 num_of_list = g_list_length(player->uri_info.uri_list);
6501 uri_idx = player->uri_info.uri_idx;
6503 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6504 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6505 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6507 LOGW("next uri does not exist");
6511 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6512 LOGE("failed to parse profile");
6516 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6517 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6518 LOGW("uri type is not supported(%d)", profile.uri_type);
6522 LOGD("success to find next uri %d", uri_idx);
6526 if (!uri || uri_idx == num_of_list) {
6527 LOGE("failed to find next uri");
6531 player->uri_info.uri_idx = uri_idx;
6532 if (mm_player_set_attribute((MMHandleType)player, NULL,
6533 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6534 LOGE("failed to set attribute");
6538 SECURE_LOGD("next playback uri: %s", uri);
6543 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6545 #define REPEAT_COUNT_INFINITE -1
6546 #define REPEAT_COUNT_MIN 2
6547 #define ORIGINAL_URI_ONLY 1
6549 MMHandleType attrs = 0;
6553 guint num_of_uri = 0;
6554 int profile_tv = -1;
6558 LOGD("checking for gapless play option");
6560 if (player->build_audio_offload) {
6561 LOGE("offload path is not supportable.");
6565 if (player->pipeline->textbin) {
6566 LOGE("subtitle path is enabled. gapless play is not supported.");
6570 attrs = MMPLAYER_GET_ATTRS(player);
6572 LOGE("fail to get attributes.");
6576 mm_attrs_multiple_get(player->attrs, NULL,
6577 "content_video_found", &video,
6578 "profile_play_count", &count,
6579 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6581 /* gapless playback is not supported in case of video at TV profile. */
6582 profile_tv = __mmplayer_check_profile();
6583 if (profile_tv && video) {
6584 LOGW("not support video gapless playback");
6588 /* check repeat count in case of audio */
6590 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6591 LOGW("gapless is disabled");
6595 num_of_uri = g_list_length(player->uri_info.uri_list);
6597 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6599 if (num_of_uri == ORIGINAL_URI_ONLY) {
6600 /* audio looping path */
6601 if (count >= REPEAT_COUNT_MIN) {
6602 /* decrease play count */
6603 /* we succeeded to rewind. update play count and then wait for next EOS */
6605 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6606 } else if (count != REPEAT_COUNT_INFINITE) {
6607 LOGD("there is no next uri and no repeat");
6610 LOGD("looping cnt %d", count);
6612 /* gapless playback path */
6613 if (!__mmplayer_get_next_uri(player)) {
6614 LOGE("failed to get next uri");
6621 LOGE("unable to play gapless path. EOS will be posted soon");
6626 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6628 GstPad *sinkpad = g_value_get_object (item);
6629 GstElement *element = GST_ELEMENT(user_data);
6630 if (!sinkpad || !element) {
6631 LOGE("invalid parameter");
6635 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6636 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6640 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6642 mmplayer_gst_element_t *sinkbin = NULL;
6643 main_element_id_e concatId = MMPLAYER_M_NUM;
6644 main_element_id_e sinkId = MMPLAYER_M_NUM;
6645 gboolean send_notice = FALSE;
6646 GstElement *element;
6650 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6652 LOGD("type %d", type);
6655 case MM_PLAYER_TRACK_TYPE_AUDIO:
6656 concatId = MMPLAYER_M_A_CONCAT;
6657 sinkId = MMPLAYER_A_BIN;
6658 sinkbin = player->pipeline->audiobin;
6660 case MM_PLAYER_TRACK_TYPE_VIDEO:
6661 concatId = MMPLAYER_M_V_CONCAT;
6662 sinkId = MMPLAYER_V_BIN;
6663 sinkbin = player->pipeline->videobin;
6666 case MM_PLAYER_TRACK_TYPE_TEXT:
6667 concatId = MMPLAYER_M_T_CONCAT;
6668 sinkId = MMPLAYER_T_BIN;
6669 sinkbin = player->pipeline->textbin;
6672 LOGE("requested type is not supportable");
6677 element = player->pipeline->mainbin[concatId].gst;
6681 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6682 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6683 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6684 if (srcpad && sinkpad) {
6685 /* after getting drained signal there is no data flows, so no need to do pad_block */
6686 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6687 gst_pad_unlink(srcpad, sinkpad);
6689 /* send custom event to sink pad to handle it at video sink */
6691 LOGD("send custom event to sinkpad");
6692 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6693 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6694 gst_pad_send_event(sinkpad, event);
6697 gst_object_unref(srcpad);
6698 gst_object_unref(sinkpad);
6701 LOGD("release concat request pad");
6702 /* release and unref requests pad from the selector */
6703 iter = gst_element_iterate_sink_pads(element);
6704 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6705 gst_iterator_resync(iter);
6706 gst_iterator_free(iter);
6712 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6714 mmplayer_track_t *selector = &player->track[type];
6715 mmplayer_gst_element_t *sinkbin = NULL;
6716 main_element_id_e selectorId = MMPLAYER_M_NUM;
6717 main_element_id_e sinkId = MMPLAYER_M_NUM;
6718 GstPad *srcpad = NULL;
6719 GstPad *sinkpad = NULL;
6720 gboolean send_notice = FALSE;
6723 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6725 LOGD("type %d", type);
6728 case MM_PLAYER_TRACK_TYPE_AUDIO:
6729 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6730 sinkId = MMPLAYER_A_BIN;
6731 sinkbin = player->pipeline->audiobin;
6733 case MM_PLAYER_TRACK_TYPE_VIDEO:
6734 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6735 sinkId = MMPLAYER_V_BIN;
6736 sinkbin = player->pipeline->videobin;
6739 case MM_PLAYER_TRACK_TYPE_TEXT:
6740 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6741 sinkId = MMPLAYER_T_BIN;
6742 sinkbin = player->pipeline->textbin;
6745 LOGE("requested type is not supportable");
6750 if (player->pipeline->mainbin[selectorId].gst) {
6753 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6755 if (selector->event_probe_id != 0)
6756 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6757 selector->event_probe_id = 0;
6759 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6760 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6762 if (srcpad && sinkpad) {
6763 /* after getting drained signal there is no data flows, so no need to do pad_block */
6764 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6765 gst_pad_unlink(srcpad, sinkpad);
6767 /* send custom event to sink pad to handle it at video sink */
6769 LOGD("send custom event to sinkpad");
6770 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6771 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6772 gst_pad_send_event(sinkpad, event);
6776 gst_object_unref(sinkpad);
6779 gst_object_unref(srcpad);
6782 LOGD("selector release");
6784 /* release and unref requests pad from the selector */
6785 for (n = 0; n < selector->streams->len; n++) {
6786 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6787 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6790 g_ptr_array_set_size(selector->streams, 0);
6792 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6793 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6794 player->pipeline->mainbin[selectorId].gst)) {
6795 LOGE("failed to remove selector");
6796 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6799 player->pipeline->mainbin[selectorId].gst = NULL;
6807 __mmplayer_deactivate_old_path(mmplayer_t *player)
6810 MMPLAYER_RETURN_IF_FAIL(player);
6812 if (MMPLAYER_USE_DECODEBIN(player)) {
6813 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6814 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6815 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6816 LOGE("deactivate selector error");
6820 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6821 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6822 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6823 LOGE("deactivate concat error");
6828 _mmplayer_track_destroy(player);
6829 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6831 if (player->streamer) {
6832 _mm_player_streaming_initialize(player->streamer, FALSE);
6833 _mm_player_streaming_destroy(player->streamer);
6834 player->streamer = NULL;
6837 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6843 if (!player->msg_posted) {
6844 MMMessageParamType msg = {0,};
6847 msg.code = MM_ERROR_PLAYER_INTERNAL;
6848 LOGE("gapless_uri_play> deactivate error");
6850 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6851 player->msg_posted = TRUE;
6857 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6859 int result = MM_ERROR_NONE;
6860 mmplayer_t *player = (mmplayer_t *)hplayer;
6863 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6864 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6866 if (mm_player_set_attribute(hplayer, NULL,
6867 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6868 LOGE("failed to set attribute");
6869 result = MM_ERROR_PLAYER_INTERNAL;
6871 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6872 LOGE("failed to add the original uri in the uri list.");
6880 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6882 mmplayer_t *player = (mmplayer_t *)hplayer;
6883 guint num_of_list = 0;
6887 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6888 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6890 if (player->pipeline && player->pipeline->textbin) {
6891 LOGE("subtitle path is enabled.");
6892 return MM_ERROR_PLAYER_INVALID_STATE;
6895 num_of_list = g_list_length(player->uri_info.uri_list);
6897 if (is_first_path) {
6898 if (num_of_list == 0) {
6899 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6900 SECURE_LOGD("add original path : %s", uri);
6902 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6903 player->uri_info.uri_list = g_list_prepend(
6904 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6905 SECURE_LOGD("change original path : %s", uri);
6908 MMHandleType attrs = 0;
6909 attrs = MMPLAYER_GET_ATTRS(player);
6911 if (num_of_list == 0) {
6912 char *original_uri = NULL;
6915 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6917 if (!original_uri) {
6918 LOGE("there is no original uri.");
6919 return MM_ERROR_PLAYER_INVALID_STATE;
6922 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6923 player->uri_info.uri_idx = 0;
6925 SECURE_LOGD("add original path at first : %s", original_uri);
6929 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6930 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6934 return MM_ERROR_NONE;
6938 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6940 mmplayer_t *player = (mmplayer_t *)hplayer;
6941 char *next_uri = NULL;
6942 guint num_of_list = 0;
6945 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6947 num_of_list = g_list_length(player->uri_info.uri_list);
6949 if (num_of_list > 0) {
6950 gint uri_idx = player->uri_info.uri_idx;
6952 if (uri_idx < num_of_list - 1)
6957 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6958 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6960 *uri = g_strdup(next_uri);
6964 return MM_ERROR_NONE;
6968 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6969 GstCaps *caps, gpointer data)
6971 mmplayer_t *player = (mmplayer_t *)data;
6972 const gchar *klass = NULL;
6973 const gchar *mime = NULL;
6974 gchar *caps_str = NULL;
6976 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6977 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6978 caps_str = gst_caps_to_string(caps);
6980 LOGW("unknown type of caps : %s from %s",
6981 caps_str, GST_ELEMENT_NAME(elem));
6983 MMPLAYER_FREEIF(caps_str);
6985 /* There is no available codec. */
6986 _mmplayer_update_not_supported_codec_info(player, klass, mime);
6990 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6991 GstCaps *caps, gpointer data)
6993 mmplayer_t *player = (mmplayer_t *)data;
6994 const char *mime = NULL;
6995 gboolean ret = TRUE;
6997 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6998 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
7000 if (g_str_has_prefix(mime, "audio")) {
7001 GstStructure *caps_structure = NULL;
7002 gint samplerate = 0;
7004 gchar *caps_str = NULL;
7006 caps_structure = gst_caps_get_structure(caps, 0);
7007 gst_structure_get_int(caps_structure, "rate", &samplerate);
7008 gst_structure_get_int(caps_structure, "channels", &channels);
7010 if ((channels > 0 && samplerate == 0)) {
7011 LOGD("exclude audio...");
7015 caps_str = gst_caps_to_string(caps);
7016 /* set it directly because not sent by TAG */
7017 if (g_strrstr(caps_str, "mobile-xmf"))
7018 mm_player_set_attribute((MMHandleType)player, NULL,
7019 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7021 MMPLAYER_FREEIF(caps_str);
7022 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7023 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7024 LOGD("video is already linked, allow the stream switch");
7027 LOGD("video is already linked");
7031 LOGD("found new stream");
7038 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7040 gboolean ret = FALSE;
7041 GDBusConnection *conn = NULL;
7043 GVariant *result = NULL;
7044 const gchar *dbus_device_type = NULL;
7045 const gchar *dbus_ret = NULL;
7048 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7050 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7055 result = g_dbus_connection_call_sync(conn,
7056 "org.pulseaudio.Server",
7057 "/org/pulseaudio/StreamManager",
7058 "org.pulseaudio.StreamManager",
7059 "GetCurrentMediaRoutingPath",
7060 g_variant_new("(s)", "out"),
7061 G_VARIANT_TYPE("(ss)"),
7062 G_DBUS_CALL_FLAGS_NONE,
7066 if (!result || err) {
7067 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7072 /* device type is listed in stream-map.json at mmfw-sysconf */
7073 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7075 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7076 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7079 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7080 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7081 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7082 LOGD("audio offload is supportable");
7088 LOGD("audio offload is not supportable");
7091 g_variant_unref(result);
7093 g_object_unref(conn);
7098 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7100 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7101 gint64 position = 0;
7103 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7104 player->pipeline && player->pipeline->mainbin);
7106 MMPLAYER_CMD_LOCK(player);
7107 current_state = MMPLAYER_CURRENT_STATE(player);
7109 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7110 LOGW("getting current position failed in paused");
7112 _mmplayer_unrealize((MMHandleType)player);
7113 _mmplayer_realize((MMHandleType)player);
7115 _mmplayer_set_position((MMHandleType)player, position);
7117 /* async not to be blocked in streaming case */
7118 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7120 _mmplayer_pause((MMHandleType)player);
7122 if (current_state == MM_PLAYER_STATE_PLAYING)
7123 _mmplayer_start((MMHandleType)player);
7124 MMPLAYER_CMD_UNLOCK(player);
7126 LOGD("rebuilding audio pipeline is completed.");
7129 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7131 mmplayer_t *player = (mmplayer_t *)user_data;
7132 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7133 gboolean is_supportable = FALSE;
7135 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7136 LOGW("failed to get device type");
7138 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7140 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7141 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7142 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7143 LOGD("ignore this dev connected info");
7147 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7148 if (player->build_audio_offload == is_supportable) {
7149 LOGD("keep current pipeline without re-building");
7153 /* rebuild pipeline */
7154 LOGD("re-build pipeline - offload: %d", is_supportable);
7155 player->build_audio_offload = FALSE;
7156 __mmplayer_rebuild_audio_pipeline(player);
7162 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7164 unsigned int id = 0;
7166 if (player->audio_device_cb_id != 0) {
7167 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7171 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7172 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7173 LOGD("added device connected cb (%u)", id);
7174 player->audio_device_cb_id = id;
7176 LOGW("failed to add device connected cb");
7183 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7185 mmplayer_t *player = (mmplayer_t *)hplayer;
7188 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7189 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7191 *activated = player->build_audio_offload;
7193 LOGD("offload activated : %d", (int)*activated);
7196 return MM_ERROR_NONE;
7200 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7203 this function need to be updated according to the supported media format
7204 @see player->ini.audio_offload_media_format */
7206 if (__mmplayer_is_only_mp3_type(player->type)) {
7207 LOGD("offload supportable media format type");
7215 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7217 gboolean ret = FALSE;
7218 GstElementFactory *factory = NULL;
7221 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7223 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7224 if (!__mmplayer_is_offload_supported_type(player))
7227 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7228 LOGD("there is no audio offload sink");
7232 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7233 LOGW("there is no audio device type to support offload");
7237 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7239 LOGW("there is no installed audio offload sink element");
7242 gst_object_unref(factory);
7244 if (_mmplayer_acquire_hw_resource(player,
7245 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7246 LOGE("failed to acquire audio offload decoder resource");
7250 if (!__mmplayer_add_audio_device_connected_cb(player))
7253 if (!__mmplayer_is_audio_offload_device_type(player))
7256 LOGD("audio offload can be built");
7261 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7267 static GstAutoplugSelectResult
7268 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7270 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7271 int audio_offload = 0;
7273 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7274 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7276 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7277 LOGD("expose audio path to build offload output path");
7278 player->build_audio_offload = TRUE;
7279 /* update codec info */
7280 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7281 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7282 player->audiodec_linked = 1;
7284 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7288 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7289 And need to consider the multi-track audio content.
7290 There is no HW audio decoder in public. */
7292 /* set stream information */
7293 if (!player->audiodec_linked)
7294 _mmplayer_set_audio_attrs(player, caps);
7296 /* update codec info */
7297 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7298 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7299 player->audiodec_linked = 1;
7301 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7303 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7304 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7306 /* mark video decoder for acquire */
7307 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7308 LOGW("video decoder resource is already acquired, skip it.");
7309 ret = GST_AUTOPLUG_SELECT_SKIP;
7313 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7314 LOGE("failed to acquire video decoder resource");
7315 ret = GST_AUTOPLUG_SELECT_SKIP;
7318 player->interrupted_by_resource = FALSE;
7321 /* update codec info */
7322 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7323 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7324 player->videodec_linked = 1;
7332 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7333 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7335 #define DEFAULT_IDX 0xFFFF
7336 #define MIN_FACTORY_NUM 2
7337 mmplayer_t *player = (mmplayer_t *)data;
7338 GValueArray *new_factories = NULL;
7339 GValue val = { 0, };
7340 GstElementFactory *factory = NULL;
7341 const gchar *klass = NULL;
7342 gchar *factory_name = NULL;
7343 guint hw_dec_idx = DEFAULT_IDX;
7344 guint first_sw_dec_idx = DEFAULT_IDX;
7345 guint last_sw_dec_idx = DEFAULT_IDX;
7346 guint new_pos = DEFAULT_IDX;
7347 guint rm_pos = DEFAULT_IDX;
7348 int audio_codec_type;
7349 int video_codec_type;
7350 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7352 if (factories->n_values < MIN_FACTORY_NUM)
7355 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7356 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7359 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7361 for (int i = 0 ; i < factories->n_values ; i++) {
7362 gchar *hw_dec_info = NULL;
7363 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7365 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7367 LOGW("failed to get factory object");
7370 klass = gst_element_factory_get_klass(factory);
7371 factory_name = GST_OBJECT_NAME(factory);
7374 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7376 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7377 if (!player->need_audio_dec_sorting) {
7378 LOGD("sorting is not required");
7381 codec_type = audio_codec_type;
7382 hw_dec_info = player->ini.audiocodec_element_hw;
7383 sw_dec_info = player->ini.audiocodec_element_sw;
7384 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7385 if (!player->need_video_dec_sorting) {
7386 LOGD("sorting is not required");
7389 codec_type = video_codec_type;
7390 hw_dec_info = player->ini.videocodec_element_hw;
7391 sw_dec_info = player->ini.videocodec_element_sw;
7396 if (g_strrstr(factory_name, hw_dec_info)) {
7399 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7400 if (strstr(factory_name, sw_dec_info[j])) {
7401 last_sw_dec_idx = i;
7402 if (first_sw_dec_idx == DEFAULT_IDX) {
7403 first_sw_dec_idx = i;
7408 if (first_sw_dec_idx == DEFAULT_IDX)
7409 LOGW("unknown codec %s", factory_name);
7413 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7416 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7417 if (hw_dec_idx < first_sw_dec_idx)
7419 new_pos = first_sw_dec_idx;
7420 rm_pos = hw_dec_idx + 1;
7421 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7422 if (last_sw_dec_idx < hw_dec_idx)
7424 new_pos = last_sw_dec_idx + 1;
7425 rm_pos = hw_dec_idx;
7430 /* change position - insert H/W decoder according to the new position */
7431 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7433 LOGW("failed to get factory object");
7436 new_factories = g_value_array_copy(factories);
7437 g_value_init (&val, G_TYPE_OBJECT);
7438 g_value_set_object (&val, factory);
7439 g_value_array_insert(new_factories, new_pos, &val);
7440 g_value_unset (&val);
7441 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7443 for (int i = 0 ; i < new_factories->n_values ; i++) {
7444 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7446 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7447 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7449 LOGE("[Re-arranged] failed to get factory object");
7452 return new_factories;
7456 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7457 GstCaps *caps, GstElementFactory *factory, gpointer data)
7459 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7460 mmplayer_t *player = (mmplayer_t *)data;
7462 gchar *factory_name = NULL;
7463 gchar *caps_str = NULL;
7464 const gchar *klass = NULL;
7467 factory_name = GST_OBJECT_NAME(factory);
7468 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7469 caps_str = gst_caps_to_string(caps);
7471 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7473 /* store type string */
7474 if (player->type == NULL) {
7475 player->type = gst_caps_to_string(caps);
7476 __mmplayer_update_content_type_info(player);
7479 /* filtering exclude keyword */
7480 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7481 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7482 LOGW("skipping [%s] by exclude keyword [%s]",
7483 factory_name, player->ini.exclude_element_keyword[idx]);
7485 result = GST_AUTOPLUG_SELECT_SKIP;
7490 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7491 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7492 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7493 factory_name, player->ini.unsupported_codec_keyword[idx]);
7494 result = GST_AUTOPLUG_SELECT_SKIP;
7499 /* exclude webm format */
7500 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7501 * because webm format is not supportable.
7502 * If webm is disabled in "autoplug-continue", there is no state change
7503 * failure or error because the decodebin will expose the pad directly.
7504 * It make MSL invoke _prepare_async_callback.
7505 * So, we need to disable webm format in "autoplug-select" */
7506 if (caps_str && strstr(caps_str, "webm")) {
7507 LOGW("webm is not supported");
7508 result = GST_AUTOPLUG_SELECT_SKIP;
7512 /* check factory class for filtering */
7513 /* NOTE : msl don't need to use image plugins.
7514 * So, those plugins should be skipped for error handling.
7516 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7517 LOGD("skipping [%s] by not required", factory_name);
7518 result = GST_AUTOPLUG_SELECT_SKIP;
7522 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7523 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7524 // TO CHECK : subtitle if needed, add subparse exception.
7525 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7526 result = GST_AUTOPLUG_SELECT_SKIP;
7530 if (g_strrstr(factory_name, "mpegpsdemux")) {
7531 LOGD("skipping PS container - not support");
7532 result = GST_AUTOPLUG_SELECT_SKIP;
7536 if (g_strrstr(factory_name, "mssdemux"))
7537 player->smooth_streaming = TRUE;
7539 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7540 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7543 GstStructure *str = NULL;
7544 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7546 /* don't make video because of not required */
7547 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7548 (!player->set_mode.video_export)) {
7549 LOGD("no need video decoding, expose pad");
7550 result = GST_AUTOPLUG_SELECT_EXPOSE;
7554 /* get w/h for omx state-tune */
7555 /* FIXME: deprecated? */
7556 str = gst_caps_get_structure(caps, 0);
7557 gst_structure_get_int(str, "width", &width);
7560 if (player->v_stream_caps) {
7561 gst_caps_unref(player->v_stream_caps);
7562 player->v_stream_caps = NULL;
7565 player->v_stream_caps = gst_caps_copy(caps);
7566 LOGD("take caps for video state tune");
7567 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7571 if (g_strrstr(klass, "Codec/Decoder")) {
7572 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7573 if (result != GST_AUTOPLUG_SELECT_TRY) {
7574 LOGW("skip add decoder");
7580 MMPLAYER_FREEIF(caps_str);
7586 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7589 int ret = MM_ERROR_NONE;
7590 mmplayer_t *player = (mmplayer_t *)data;
7591 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7592 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7593 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7596 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7598 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7600 if (MMPLAYER_USE_DECODEBIN(player))
7603 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7606 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7608 __mmplayer_del_sink(player, videobin[MMPLAYER_V_SINK].gst);
7610 LOGD("remove videobin");
7611 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst,
7612 GST_STATE_NULL, FALSE, timeout);
7613 if (ret != MM_ERROR_NONE) {
7614 LOGE("fail to change state of videobin to NULL");
7618 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7619 LOGE("failed to remove videobin");
7620 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7623 LOGD("remove concat");
7624 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst,
7625 GST_STATE_NULL, FALSE, timeout);
7626 if (ret != MM_ERROR_NONE) {
7627 LOGE("fail to change state of concat to NULL");
7631 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7632 LOGE("failed to remove video concat");
7633 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7636 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7637 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7638 MMPLAYER_FREEIF(player->pipeline->videobin);
7640 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7641 if (ret != MM_ERROR_NONE)
7642 LOGE("failed to release overlay resources");
7644 player->videodec_linked = 0;
7646 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7651 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7653 mmplayer_t *player = (mmplayer_t *)data;
7656 MMPLAYER_RETURN_IF_FAIL(player);
7658 LOGD("got about to finish signal");
7660 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7661 LOGW("Fail to get cmd lock");
7665 if (!__mmplayer_verify_gapless_play_path(player)) {
7666 LOGD("decoding is finished.");
7667 MMPLAYER_CMD_UNLOCK(player);
7671 _mmplayer_set_reconfigure_state(player, TRUE);
7672 MMPLAYER_CMD_UNLOCK(player);
7674 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7675 __mmplayer_deactivate_old_path(player);
7681 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7683 mmplayer_t *player = (mmplayer_t *)data;
7684 GstIterator *iter = NULL;
7685 GValue item = { 0, };
7687 gboolean done = FALSE;
7688 gboolean is_all_drained = TRUE;
7691 MMPLAYER_RETURN_IF_FAIL(player);
7693 LOGD("got drained signal");
7695 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7696 LOGW("Fail to get cmd lock");
7700 if (!__mmplayer_verify_gapless_play_path(player)) {
7701 LOGD("decoding is finished.");
7702 MMPLAYER_CMD_UNLOCK(player);
7706 _mmplayer_set_reconfigure_state(player, TRUE);
7707 MMPLAYER_CMD_UNLOCK(player);
7709 /* check decodebin src pads whether they received EOS or not */
7710 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7713 switch (gst_iterator_next(iter, &item)) {
7714 case GST_ITERATOR_OK:
7715 pad = g_value_get_object(&item);
7716 if (pad && !GST_PAD_IS_EOS(pad)) {
7717 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7718 is_all_drained = FALSE;
7721 g_value_reset(&item);
7723 case GST_ITERATOR_RESYNC:
7724 gst_iterator_resync(iter);
7726 case GST_ITERATOR_ERROR:
7727 case GST_ITERATOR_DONE:
7732 g_value_unset(&item);
7733 gst_iterator_free(iter);
7735 if (!is_all_drained) {
7736 LOGD("Wait util the all pads get EOS.");
7741 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7742 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7744 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7745 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7746 __mmplayer_deactivate_old_path(player);
7752 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7754 mmplayer_t *player = (mmplayer_t *)data;
7755 const gchar *klass = NULL;
7756 gchar *factory_name = NULL;
7758 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7759 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7761 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7763 if (__mmplayer_add_dump_buffer_probe(player, element))
7764 LOGD("add buffer probe");
7766 if (g_strrstr(klass, "Decoder")) {
7767 if (g_strrstr(klass, "Audio")) {
7768 player->audio_decoders = g_list_append(player->audio_decoders,
7769 g_strdup(GST_ELEMENT_NAME(element)));
7771 /* update codec info */
7772 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7773 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7774 player->audiodec_linked = 1;
7775 } else if (g_strrstr(klass, "Video")) {
7776 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7777 /* update codec info */
7778 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7779 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7780 player->videodec_linked = 1;
7783 GstPad *srcpad = gst_element_get_static_pad (video_parse, "src");
7785 GstCaps *caps = NULL;
7786 GstStructure *str = NULL;
7787 const gchar *name = NULL;
7788 gboolean caps_ret = TRUE;
7790 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD (srcpad, caps, str, name, caps_ret);
7791 if (caps_ret && str) {
7792 const gchar *stream_format = gst_structure_get_string (str, "stream-format");
7793 if (stream_format && g_strrstr(stream_format, "byte-stream")) {
7794 if ((g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7795 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7796 LOGD("Send SPS and PPS Insertion every IDR frame");
7800 gst_object_unref(GST_OBJECT(srcpad));
7804 } else if (g_strrstr(klass, "Demuxer")) {
7805 if (g_strrstr(klass, "Adaptive")) {
7806 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7807 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7809 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7810 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7812 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7813 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7814 "max-video-width", player->adaptive_info.limit.width,
7815 "max-video-height", player->adaptive_info.limit.height, NULL);
7818 LOGD("plugged element is demuxer. take it");
7820 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7821 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7823 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7824 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7825 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7828 if (g_strrstr(factory_name, "mpegaudioparse")) {
7829 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7830 (__mmplayer_is_only_mp3_type(player->type))) {
7831 LOGD("[mpegaudioparse] set streaming pull mode.");
7832 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7834 } else if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7835 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7836 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7838 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7839 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7841 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7842 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7843 (MMPLAYER_IS_DASH_STREAMING(player))) {
7844 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7845 _mm_player_streaming_set_multiqueue(player->streamer, element);
7846 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7854 __mmplayer_release_misc(mmplayer_t *player)
7857 bool cur_mode = player->set_mode.rich_audio;
7860 MMPLAYER_RETURN_IF_FAIL(player);
7862 player->sent_bos = FALSE;
7863 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7865 player->seek_state = MMPLAYER_SEEK_NONE;
7867 player->total_bitrate = 0;
7868 player->total_maximum_bitrate = 0;
7870 player->not_found_demuxer = 0;
7872 player->last_position = 0;
7873 player->duration = 0;
7874 player->http_content_size = 0;
7875 player->not_supported_codec = MISSING_PLUGIN_NONE;
7876 player->can_support_codec = FOUND_PLUGIN_NONE;
7877 player->pending_seek.is_pending = false;
7878 player->pending_seek.pos = 0;
7879 player->msg_posted = FALSE;
7880 player->has_many_types = FALSE;
7881 player->is_subtitle_force_drop = FALSE;
7882 player->play_subtitle = FALSE;
7883 player->adjust_subtitle_pos = 0;
7884 player->has_closed_caption = FALSE;
7885 player->set_mode.video_export = false;
7886 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7887 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7889 player->set_mode.rich_audio = cur_mode;
7891 if (player->audio_device_cb_id > 0 &&
7892 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7893 LOGW("failed to remove audio device_connected_callback");
7894 player->audio_device_cb_id = 0;
7896 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7897 player->bitrate[i] = 0;
7898 player->maximum_bitrate[i] = 0;
7901 /* free memory related to audio effect */
7902 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7904 if (player->adaptive_info.var_list) {
7905 g_list_free_full(player->adaptive_info.var_list, g_free);
7906 player->adaptive_info.var_list = NULL;
7909 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7910 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7911 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7913 /* Reset video360 settings to their defaults in case if the pipeline is to be
7916 player->video360_metadata.is_spherical = -1;
7917 player->is_openal_plugin_used = FALSE;
7919 player->is_content_spherical = FALSE;
7920 player->is_video360_enabled = TRUE;
7921 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7922 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7923 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7924 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7925 player->video360_zoom = 1.0f;
7926 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7927 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7929 player->sound.rg_enable = false;
7931 __mmplayer_initialize_video_roi(player);
7936 __mmplayer_release_misc_post(mmplayer_t *player)
7938 gchar *original_uri = NULL;
7941 /* player->pipeline is already released before. */
7942 MMPLAYER_RETURN_IF_FAIL(player);
7944 player->video_decoded_cb = NULL;
7945 player->video_decoded_cb_user_param = NULL;
7946 player->video_stream_prerolled = false;
7948 player->audio_decoded_cb = NULL;
7949 player->audio_decoded_cb_user_param = NULL;
7950 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7952 player->audio_stream_changed_cb = NULL;
7953 player->audio_stream_changed_cb_user_param = NULL;
7955 mm_player_set_attribute((MMHandleType)player, NULL,
7956 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7958 /* clean found audio decoders */
7959 if (player->audio_decoders) {
7960 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7961 player->audio_decoders = NULL;
7964 /* clean the uri list except original uri */
7965 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7967 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7968 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7969 g_list_free_full(tmp, (GDestroyNotify)g_free);
7972 LOGW("failed to get original uri info");
7974 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7975 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7976 MMPLAYER_FREEIF(original_uri);
7979 /* clear the audio stream buffer list */
7980 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7982 /* clear the video stream bo list */
7983 __mmplayer_video_stream_destroy_bo_list(player);
7984 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7986 if (player->profile.input_mem.buf) {
7987 free(player->profile.input_mem.buf);
7988 player->profile.input_mem.buf = NULL;
7990 player->profile.input_mem.len = 0;
7991 player->profile.input_mem.offset = 0;
7993 player->uri_info.uri_idx = 0;
7998 __mmplayer_check_subtitle(mmplayer_t *player)
8000 MMHandleType attrs = 0;
8001 char *subtitle_uri = NULL;
8005 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8007 /* get subtitle attribute */
8008 attrs = MMPLAYER_GET_ATTRS(player);
8012 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8013 if (!subtitle_uri || !strlen(subtitle_uri))
8016 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
8017 player->is_external_subtitle_present = TRUE;
8025 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8027 MMPLAYER_RETURN_IF_FAIL(player);
8029 if (player->eos_timer) {
8030 LOGD("cancel eos timer");
8031 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8032 player->eos_timer = 0;
8039 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8043 MMPLAYER_RETURN_IF_FAIL(player);
8044 MMPLAYER_RETURN_IF_FAIL(sink);
8047 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8049 player->sink_elements = g_list_append(player->sink_elements, sink);
8055 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8059 MMPLAYER_RETURN_IF_FAIL(player);
8060 MMPLAYER_RETURN_IF_FAIL(sink);
8062 player->sink_elements = g_list_remove(player->sink_elements, sink);
8068 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8069 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8071 mmplayer_signal_item_t *item = NULL;
8074 MMPLAYER_RETURN_IF_FAIL(player);
8076 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8077 LOGE("invalid signal type [%d]", type);
8081 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8083 LOGE("cannot connect signal [%s]", signal);
8088 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8089 player->signals[type] = g_list_append(player->signals[type], item);
8095 /* NOTE : be careful with calling this api. please refer to below glib comment
8096 * glib comment : Note that there is a bug in GObject that makes this function much
8097 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8098 * will no longer be called, but, the signal handler is not currently disconnected.
8099 * If the instance is itself being freed at the same time than this doesn't matter,
8100 * since the signal will automatically be removed, but if instance persists,
8101 * then the signal handler will leak. You should not remove the signal yourself
8102 * because in a future versions of GObject, the handler will automatically be
8105 * It's possible to work around this problem in a way that will continue to work
8106 * with future versions of GObject by checking that the signal handler is still
8107 * connected before disconnected it:
8109 * if (g_signal_handler_is_connected(instance, id))
8110 * g_signal_handler_disconnect(instance, id);
8113 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8115 GList *sig_list = NULL;
8116 mmplayer_signal_item_t *item = NULL;
8120 MMPLAYER_RETURN_IF_FAIL(player);
8122 LOGD("release signals type : %d", type);
8124 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8125 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8126 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8127 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8128 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8129 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8133 sig_list = player->signals[type];
8135 for (; sig_list; sig_list = sig_list->next) {
8136 item = sig_list->data;
8138 if (item && item->obj) {
8139 if (g_signal_handler_is_connected(item->obj, item->sig))
8140 g_signal_handler_disconnect(item->obj, item->sig);
8143 MMPLAYER_FREEIF(item);
8146 g_list_free(player->signals[type]);
8147 player->signals[type] = NULL;
8155 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8157 mmplayer_t *player = 0;
8158 int prev_display_surface_type = 0;
8162 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8164 player = MM_PLAYER_CAST(handle);
8166 /* check video sinkbin is created */
8167 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8168 LOGW("Videosink is already created");
8169 return MM_ERROR_NONE;
8172 LOGD("videosink element is not yet ready");
8174 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8175 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8177 return MM_ERROR_INVALID_ARGUMENT;
8180 /* load previous attributes */
8181 if (player->attrs) {
8182 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8183 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8184 if (prev_display_surface_type == surface_type) {
8185 LOGD("incoming display surface type is same as previous one, do nothing..");
8187 return MM_ERROR_NONE;
8190 LOGE("failed to load attributes");
8192 return MM_ERROR_PLAYER_INTERNAL;
8195 /* videobin is not created yet, so we just set attributes related to display surface */
8196 LOGD("store display attribute for given surface type(%d)", surface_type);
8197 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8198 "display_overlay", wl_surface_id, NULL);
8201 return MM_ERROR_NONE;
8204 /* Note : if silent is true, then subtitle would not be displayed. :*/
8206 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8208 mmplayer_t *player = (mmplayer_t *)hplayer;
8212 /* check player handle */
8213 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8215 player->set_mode.subtitle_off = silent;
8217 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8221 return MM_ERROR_NONE;
8225 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8227 mmplayer_gst_element_t *mainbin = NULL;
8228 mmplayer_gst_element_t *textbin = NULL;
8229 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8230 GstState current_state = GST_STATE_VOID_PENDING;
8231 GstState element_state = GST_STATE_VOID_PENDING;
8232 GstState element_pending_state = GST_STATE_VOID_PENDING;
8234 GstEvent *event = NULL;
8235 int result = MM_ERROR_NONE;
8237 GstClock *curr_clock = NULL;
8238 GstClockTime base_time, start_time, curr_time;
8243 /* check player handle */
8244 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8246 player->pipeline->mainbin &&
8247 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8249 mainbin = player->pipeline->mainbin;
8250 textbin = player->pipeline->textbin;
8252 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8254 // sync clock with current pipeline
8255 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8256 curr_time = gst_clock_get_time(curr_clock);
8258 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8259 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8261 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8262 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8264 if (current_state > GST_STATE_READY) {
8265 // sync state with current pipeline
8266 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8267 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8268 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8270 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8271 if (GST_STATE_CHANGE_FAILURE == ret) {
8272 LOGE("fail to state change.");
8273 result = MM_ERROR_PLAYER_INTERNAL;
8277 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8278 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8281 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8282 gst_object_unref(curr_clock);
8285 // seek to current position
8286 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8287 result = MM_ERROR_PLAYER_INVALID_STATE;
8288 LOGE("gst_element_query_position failed, invalid state");
8292 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8293 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);
8295 _mmplayer_gst_send_event_to_sink(player, event);
8297 result = MM_ERROR_PLAYER_INTERNAL;
8298 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8302 /* sync state with current pipeline */
8303 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8304 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8305 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8307 return MM_ERROR_NONE;
8310 /* release text pipeline resource */
8311 player->textsink_linked = 0;
8313 /* release signal */
8314 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8316 /* release textbin with it's children */
8317 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8318 MMPLAYER_FREEIF(player->pipeline->textbin);
8319 player->pipeline->textbin = NULL;
8321 /* release subtitle elem */
8322 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8323 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8329 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8331 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8332 GstState current_state = GST_STATE_VOID_PENDING;
8334 MMHandleType attrs = 0;
8335 mmplayer_gst_element_t *mainbin = NULL;
8336 mmplayer_gst_element_t *textbin = NULL;
8338 gchar *subtitle_uri = NULL;
8339 int result = MM_ERROR_NONE;
8340 const gchar *charset = NULL;
8344 /* check player handle */
8345 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8347 player->pipeline->mainbin &&
8348 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8349 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8351 mainbin = player->pipeline->mainbin;
8352 textbin = player->pipeline->textbin;
8354 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8355 if (current_state < GST_STATE_READY) {
8356 result = MM_ERROR_PLAYER_INVALID_STATE;
8357 LOGE("Pipeline is not in proper state");
8361 attrs = MMPLAYER_GET_ATTRS(player);
8363 LOGE("cannot get content attribute");
8364 result = MM_ERROR_PLAYER_INTERNAL;
8368 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8369 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8370 LOGE("subtitle uri is not proper filepath");
8371 result = MM_ERROR_PLAYER_INVALID_URI;
8375 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8376 LOGE("failed to get storage info of subtitle path");
8377 result = MM_ERROR_PLAYER_INVALID_URI;
8381 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8382 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8384 if (!strcmp(filepath, subtitle_uri)) {
8385 LOGD("subtitle path is not changed");
8388 if (mm_player_set_attribute((MMHandleType)player, NULL,
8389 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8390 LOGE("failed to set attribute");
8395 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8396 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8397 player->subtitle_language_list = NULL;
8398 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8400 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8401 if (ret != GST_STATE_CHANGE_SUCCESS) {
8402 LOGE("failed to change state of textbin to READY");
8403 result = MM_ERROR_PLAYER_INTERNAL;
8407 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8408 if (ret != GST_STATE_CHANGE_SUCCESS) {
8409 LOGE("failed to change state of subparse to READY");
8410 result = MM_ERROR_PLAYER_INTERNAL;
8414 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8415 if (ret != GST_STATE_CHANGE_SUCCESS) {
8416 LOGE("failed to change state of filesrc to READY");
8417 result = MM_ERROR_PLAYER_INTERNAL;
8421 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8423 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8425 charset = _mmplayer_get_charset(filepath);
8427 LOGD("detected charset is %s", charset);
8428 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8431 result = _mmplayer_sync_subtitle_pipeline(player);
8438 /* API to switch between external subtitles */
8440 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8442 int result = MM_ERROR_NONE;
8443 mmplayer_t *player = (mmplayer_t *)hplayer;
8448 /* check player handle */
8449 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8451 /* filepath can be null in idle state */
8453 /* check file path */
8454 if ((path = strstr(filepath, "file://")))
8455 result = _mmplayer_exist_file_path(path + 7);
8457 result = _mmplayer_exist_file_path(filepath);
8459 if (result != MM_ERROR_NONE) {
8460 LOGE("invalid subtitle path 0x%X", result);
8461 return result; /* file not found or permission denied */
8465 if (!player->pipeline) {
8467 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8468 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8469 LOGE("failed to set attribute");
8470 return MM_ERROR_PLAYER_INTERNAL;
8473 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8474 /* check filepath */
8475 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8477 if (!__mmplayer_check_subtitle(player)) {
8478 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8479 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8480 LOGE("failed to set attribute");
8481 return MM_ERROR_PLAYER_INTERNAL;
8484 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8485 LOGE("fail to create text pipeline");
8486 return MM_ERROR_PLAYER_INTERNAL;
8489 result = _mmplayer_sync_subtitle_pipeline(player);
8491 result = __mmplayer_change_external_subtitle_language(player, filepath);
8494 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8495 player->is_external_subtitle_added_now = TRUE;
8497 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8498 if (!player->subtitle_language_list) {
8499 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8500 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8501 LOGW("subtitle language list is not updated yet");
8503 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8511 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8513 guint active_idx = 0;
8514 GstStream *stream = NULL;
8515 GList *streams = NULL;
8516 GstCaps *caps = NULL;
8519 LOGD("Switching Streams... type: %d, index: %d", type, index);
8521 player->track[type].active_track_index = index;
8523 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8524 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8525 LOGD("track type:%d, total: %d, active: %d", i,
8526 player->track[i].total_track_num, player->track[i].active_track_index);
8527 if (player->track[i].total_track_num > 0 &&
8528 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8529 active_idx = player->track[i].active_track_index;
8530 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8531 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8532 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8534 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8535 caps = gst_stream_get_caps(stream);
8537 _mmplayer_set_audio_attrs(player, caps);
8538 gst_caps_unref(caps);
8545 LOGD("send select stream event");
8546 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8547 gst_event_new_select_streams(streams));
8548 g_list_free(streams);
8551 /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8552 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8553 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8555 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8556 pos_nsec = player->last_position;
8558 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8560 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8561 player->playback_rate, GST_FORMAT_TIME,
8562 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8563 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8564 LOGW("failed to seek");
8565 return MM_ERROR_PLAYER_INTERNAL;
8570 return MM_ERROR_NONE;
8574 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8576 int result = MM_ERROR_NONE;
8577 gchar *change_pad_name = NULL;
8578 GstPad *sinkpad = NULL;
8579 mmplayer_gst_element_t *mainbin = NULL;
8580 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8581 GstCaps *caps = NULL;
8582 gint total_track_num = 0;
8586 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8587 MM_ERROR_PLAYER_NOT_INITIALIZED);
8589 LOGD("Change Track(%d) to %d", type, index);
8591 mainbin = player->pipeline->mainbin;
8593 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8594 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8595 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8596 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8598 /* Changing Video Track is not supported. */
8599 LOGE("Track Type Error");
8603 if (mainbin[elem_idx].gst == NULL) {
8604 result = MM_ERROR_PLAYER_NO_OP;
8605 LOGD("Req track doesn't exist");
8609 total_track_num = player->track[type].total_track_num;
8610 if (total_track_num <= 0) {
8611 result = MM_ERROR_PLAYER_NO_OP;
8612 LOGD("Language list is not available");
8616 if ((index < 0) || (index >= total_track_num)) {
8617 result = MM_ERROR_INVALID_ARGUMENT;
8618 LOGD("Not a proper index : %d", index);
8622 /*To get the new pad from the selector*/
8623 change_pad_name = g_strdup_printf("sink_%u", index);
8624 if (change_pad_name == NULL) {
8625 result = MM_ERROR_PLAYER_INTERNAL;
8626 LOGD("Pad does not exists");
8630 LOGD("new active pad name: %s", change_pad_name);
8632 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8633 if (sinkpad == NULL) {
8634 LOGD("sinkpad is NULL");
8635 result = MM_ERROR_PLAYER_INTERNAL;
8639 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8640 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8642 caps = gst_pad_get_current_caps(sinkpad);
8643 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8646 gst_object_unref(sinkpad);
8648 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8649 _mmplayer_set_audio_attrs(player, caps);
8652 gst_caps_unref(caps);
8655 MMPLAYER_FREEIF(change_pad_name);
8660 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8662 int result = MM_ERROR_NONE;
8663 mmplayer_t *player = NULL;
8664 mmplayer_gst_element_t *mainbin = NULL;
8666 gint current_active_index = 0;
8668 GstState current_state = GST_STATE_VOID_PENDING;
8673 player = (mmplayer_t *)hplayer;
8674 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8676 if (!player->pipeline) {
8677 LOGE("Track %d pre setting -> %d", type, index);
8679 player->track[type].active_track_index = index;
8683 mainbin = player->pipeline->mainbin;
8685 current_active_index = player->track[type].active_track_index;
8687 /*If index is same as running index no need to change the pad*/
8688 if (current_active_index == index)
8691 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8692 result = MM_ERROR_PLAYER_INVALID_STATE;
8696 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8697 if (current_state < GST_STATE_PAUSED) {
8698 result = MM_ERROR_PLAYER_INVALID_STATE;
8699 LOGW("Pipeline not in proper state");
8703 if (MMPLAYER_USE_DECODEBIN(player))
8704 result = __mmplayer_change_selector_pad(player, type, index);
8706 result = __mmplayer_switch_stream(player, type, index);
8708 if (result != MM_ERROR_NONE) {
8709 LOGE("failed to change track");
8713 player->track[type].active_track_index = index;
8715 if (MMPLAYER_USE_DECODEBIN(player)) {
8716 GstEvent *event = NULL;
8717 if (current_state == GST_STATE_PLAYING) {
8718 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8719 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8720 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8722 _mmplayer_gst_send_event_to_sink(player, event);
8724 result = MM_ERROR_PLAYER_INTERNAL;
8735 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8737 mmplayer_t *player = (mmplayer_t *)hplayer;
8741 /* check player handle */
8742 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8744 *silent = player->set_mode.subtitle_off;
8746 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8750 return MM_ERROR_NONE;
8754 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8756 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8757 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8759 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8760 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8764 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8765 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8766 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8767 mmplayer_dump_t *dump_s;
8768 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8769 if (dump_s == NULL) {
8770 LOGE("malloc fail");
8774 dump_s->dump_element_file = NULL;
8775 dump_s->dump_pad = NULL;
8776 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8778 if (dump_s->dump_pad) {
8779 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8780 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]);
8781 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8782 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);
8783 /* add list for removed buffer probe and close FILE */
8784 player->dump_list = g_list_append(player->dump_list, dump_s);
8785 LOGD("%s sink pad added buffer probe for dump", factory_name);
8788 MMPLAYER_FREEIF(dump_s);
8789 LOGE("failed to get %s sink pad added", factory_name);
8796 static GstPadProbeReturn
8797 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8799 FILE *dump_data = (FILE *)u_data;
8801 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8802 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8804 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8806 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8808 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8810 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8812 gst_buffer_unmap(buffer, &probe_info);
8814 return GST_PAD_PROBE_OK;
8818 __mmplayer_release_dump_list(GList *dump_list)
8820 GList *d_list = dump_list;
8825 for (; d_list; d_list = g_list_next(d_list)) {
8826 mmplayer_dump_t *dump_s = d_list->data;
8827 if (dump_s->dump_pad) {
8828 if (dump_s->probe_handle_id)
8829 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8830 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8832 if (dump_s->dump_element_file) {
8833 fclose(dump_s->dump_element_file);
8834 dump_s->dump_element_file = NULL;
8836 MMPLAYER_FREEIF(dump_s);
8838 g_list_free(dump_list);
8843 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8845 mmplayer_t *player = (mmplayer_t *)hplayer;
8849 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8850 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8852 *exist = (bool)player->has_closed_caption;
8856 return MM_ERROR_NONE;
8860 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8865 LOGD("unref internal gst buffer %p", buffer);
8867 gst_buffer_unref((GstBuffer *)buffer);
8874 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8876 mmplayer_t *player = (mmplayer_t *)hplayer;
8880 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8881 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8883 if (MMPLAYER_IS_STREAMING(player))
8884 *timeout = (int)player->ini.live_state_change_timeout;
8886 *timeout = (int)player->ini.localplayback_state_change_timeout;
8888 LOGD("timeout = %d", *timeout);
8891 return MM_ERROR_NONE;
8895 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8899 MMPLAYER_RETURN_IF_FAIL(player);
8901 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8903 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8904 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8905 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8906 player->storage_info[i].id = -1;
8907 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8909 if (path_type != MMPLAYER_PATH_MAX)
8918 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8920 int ret = MM_ERROR_NONE;
8921 mmplayer_t *player = (mmplayer_t *)hplayer;
8922 MMMessageParamType msg_param = {0, };
8925 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8927 LOGW("state changed storage %d:%d", id, state);
8929 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8930 return MM_ERROR_NONE;
8932 /* FIXME: text path should be handled separately. */
8933 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8934 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8935 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8936 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8937 LOGW("external storage is removed");
8939 if (player->msg_posted == FALSE) {
8940 memset(&msg_param, 0, sizeof(MMMessageParamType));
8941 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8942 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8943 player->msg_posted = TRUE;
8946 /* unrealize the player */
8947 ret = _mmplayer_unrealize(hplayer);
8948 if (ret != MM_ERROR_NONE)
8949 LOGE("failed to unrealize");
8957 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8959 int ret = MM_ERROR_NONE;
8960 mmplayer_t *player = (mmplayer_t *)hplayer;
8961 int idx = 0, total = 0;
8962 gchar *result = NULL, *tmp = NULL;
8965 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8966 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8968 total = *num = g_list_length(player->adaptive_info.var_list);
8970 LOGW("There is no stream variant info.");
8974 result = g_strdup("");
8975 for (idx = 0 ; idx < total ; idx++) {
8976 stream_variant_t *v_data = NULL;
8977 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8980 gchar data[64] = {0};
8981 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8983 tmp = g_strconcat(result, data, NULL);
8987 LOGW("There is no variant data in %d", idx);
8992 *var_info = (char *)result;
8994 LOGD("variant info %d:%s", *num, *var_info);
9000 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
9002 int ret = MM_ERROR_NONE;
9003 mmplayer_t *player = (mmplayer_t *)hplayer;
9006 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9008 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9010 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9011 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9012 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9014 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9015 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9016 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9017 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9019 /* FIXME: seek to current position for applying new variant limitation */
9028 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9030 int ret = MM_ERROR_NONE;
9031 mmplayer_t *player = (mmplayer_t *)hplayer;
9034 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9035 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9037 *bandwidth = player->adaptive_info.limit.bandwidth;
9038 *width = player->adaptive_info.limit.width;
9039 *height = player->adaptive_info.limit.height;
9041 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9048 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9050 int ret = MM_ERROR_NONE;
9051 mmplayer_t *player = (mmplayer_t *)hplayer;
9054 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9055 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9056 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9058 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9060 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9061 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9062 else /* live case */
9063 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9065 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9072 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9074 #define IDX_FIRST_SW_CODEC 0
9075 mmplayer_t *player = (mmplayer_t *)hplayer;
9076 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9077 const char *attr_name = NULL;
9078 const char *default_type = NULL;
9079 const char *element_hw = NULL;
9080 const char *element_sw = NULL;
9083 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9085 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9087 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9088 switch (stream_type) {
9089 case MM_PLAYER_STREAM_TYPE_AUDIO:
9090 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9091 default_type = player->ini.audiocodec_default_type;
9092 element_hw = player->ini.audiocodec_element_hw;
9093 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9095 case MM_PLAYER_STREAM_TYPE_VIDEO:
9096 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9097 default_type = player->ini.videocodec_default_type;
9098 element_hw = player->ini.videocodec_element_hw;
9099 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9102 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9103 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9107 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9109 if (!strcmp(default_type, "sw"))
9110 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9112 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9114 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9115 codec_type = default_codec_type;
9117 /* to support codec selection, codec info have to be added in ini file.
9118 in case of hw codec is selected, filter elements should be applied
9119 depending on the hw capabilities. */
9120 if (codec_type != default_codec_type) {
9121 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9122 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9123 LOGE("There is no codec for type %d", codec_type);
9124 return MM_ERROR_PLAYER_NO_OP;
9127 LOGD("sorting is required");
9128 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9129 player->need_audio_dec_sorting = TRUE;
9131 player->need_video_dec_sorting = TRUE;
9134 LOGD("update %s codec_type to %d", attr_name, codec_type);
9135 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9138 return MM_ERROR_NONE;
9142 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9144 mmplayer_t *player = (mmplayer_t *)hplayer;
9145 GstElement *rg_vol_element = NULL;
9149 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9151 player->sound.rg_enable = enabled;
9153 /* just hold rgvolume enable value if pipeline is not ready */
9154 if (!player->pipeline || !player->pipeline->audiobin) {
9155 LOGD("pipeline is not ready. holding rgvolume enable value");
9156 return MM_ERROR_NONE;
9159 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9161 if (!rg_vol_element) {
9162 LOGD("rgvolume element is not created");
9163 return MM_ERROR_PLAYER_INTERNAL;
9167 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9169 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9173 return MM_ERROR_NONE;
9177 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9179 mmplayer_t *player = (mmplayer_t *)hplayer;
9180 GstElement *rg_vol_element = NULL;
9181 gboolean enable = FALSE;
9185 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9186 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9188 /* just hold enable_rg value if pipeline is not ready */
9189 if (!player->pipeline || !player->pipeline->audiobin) {
9190 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9191 *enabled = player->sound.rg_enable;
9192 return MM_ERROR_NONE;
9195 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9197 if (!rg_vol_element) {
9198 LOGD("rgvolume element is not created");
9199 return MM_ERROR_PLAYER_INTERNAL;
9202 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9203 *enabled = (bool)enable;
9207 return MM_ERROR_NONE;
9211 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9213 mmplayer_t *player = (mmplayer_t *)hplayer;
9214 MMHandleType attrs = 0;
9216 int ret = MM_ERROR_NONE;
9220 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9222 attrs = MMPLAYER_GET_ATTRS(player);
9223 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9225 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9227 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9228 return MM_ERROR_PLAYER_INTERNAL;
9231 player->video_roi.scale_x = scale_x;
9232 player->video_roi.scale_y = scale_y;
9233 player->video_roi.scale_width = scale_width;
9234 player->video_roi.scale_height = scale_height;
9236 /* check video sinkbin is created */
9237 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9238 return MM_ERROR_NONE;
9240 if (!gst_video_overlay_set_video_roi_area(
9241 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9242 scale_x, scale_y, scale_width, scale_height))
9243 ret = MM_ERROR_PLAYER_INTERNAL;
9245 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9246 scale_x, scale_y, scale_width, scale_height);
9254 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9256 mmplayer_t *player = (mmplayer_t *)hplayer;
9257 int ret = MM_ERROR_NONE;
9261 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9262 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9264 *scale_x = player->video_roi.scale_x;
9265 *scale_y = player->video_roi.scale_y;
9266 *scale_width = player->video_roi.scale_width;
9267 *scale_height = player->video_roi.scale_height;
9269 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9270 *scale_x, *scale_y, *scale_width, *scale_height);
9276 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9278 mmplayer_t *player = (mmplayer_t *)hplayer;
9282 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9284 player->client_pid = pid;
9286 LOGD("client pid[%d] %p", pid, player);
9290 return MM_ERROR_NONE;
9294 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9296 mmplayer_t *player = (mmplayer_t *)hplayer;
9297 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9298 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9302 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9303 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9306 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9308 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9310 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9311 return MM_ERROR_NONE;
9313 /* in case of audio codec default type is HW */
9315 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9316 if (player->ini.support_audio_effect)
9317 return MM_ERROR_NONE;
9318 elem_id = MMPLAYER_A_FILTER;
9320 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9321 if (player->ini.support_replaygain_control)
9322 return MM_ERROR_NONE;
9323 elem_id = MMPLAYER_A_RGVOL;
9325 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9326 if (player->ini.support_pitch_control)
9327 return MM_ERROR_NONE;
9328 elem_id = MMPLAYER_A_PITCH;
9330 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9331 if (player->ini.support_audio_effect)
9332 return MM_ERROR_NONE;
9334 /* default case handling is not required */
9337 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9338 LOGW("audio control option [%d] is not available", opt);
9341 /* setting pcm exporting option is allowed before READY state */
9342 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9343 return MM_ERROR_PLAYER_INVALID_STATE;
9345 /* check whether the audio filter exist or not after READY state,
9346 because the sw codec could be added during auto-plugging in some cases */
9347 if (!player->pipeline ||
9348 !player->pipeline->audiobin ||
9349 !player->pipeline->audiobin[elem_id].gst) {
9350 LOGW("there is no audio elem [%d]", elem_id);
9355 LOGD("audio control opt %d, available %d", opt, *available);
9359 return MM_ERROR_NONE;
9363 __mmplayer_update_duration_value(mmplayer_t *player)
9365 gboolean ret = FALSE;
9366 gint64 dur_nsec = 0;
9367 LOGD("try to update duration");
9369 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9370 player->duration = dur_nsec;
9371 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9375 if (player->duration < 0) {
9376 LOGW("duration is Non-Initialized !!!");
9377 player->duration = 0;
9380 /* update streaming service type */
9381 player->streaming_type = _mmplayer_get_stream_service_type(player);
9383 /* check duration is OK */
9384 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9385 /* FIXIT : find another way to get duration here. */
9386 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9392 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9394 /* update audio params
9395 NOTE : We need original audio params and it can be only obtained from src pad of audio
9396 decoder. Below code only valid when we are not using 'resampler' just before
9397 'audioconverter'. */
9398 GstCaps *caps_a = NULL;
9400 gint samplerate = 0, channels = 0;
9401 GstStructure *p = NULL;
9402 GstElement *aconv = NULL;
9404 LOGD("try to update audio attrs");
9406 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9408 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9409 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9410 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9411 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9413 LOGE("there is no audio converter");
9417 pad = gst_element_get_static_pad(aconv, "sink");
9420 LOGW("failed to get pad from audio converter");
9424 caps_a = gst_pad_get_current_caps(pad);
9426 LOGW("not ready to get audio caps");
9427 gst_object_unref(pad);
9431 p = gst_caps_get_structure(caps_a, 0);
9432 gst_structure_get_int(p, "rate", &samplerate);
9433 gst_structure_get_int(p, "channels", &channels);
9435 mm_player_set_attribute((MMHandleType)player, NULL,
9436 "content_audio_samplerate", samplerate,
9437 "content_audio_channels", channels, NULL);
9439 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9441 gst_caps_unref(caps_a);
9442 gst_object_unref(pad);
9448 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9450 LOGD("try to update video attrs");
9452 GstCaps *caps_v = NULL;
9456 GstStructure *p = NULL;
9458 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9459 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9461 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9463 LOGD("no videosink sink pad");
9467 caps_v = gst_pad_get_current_caps(pad);
9468 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9469 if (!caps_v && player->v_stream_caps) {
9470 caps_v = player->v_stream_caps;
9471 gst_caps_ref(caps_v);
9475 LOGD("no negotiated caps from videosink");
9476 gst_object_unref(pad);
9480 p = gst_caps_get_structure(caps_v, 0);
9481 gst_structure_get_int(p, "width", &width);
9482 gst_structure_get_int(p, "height", &height);
9484 mm_player_set_attribute((MMHandleType)player, NULL,
9485 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9487 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9489 SECURE_LOGD("width : %d height : %d", width, height);
9491 gst_caps_unref(caps_v);
9492 gst_object_unref(pad);
9495 mm_player_set_attribute((MMHandleType)player, NULL,
9496 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9497 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9504 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9506 gboolean ret = FALSE;
9507 guint64 data_size = 0;
9511 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9512 if (!player->duration)
9515 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9516 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9517 if (stat(path, &sb) == 0)
9518 data_size = (guint64)sb.st_size;
9520 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9521 data_size = player->http_content_size;
9524 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9527 guint64 bitrate = 0;
9528 guint64 msec_dur = 0;
9530 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9532 bitrate = data_size * 8 * 1000 / msec_dur;
9533 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9534 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9535 mm_player_set_attribute((MMHandleType)player, NULL,
9536 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9539 LOGD("player duration is less than 0");
9543 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9544 if (player->total_bitrate) {
9545 mm_player_set_attribute((MMHandleType)player, NULL,
9546 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9555 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9557 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9558 data->uri_type = uri_type;
9562 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9564 int ret = MM_ERROR_PLAYER_INVALID_URI;
9566 char *buffer = NULL;
9567 char *seperator = strchr(path, ',');
9568 char ext[100] = {0,}, size[100] = {0,};
9571 if ((buffer = strstr(path, "ext="))) {
9572 buffer += strlen("ext=");
9574 if (strlen(buffer)) {
9575 strncpy(ext, buffer, 99);
9577 if ((seperator = strchr(ext, ','))
9578 || (seperator = strchr(ext, ' '))
9579 || (seperator = strchr(ext, '\0'))) {
9580 seperator[0] = '\0';
9585 if ((buffer = strstr(path, "size="))) {
9586 buffer += strlen("size=");
9588 if (strlen(buffer) > 0) {
9589 strncpy(size, buffer, 99);
9591 if ((seperator = strchr(size, ','))
9592 || (seperator = strchr(size, ' '))
9593 || (seperator = strchr(size, '\0'))) {
9594 seperator[0] = '\0';
9597 mem_size = atoi(size);
9602 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9604 if (mem_size && param) {
9605 if (data->input_mem.buf)
9606 free(data->input_mem.buf);
9607 data->input_mem.buf = malloc(mem_size);
9609 if (data->input_mem.buf) {
9610 memcpy(data->input_mem.buf, param, mem_size);
9611 data->input_mem.len = mem_size;
9612 ret = MM_ERROR_NONE;
9614 LOGE("failed to alloc mem %d", mem_size);
9615 ret = MM_ERROR_PLAYER_INTERNAL;
9618 data->input_mem.offset = 0;
9619 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9626 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9628 gchar *location = NULL;
9631 int ret = MM_ERROR_NONE;
9633 if ((path = strstr(uri, "file://"))) {
9634 location = g_filename_from_uri(uri, NULL, &err);
9635 if (!location || (err != NULL)) {
9636 LOGE("Invalid URI '%s' for filesrc: %s", path,
9637 (err != NULL) ? err->message : "unknown error");
9641 MMPLAYER_FREEIF(location);
9643 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9644 return MM_ERROR_PLAYER_INVALID_URI;
9646 LOGD("path from uri: %s", location);
9649 path = (location != NULL) ? (location) : ((char *)uri);
9652 ret = _mmplayer_exist_file_path(path);
9654 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9655 if (ret == MM_ERROR_NONE) {
9656 if (_mmplayer_is_sdp_file(path)) {
9657 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9658 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9659 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9661 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9662 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9664 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9665 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9667 LOGE("invalid uri, could not play..");
9668 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9671 MMPLAYER_FREEIF(location);
9676 static mmplayer_video_decoded_data_info_t *
9677 __mmplayer_create_stream_from_pad(GstPad *pad)
9679 GstCaps *caps = NULL;
9680 GstStructure *structure = NULL;
9681 unsigned int fourcc = 0;
9682 const gchar *string_format = NULL;
9683 mmplayer_video_decoded_data_info_t *stream = NULL;
9685 MMPixelFormatType format;
9688 caps = gst_pad_get_current_caps(pad);
9690 LOGE("Caps is NULL.");
9695 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9697 structure = gst_caps_get_structure(caps, 0);
9698 gst_structure_get_int(structure, "width", &width);
9699 gst_structure_get_int(structure, "height", &height);
9700 string_format = gst_structure_get_string(structure, "format");
9703 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9704 format = _mmplayer_get_pixtype(fourcc);
9705 gst_video_info_from_caps(&info, caps);
9706 gst_caps_unref(caps);
9709 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9710 LOGE("Wrong condition!!");
9714 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9716 LOGE("failed to alloc mem for video data");
9720 stream->width = width;
9721 stream->height = height;
9722 stream->format = format;
9723 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9729 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9731 unsigned int pitch = 0;
9732 unsigned int size = 0;
9734 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9737 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9738 bo = gst_tizen_memory_get_bos(mem, index);
9740 stream->bo[index] = tbm_bo_ref(bo);
9742 LOGE("failed to get bo for index %d", index);
9745 for (index = 0; index < stream->plane_num; index++) {
9746 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9747 stream->stride[index] = pitch;
9749 stream->elevation[index] = size / pitch;
9751 stream->elevation[index] = stream->height;
9756 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9758 if (stream->format == MM_PIXEL_FORMAT_I420) {
9759 int ret = TBM_SURFACE_ERROR_NONE;
9760 tbm_surface_h surface;
9761 tbm_surface_info_s info;
9763 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9765 ret = tbm_surface_get_info(surface, &info);
9766 if (ret != TBM_SURFACE_ERROR_NONE) {
9767 tbm_surface_destroy(surface);
9771 tbm_surface_destroy(surface);
9772 stream->stride[0] = info.planes[0].stride;
9773 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9774 stream->stride[1] = info.planes[1].stride;
9775 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9776 stream->stride[2] = info.planes[2].stride;
9777 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9778 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9779 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9780 stream->stride[0] = stream->width * 4;
9781 stream->elevation[0] = stream->height;
9782 stream->bo_size = stream->stride[0] * stream->height;
9784 LOGE("Not support format %d", stream->format);
9792 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9794 tbm_bo_handle thandle;
9796 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9797 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9798 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9802 unsigned char *src = NULL;
9803 unsigned char *dest = NULL;
9804 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9806 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9808 LOGE("fail to gst_memory_map");
9812 if (!mapinfo.data) {
9813 LOGE("data pointer is wrong");
9817 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9818 if (!stream->bo[0]) {
9819 LOGE("Fail to tbm_bo_alloc!!");
9823 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9825 LOGE("thandle pointer is wrong");
9829 if (stream->format == MM_PIXEL_FORMAT_I420) {
9830 src_stride[0] = GST_ROUND_UP_4(stream->width);
9831 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9832 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9833 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9836 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9837 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9839 for (i = 0; i < 3; i++) {
9840 src = mapinfo.data + src_offset[i];
9841 dest = thandle.ptr + dest_offset[i];
9846 for (j = 0; j < stream->height >> k; j++) {
9847 memcpy(dest, src, stream->width>>k);
9848 src += src_stride[i];
9849 dest += stream->stride[i];
9852 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9853 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9855 LOGE("Not support format %d", stream->format);
9859 tbm_bo_unmap(stream->bo[0]);
9860 gst_memory_unmap(mem, &mapinfo);
9866 tbm_bo_unmap(stream->bo[0]);
9869 gst_memory_unmap(mem, &mapinfo);
9875 __mmplayer_set_pause_state(mmplayer_t *player)
9877 if (player->sent_bos)
9880 /* rtsp case, get content attrs by GstMessage */
9881 if (MMPLAYER_IS_RTSP_STREAMING(player))
9884 /* it's first time to update all content attrs. */
9885 _mmplayer_update_content_attrs(player, ATTR_ALL);
9889 __mmplayer_set_playing_state(mmplayer_t *player)
9891 gchar *audio_codec = NULL;
9893 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9894 /* initialize because auto resume is done well. */
9895 player->resumed_by_rewind = FALSE;
9896 player->playback_rate = 1.0;
9899 if (player->sent_bos)
9902 /* try to get content metadata */
9904 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9905 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9906 * legacy mmfw-player api
9908 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9910 if ((player->cmd == MMPLAYER_COMMAND_START)
9911 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9912 __mmplayer_handle_missed_plugin(player);
9915 /* check audio codec field is set or not
9916 * we can get it from typefinder or codec's caps.
9918 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9920 /* The codec format can't be sent for audio only case like amr, mid etc.
9921 * Because, parser don't make related TAG.
9922 * So, if it's not set yet, fill it with found data.
9925 if (g_strrstr(player->type, "audio/midi"))
9926 audio_codec = "MIDI";
9927 else if (g_strrstr(player->type, "audio/x-amr"))
9928 audio_codec = "AMR";
9929 else if (g_strrstr(player->type, "audio/mpeg")
9930 && !g_strrstr(player->type, "mpegversion=(int)1"))
9931 audio_codec = "AAC";
9933 audio_codec = "unknown";
9935 if (mm_player_set_attribute((MMHandleType)player, NULL,
9936 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9937 LOGE("failed to set attribute");
9939 LOGD("set audio codec type with caps");