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 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
748 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
749 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
753 /* Initialize Player values */
754 __mmplayer_initialize_gapless_play(player);
756 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
758 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
764 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
766 GSource *source = NULL;
770 source = g_main_context_find_source_by_id(context, source_id);
771 if (source != NULL) {
772 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
773 g_source_destroy(source);
780 _mmplayer_watcher_removed_notify(gpointer data)
782 mmplayer_t *player = (mmplayer_t *)data;
783 MMPLAYER_RETURN_IF_FAIL(player);
785 MMPLAYER_BUS_WATCHER_LOCK(player);
786 player->bus_watcher = 0;
787 MMPLAYER_BUS_WATCHER_SIGNAL(player);
788 MMPLAYER_BUS_WATCHER_UNLOCK(player);
792 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
794 mmplayer_t *player = (mmplayer_t *)hplayer;
797 MMPLAYER_RETURN_IF_FAIL(player);
799 /* disconnecting bus watch */
800 if (player->bus_watcher > 0) {
801 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
802 MMPLAYER_BUS_WATCHER_LOCK(player);
803 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
804 while (player->bus_watcher > 0) {
805 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
806 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
807 player->bus_watcher);
811 MMPLAYER_BUS_WATCHER_UNLOCK(player);
812 g_mutex_clear(&player->bus_watcher_mutex);
813 g_cond_clear(&player->bus_watcher_cond);
820 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
822 mmplayer_t *player = (mmplayer_t *)hplayer;
823 GstMessage *msg = NULL;
824 GQueue *queue = NULL;
827 MMPLAYER_RETURN_IF_FAIL(player);
829 /* destroy the gst bus msg thread */
830 if (player->bus_msg_thread) {
831 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
832 player->bus_msg_thread_exit = TRUE;
833 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
834 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
836 LOGD("gst bus msg thread exit.");
837 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
838 player->bus_msg_thread = NULL;
840 g_mutex_clear(&player->bus_msg_thread_mutex);
841 g_cond_clear(&player->bus_msg_thread_cond);
844 g_mutex_lock(&player->bus_msg_q_lock);
845 queue = player->bus_msg_q;
846 while (!g_queue_is_empty(queue)) {
847 msg = (GstMessage *)g_queue_pop_head(queue);
852 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
853 gst_message_unref(msg);
855 g_mutex_unlock(&player->bus_msg_q_lock);
861 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
863 GstElement *parent = NULL;
865 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
866 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
869 MMPLAYER_FSINK_LOCK(player);
871 /* get parent of fakesink */
872 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
874 LOGD("fakesink already removed");
878 gst_element_set_locked_state(fakesink->gst, TRUE);
880 /* setting the state to NULL never returns async
881 * so no need to wait for completion of state transition
883 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
884 LOGE("fakesink state change failure!");
885 /* FIXIT : should I return here? or try to proceed to next? */
888 /* remove fakesink from it's parent */
889 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
890 LOGE("failed to remove fakesink");
892 gst_object_unref(parent);
897 gst_object_unref(parent);
899 LOGD("state-holder removed");
901 gst_element_set_locked_state(fakesink->gst, FALSE);
903 MMPLAYER_FSINK_UNLOCK(player);
908 gst_element_set_locked_state(fakesink->gst, FALSE);
910 MMPLAYER_FSINK_UNLOCK(player);
914 static GstPadProbeReturn
915 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
917 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
918 return GST_PAD_PROBE_OK;
922 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
924 gint64 stop_running_time = 0;
925 gint64 position_running_time = 0;
929 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
930 if ((player->gapless.update_segment[idx] == TRUE) ||
931 !(player->track[idx].event_probe_id)) {
933 LOGW("[%d] skip", idx);
938 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
940 gst_segment_to_running_time(&player->gapless.segment[idx],
941 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
942 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
944 gst_segment_to_running_time(&player->gapless.segment[idx],
945 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
947 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
949 gst_segment_to_running_time(&player->gapless.segment[idx],
950 GST_FORMAT_TIME, player->duration);
953 position_running_time =
954 gst_segment_to_running_time(&player->gapless.segment[idx],
955 GST_FORMAT_TIME, player->gapless.segment[idx].position);
957 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
958 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
960 GST_TIME_ARGS(stop_running_time),
961 GST_TIME_ARGS(position_running_time),
962 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
963 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
965 position_running_time = MAX(position_running_time, stop_running_time);
966 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
967 GST_FORMAT_TIME, player->gapless.segment[idx].start);
968 position_running_time = MAX(0, position_running_time);
969 position = MAX(position, position_running_time);
973 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
974 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
975 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
977 player->gapless.start_time[stream_type] += position;
983 static GstPadProbeReturn
984 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
986 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
987 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
988 mmplayer_t *player = (mmplayer_t *)data;
989 GstCaps *caps = NULL;
990 GstStructure *str = NULL;
991 const gchar *name = NULL;
992 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
993 gboolean caps_ret = TRUE;
995 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
996 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
997 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
998 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
999 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1002 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1006 if (strstr(name, "audio")) {
1007 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1008 } else if (strstr(name, "video")) {
1009 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1011 /* text track is not supportable */
1012 LOGE("invalid name %s", name);
1016 switch (GST_EVENT_TYPE(event)) {
1019 /* in case of gapless, drop eos event not to send it to sink */
1020 if (player->gapless.reconfigure && !player->msg_posted) {
1021 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1022 ret = GST_PAD_PROBE_DROP;
1026 case GST_EVENT_STREAM_START:
1028 __mmplayer_gst_selector_update_start_time(player, stream_type);
1031 case GST_EVENT_FLUSH_STOP:
1033 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1034 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1035 player->gapless.start_time[stream_type] = 0;
1038 case GST_EVENT_SEGMENT:
1043 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1044 gst_event_copy_segment(event, &segment);
1046 if (segment.format != GST_FORMAT_TIME)
1049 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1050 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1051 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1052 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1053 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1054 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1056 /* keep the all the segment ev to cover the seeking */
1057 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1058 player->gapless.update_segment[stream_type] = TRUE;
1060 if (!player->gapless.running)
1063 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1065 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1067 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1068 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1069 gst_event_unref(event);
1070 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1076 gdouble proportion = 0.0;
1077 GstClockTimeDiff diff = 0;
1078 GstClockTime timestamp = 0;
1079 gint64 running_time_diff = -1;
1080 GstQOSType type = 0;
1081 GstEvent *tmpev = NULL;
1083 running_time_diff = player->gapless.segment[stream_type].base;
1085 if (running_time_diff <= 0) /* don't need to adjust */
1088 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1089 gst_event_unref(event);
1091 if (timestamp < running_time_diff) {
1092 LOGW("QOS event from previous group");
1093 ret = GST_PAD_PROBE_DROP;
1098 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1099 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1100 stream_type, GST_TIME_ARGS(timestamp),
1101 GST_TIME_ARGS(running_time_diff),
1102 GST_TIME_ARGS(timestamp - running_time_diff));
1105 timestamp -= running_time_diff;
1107 /* That case is invalid for QoS events */
1108 if (diff < 0 && -diff > timestamp) {
1109 LOGW("QOS event from previous group");
1110 ret = GST_PAD_PROBE_DROP;
1114 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1115 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1125 gst_caps_unref(caps);
1129 /* create fakesink for audio or video path without audiobin or videobin */
1131 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1133 GstElement *pipeline = NULL;
1134 GstElement *fakesink = NULL;
1135 GstPad *sinkpad = NULL;
1138 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1140 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1143 fakesink = gst_element_factory_make("fakesink", NULL);
1144 if (fakesink == NULL) {
1145 LOGE("failed to create fakesink");
1149 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1150 LOGE("failed to add fakesink to pipeline");
1155 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1157 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1159 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1160 LOGE("failed to link fakesink");
1164 if (strstr(name, "video")) {
1165 if (player->v_stream_caps) {
1166 gst_caps_unref(player->v_stream_caps);
1167 player->v_stream_caps = NULL;
1169 if (player->ini.set_dump_element_flag)
1170 __mmplayer_add_dump_buffer_probe(player, fakesink);
1173 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1174 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1176 /* store it as it's sink element */
1177 __mmplayer_add_sink(player, fakesink, FALSE);
1180 gst_object_unref(GST_OBJECT(sinkpad));
1188 gst_object_unref(GST_OBJECT(sinkpad));
1191 gst_element_set_state(fakesink, GST_STATE_NULL);
1193 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1194 gst_object_unref(GST_OBJECT(fakesink));
1201 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1203 GstElement *pipeline = NULL;
1204 GstElement *concat = NULL;
1207 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1209 concat = gst_element_factory_make("concat", NULL);
1211 LOGE("failed to create concat");
1215 gst_element_set_state(concat, GST_STATE_PAUSED);
1217 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1218 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1219 LOGE("failed to add concat to pipeline");
1220 gst_element_set_state(concat, GST_STATE_NULL);
1221 gst_object_unref(GST_OBJECT(concat));
1225 LOGD("Create concat [%d] element", elem_idx);
1227 player->pipeline->mainbin[elem_idx].id = elem_idx;
1228 player->pipeline->mainbin[elem_idx].gst = concat;
1235 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1237 GstElement *pipeline = NULL;
1238 GstElement *selector = NULL;
1239 GstPad *srcpad = NULL;
1242 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1244 selector = gst_element_factory_make("input-selector", NULL);
1246 LOGE("failed to create input-selector");
1249 g_object_set(selector, "sync-streams", TRUE, NULL);
1251 srcpad = gst_element_get_static_pad(selector, "src");
1253 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1254 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1255 __mmplayer_gst_selector_blocked, NULL, NULL);
1256 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1257 __mmplayer_gst_selector_event_probe, player, NULL);
1259 gst_element_set_state(selector, GST_STATE_PAUSED);
1261 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1262 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1263 LOGE("failed to add selector to pipeline");
1265 if (player->track[stream_type].block_id != 0)
1266 gst_pad_remove_probe (srcpad, player->track[stream_type].block_id);
1267 player->track[stream_type].block_id = 0;
1269 if (player->track[stream_type].event_probe_id != 0)
1270 gst_pad_remove_probe (srcpad, player->track[stream_type].event_probe_id);
1271 player->track[stream_type].event_probe_id = 0;
1273 gst_object_unref(GST_OBJECT(srcpad));
1275 gst_element_set_state(selector, GST_STATE_NULL);
1276 gst_object_unref(GST_OBJECT(selector));
1280 gst_object_unref(GST_OBJECT(srcpad));
1282 player->pipeline->mainbin[elem_idx].id = elem_idx;
1283 player->pipeline->mainbin[elem_idx].gst = selector;
1290 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1292 mmplayer_t *player = (mmplayer_t *)data;
1293 GstElement *combiner = NULL;
1294 GstCaps *caps = NULL;
1295 GstStructure *str = NULL;
1296 const gchar *name = NULL;
1297 GstPad *sinkpad = NULL;
1298 gboolean first_track = FALSE;
1299 gboolean caps_ret = TRUE;
1301 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1302 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1305 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1306 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1308 LOGD("pad-added signal handling");
1310 /* get mimetype from caps */
1311 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1315 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1317 LOGD("detected mimetype : %s", name);
1320 if (strstr(name, "video")) {
1322 gchar *caps_str = NULL;
1324 caps_str = gst_caps_to_string(caps);
1325 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1326 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1327 player->set_mode.video_zc = true;
1329 MMPLAYER_FREEIF(caps_str);
1331 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1332 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1334 LOGD("surface type : %d", stype);
1336 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1337 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1341 /* in case of exporting video frame, it requires the 360 video filter.
1342 * it will be handled in _no_more_pads(). */
1343 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1344 __mmplayer_gst_make_fakesink(player, pad, name);
1348 if (MMPLAYER_USE_DECODEBIN(player)) {
1349 LOGD("video selector is required");
1350 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1352 LOGD("video concat is required");
1353 elem_idx = MMPLAYER_M_V_CONCAT;
1355 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1356 } else if (strstr(name, "audio")) {
1357 gint samplerate = 0;
1360 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1361 if (player->build_audio_offload)
1362 player->no_more_pad = TRUE; /* remove state holder */
1363 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1367 gst_structure_get_int(str, "rate", &samplerate);
1368 gst_structure_get_int(str, "channels", &channels);
1370 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1371 __mmplayer_gst_make_fakesink(player, pad, name);
1374 if (MMPLAYER_USE_DECODEBIN(player)) {
1375 LOGD("audio selector is required");
1376 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1378 LOGD("audio concat is required");
1379 elem_idx = MMPLAYER_M_A_CONCAT;
1381 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1383 } else if (strstr(name, "text")) {
1384 if (MMPLAYER_USE_DECODEBIN(player)) {
1385 LOGD("text selector is required");
1386 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1388 LOGD("text concat is required");
1389 elem_idx = MMPLAYER_M_T_CONCAT;
1391 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1393 LOGE("invalid caps info");
1397 /* check selector and create it */
1398 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1399 if (MMPLAYER_USE_DECODEBIN(player))
1400 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1402 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1408 LOGD("Combiner element is already created.");
1412 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1414 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1416 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1417 LOGE("failed to link combiner");
1418 gst_object_unref(GST_OBJECT(combiner));
1423 if (MMPLAYER_USE_DECODEBIN(player)) {
1424 LOGD("this track will be activated");
1425 g_object_set(combiner, "active-pad", sinkpad, NULL);
1429 if (MMPLAYER_USE_DECODEBIN(player)) {
1430 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1432 /* apply the text track information */
1433 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1434 mm_player_set_attribute((MMHandleType)player, NULL,
1435 "content_text_track_num", player->track[stream_type].total_track_num,
1436 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1437 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1444 gst_caps_unref(caps);
1447 gst_object_unref(GST_OBJECT(sinkpad));
1451 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1456 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1458 GstPad *srcpad = NULL;
1461 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1463 LOGD("type %d", type);
1466 LOGD("there is no %d track", type);
1470 srcpad = gst_element_get_static_pad(combiner, "src");
1472 LOGE("failed to get srcpad from combiner");
1476 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1478 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1480 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1481 if (player->track[type].block_id) {
1482 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1483 player->track[type].block_id = 0;
1487 gst_object_unref(GST_OBJECT(srcpad));
1496 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1498 gint active_index = 0;
1501 MMPLAYER_RETURN_IF_FAIL(player);
1503 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1505 /* change track to active pad */
1506 active_index = player->track[type].active_track_index;
1507 if ((active_index != DEFAULT_TRACK_INDEX) &&
1508 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1509 LOGW("failed to change %d type track to %d", type, active_index);
1510 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1514 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1515 mm_player_set_attribute((MMHandleType)player, NULL,
1516 "content_text_track_num", player->track[type].total_track_num,
1517 "current_text_track_index", player->track[type].active_track_index, NULL);
1524 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1527 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1529 if (!audio_selector) {
1530 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1532 /* in case the source is changed, output can be changed. */
1533 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1534 LOGD("remove previous audiobin if it exist");
1536 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1537 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1539 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1540 MMPLAYER_FREEIF(player->pipeline->audiobin);
1543 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1544 _mmplayer_pipeline_complete(NULL, player);
1549 /* apply the audio track information */
1550 if (MMPLAYER_USE_DECODEBIN(player))
1551 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1553 /* create audio sink path */
1554 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1555 LOGE("failed to create audio sink path");
1564 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1567 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1569 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1570 LOGD("text path is not supported");
1574 /* apply the text track information */
1575 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1577 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1578 player->has_closed_caption = TRUE;
1580 /* create text decode path */
1581 player->no_more_pad = TRUE;
1583 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1584 LOGE("failed to create text sink path");
1593 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1595 gint64 dur_bytes = 0L;
1598 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1599 player->pipeline->mainbin && player->streamer, FALSE);
1601 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1602 LOGE("fail to get duration.");
1604 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1605 * use file information was already set on Q2 when it was created. */
1606 _mm_player_streaming_set_queue2(player->streamer,
1607 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1608 TRUE, /* use_buffering */
1609 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1610 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1617 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1619 mmplayer_t *player = NULL;
1620 GstElement *video_selector = NULL;
1621 GstElement *audio_selector = NULL;
1622 GstElement *text_selector = NULL;
1625 player = (mmplayer_t *)data;
1627 LOGD("no-more-pad signal handling");
1629 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1630 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1631 LOGW("player is shutting down");
1635 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1636 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1637 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1638 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1639 LOGE("failed to set queue2 buffering");
1644 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1645 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1646 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1648 if (!video_selector && !audio_selector && !text_selector) {
1649 LOGW("there is no selector");
1650 player->no_more_pad = TRUE;
1654 /* create video path followed by video-select */
1655 if (video_selector && !audio_selector && !text_selector)
1656 player->no_more_pad = TRUE;
1658 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1661 /* create audio path followed by audio-select */
1662 if (audio_selector && !text_selector)
1663 player->no_more_pad = TRUE;
1665 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1668 /* create text path followed by text-select */
1669 __mmplayer_create_text_sink_path(player, text_selector);
1672 _mmplayer_set_reconfigure_state(player, FALSE);
1677 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1679 gboolean ret = FALSE;
1680 GstElement *pipeline = NULL;
1681 GstPad *sinkpad = NULL;
1684 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1685 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1687 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1689 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1691 LOGE("failed to get pad from sinkbin");
1697 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1698 LOGE("failed to link sinkbin for reusing");
1699 goto EXIT; /* exit either pass or fail */
1703 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1704 LOGE("failed to set state(READY) to sinkbin");
1709 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1710 LOGE("failed to add sinkbin to pipeline");
1715 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1716 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1721 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1722 LOGE("failed to set state(PAUSED) to sinkbin");
1731 gst_object_unref(GST_OBJECT(sinkpad));
1739 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1741 mmplayer_t *player = NULL;
1742 GstCaps *caps = NULL;
1743 gchar *caps_str = NULL;
1744 GstStructure *str = NULL;
1745 const gchar *name = NULL;
1746 GstElement *sinkbin = NULL;
1747 gboolean reusing = FALSE;
1748 gboolean caps_ret = TRUE;
1749 gchar *sink_pad_name = "sink";
1752 player = (mmplayer_t *)data;
1755 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1756 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1757 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1759 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1763 gst_caps_unref(caps);
1764 caps = gst_caps_ref(ref_caps);
1767 caps_str = gst_caps_to_string(caps);
1769 LOGD("detected mimetype : %s", name);
1771 if (strstr(name, "audio")) {
1772 if (player->pipeline->audiobin == NULL) {
1773 const gchar *audio_format = gst_structure_get_string(str, "format");
1775 LOGD("original audio format %s", audio_format);
1776 mm_player_set_attribute((MMHandleType)player, NULL,
1777 "content_audio_format", audio_format, strlen(audio_format), NULL);
1780 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1781 LOGE("failed to create audiobin. continuing without audio");
1785 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1786 LOGD("creating audiobin success");
1789 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1790 LOGD("reusing audiobin");
1791 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1793 } else if (strstr(name, "video")) {
1794 /* 1. zero copy is updated at _decode_pad_added()
1795 * 2. NULL surface type is handled in _decode_pad_added() */
1796 LOGD("zero copy %d", player->set_mode.video_zc);
1797 if (player->pipeline->videobin == NULL) {
1798 int surface_type = 0;
1799 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1800 LOGD("display_surface_type (%d)", surface_type);
1802 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1803 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1804 LOGE("failed to acquire video overlay resource");
1808 player->interrupted_by_resource = FALSE;
1810 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1811 LOGE("failed to create videobin. continuing without video");
1815 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1816 LOGD("creating videosink bin success");
1819 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1820 LOGD("re-using videobin");
1821 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1823 } else if (strstr(name, "text")) {
1824 if (player->pipeline->textbin == NULL) {
1825 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1826 LOGE("failed to create text sink bin. continuing without text");
1830 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1831 player->textsink_linked = 1;
1832 LOGD("creating textsink bin success");
1834 if (!player->textsink_linked) {
1835 LOGD("re-using textbin");
1837 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1838 player->textsink_linked = 1;
1840 /* linked textbin exist which means that the external subtitle path exist already */
1841 LOGW("ignoring internal subtitle since external subtitle is available");
1844 sink_pad_name = "text_sink";
1846 LOGW("unknown mime type %s, ignoring it", name);
1850 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1853 LOGD("[handle: %p] success to create and link sink bin", player);
1855 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1856 * streaming task. if the task blocked, then buffer will not flow to the next element
1857 *(autoplugging element). so this is special hack for streaming. please try to remove it
1859 /* dec stream count. we can remove fakesink if it's zero */
1860 if (player->num_dynamic_pad)
1861 player->num_dynamic_pad--;
1863 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1865 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1866 _mmplayer_pipeline_complete(NULL, player);
1870 MMPLAYER_FREEIF(caps_str);
1873 gst_caps_unref(caps);
1879 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1881 int required_angle = 0; /* Angle required for straight view */
1882 int rotation_angle = 0;
1884 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1885 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1887 /* Counter clockwise */
1888 switch (orientation) {
1893 required_angle = 270;
1896 required_angle = 180;
1899 required_angle = 90;
1903 rotation_angle = display_angle + required_angle;
1904 if (rotation_angle >= 360)
1905 rotation_angle -= 360;
1907 /* check if supported or not */
1908 if (rotation_angle % 90) {
1909 LOGD("not supported rotation angle = %d", rotation_angle);
1913 switch (rotation_angle) {
1915 *value = MM_DISPLAY_ROTATION_NONE;
1918 *value = MM_DISPLAY_ROTATION_90;
1921 *value = MM_DISPLAY_ROTATION_180;
1924 *value = MM_DISPLAY_ROTATION_270;
1928 LOGD("setting rotation property value : %d", *value);
1934 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1936 int display_rotation = 0;
1937 gchar *org_orient = NULL;
1938 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1941 LOGE("cannot get content attribute");
1942 return MM_ERROR_PLAYER_INTERNAL;
1945 if (display_angle) {
1946 /* update user rotation */
1947 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1949 /* Counter clockwise */
1950 switch (display_rotation) {
1951 case MM_DISPLAY_ROTATION_NONE:
1954 case MM_DISPLAY_ROTATION_90:
1955 *display_angle = 90;
1957 case MM_DISPLAY_ROTATION_180:
1958 *display_angle = 180;
1960 case MM_DISPLAY_ROTATION_270:
1961 *display_angle = 270;
1964 LOGW("wrong angle type : %d", display_rotation);
1967 LOGD("check user angle: %d", *display_angle);
1971 /* Counter clockwise */
1972 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1975 if (!strcmp(org_orient, "rotate-90"))
1977 else if (!strcmp(org_orient, "rotate-180"))
1979 else if (!strcmp(org_orient, "rotate-270"))
1982 LOGD("original rotation is %s", org_orient);
1984 LOGD("content_video_orientation get fail");
1987 LOGD("check orientation: %d", *orientation);
1990 return MM_ERROR_NONE;
1993 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1995 int rotation_value = 0;
1996 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1997 int display_angle = 0;
2000 /* check video sinkbin is created */
2001 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2004 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2006 /* get rotation value to set */
2007 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2008 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2009 LOGD("set video param : rotate %d", rotation_value);
2012 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2014 MMHandleType attrs = 0;
2018 /* check video sinkbin is created */
2019 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2020 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2023 attrs = MMPLAYER_GET_ATTRS(player);
2024 MMPLAYER_RETURN_IF_FAIL(attrs);
2026 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2027 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2028 LOGD("set video param : visible %d", visible);
2031 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2033 MMHandleType attrs = 0;
2034 int display_method = 0;
2037 /* check video sinkbin is created */
2038 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2041 attrs = MMPLAYER_GET_ATTRS(player);
2042 MMPLAYER_RETURN_IF_FAIL(attrs);
2044 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2045 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2046 LOGD("set video param : method %d", display_method);
2049 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2051 MMHandleType attrs = 0;
2055 /* check video sinkbin is created */
2056 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2059 attrs = MMPLAYER_GET_ATTRS(player);
2060 MMPLAYER_RETURN_IF_FAIL(attrs);
2062 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2063 MMPLAYER_RETURN_IF_FAIL(handle);
2065 gst_video_overlay_set_video_roi_area(
2066 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2067 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2068 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2069 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2072 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2074 MMHandleType attrs = 0;
2079 int win_roi_width = 0;
2080 int win_roi_height = 0;
2083 /* check video sinkbin is created */
2084 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2087 attrs = MMPLAYER_GET_ATTRS(player);
2088 MMPLAYER_RETURN_IF_FAIL(attrs);
2090 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2091 MMPLAYER_RETURN_IF_FAIL(handle);
2093 /* It should be set after setting window */
2094 mm_attrs_multiple_get(attrs, NULL,
2095 "display_win_roi_x", &win_roi_x,
2096 "display_win_roi_y", &win_roi_y,
2097 "display_win_roi_width", &win_roi_width,
2098 "display_win_roi_height", &win_roi_height, NULL);
2100 /* After setting window handle, set display roi area */
2101 gst_video_overlay_set_display_roi_area(
2102 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2103 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2104 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2105 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2108 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2110 MMHandleType attrs = 0;
2111 gchar *handle = NULL;
2113 /* check video sinkbin is created */
2114 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2117 attrs = MMPLAYER_GET_ATTRS(player);
2118 MMPLAYER_RETURN_IF_FAIL(attrs);
2120 /* common case if using overlay surface */
2121 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2122 MMPLAYER_RETURN_IF_FAIL(handle);
2124 gst_video_overlay_set_wl_window_exported_shell_handle(
2125 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2127 LOGD("set video param: exported_shell_handle (%s)", handle);
2130 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2132 MMHandleType attrs = 0;
2135 /* check video sinkbin is created */
2136 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2139 attrs = MMPLAYER_GET_ATTRS(player);
2140 MMPLAYER_RETURN_IF_FAIL(attrs);
2142 /* common case if using overlay surface */
2143 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2144 MMPLAYER_RETURN_IF_FAIL(handle);
2146 /* default is using wl_surface_id */
2147 LOGD("set video param : wl_surface_id %d", handle);
2148 gst_video_overlay_set_wl_window_wl_surface_id(
2149 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2154 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2156 gboolean update_all_param = FALSE;
2157 int curr_type = MM_DISPLAY_SURFACE_NUM;
2161 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2162 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2163 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2164 LOGW("videosink is not ready yet");
2165 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2168 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2170 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2171 LOGE("current type(%d) is wrong", curr_type);
2172 return MM_ERROR_PLAYER_INTERNAL;
2175 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2176 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2177 return MM_ERROR_PLAYER_INTERNAL;
2180 LOGD("param_name : %s", param_name);
2181 if (!g_strcmp0(param_name, "update_all_param"))
2182 update_all_param = TRUE;
2184 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2185 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2187 return MM_ERROR_NONE;
2189 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2190 __mmplayer_video_param_set_display_overlay(player);
2191 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2192 __mmplayer_video_param_set_display_method(player);
2193 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2194 __mmplayer_video_param_set_display_visible(player);
2195 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2196 __mmplayer_video_param_set_display_rotation(player);
2197 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2198 __mmplayer_video_param_set_roi_area(player);
2199 if (update_all_param)
2200 __mmplayer_video_param_set_video_roi_area(player);
2203 return MM_ERROR_NONE;
2206 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2208 gboolean disable_overlay = FALSE;
2211 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2212 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2213 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2215 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2216 LOGW("Display control is not supported");
2217 return MM_ERROR_PLAYER_INTERNAL;
2220 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2222 if (disable == (bool)disable_overlay) {
2223 LOGE("It's the same with current setting: (%d)", disable);
2224 return MM_ERROR_NONE;
2228 LOGE("disable overlay");
2229 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2231 /* release overlay resource */
2232 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2233 LOGE("failed to release overlay resource");
2234 return MM_ERROR_PLAYER_INTERNAL;
2237 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2238 LOGE("failed to acquire video overlay resource");
2239 return MM_ERROR_PLAYER_INTERNAL;
2241 player->interrupted_by_resource = FALSE;
2243 LOGD("enable overlay");
2244 __mmplayer_video_param_set_display_overlay(player);
2245 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2246 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2250 return MM_ERROR_NONE;
2254 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2256 int ret = MM_ERROR_NONE;
2257 mmplayer_t *player = (mmplayer_t *)hplayer;
2260 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2262 if (MMPLAYER_USE_DECODEBIN(player)) {
2263 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2268 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2269 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2270 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2272 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
2274 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2276 /* release decoder resource */
2277 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2278 LOGE("failed to release video decoder resources");
2279 return MM_ERROR_PLAYER_INTERNAL;
2281 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2283 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2287 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2294 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2296 GList *bucket = element_bucket;
2297 mmplayer_gst_element_t *element = NULL;
2298 mmplayer_gst_element_t *prv_element = NULL;
2299 GstElement *tee_element = NULL;
2300 gint successful_link_count = 0;
2304 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2306 prv_element = (mmplayer_gst_element_t *)bucket->data;
2307 bucket = bucket->next;
2309 for (; bucket; bucket = bucket->next) {
2310 element = (mmplayer_gst_element_t *)bucket->data;
2312 if (element && element->gst) {
2313 if (prv_element && prv_element->gst) {
2314 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2316 prv_element->gst = tee_element;
2318 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2319 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2320 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2324 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2325 LOGD("linking [%s] to [%s] success",
2326 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2327 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2328 successful_link_count++;
2329 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2330 LOGD("keep audio-tee element for next audio pipeline branch");
2331 tee_element = prv_element->gst;
2334 LOGD("linking [%s] to [%s] failed",
2335 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2336 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2342 prv_element = element;
2347 return successful_link_count;
2351 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2353 GList *bucket = element_bucket;
2354 mmplayer_gst_element_t *element = NULL;
2355 int successful_add_count = 0;
2359 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2360 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2362 for (; bucket; bucket = bucket->next) {
2363 element = (mmplayer_gst_element_t *)bucket->data;
2365 if (element && element->gst) {
2366 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2367 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2368 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2369 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2372 successful_add_count++;
2378 return successful_add_count;
2382 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2384 mmplayer_t *player = (mmplayer_t *)data;
2385 GstCaps *caps = NULL;
2386 GstStructure *str = NULL;
2388 gboolean caps_ret = TRUE;
2392 MMPLAYER_RETURN_IF_FAIL(pad);
2393 MMPLAYER_RETURN_IF_FAIL(unused);
2394 MMPLAYER_RETURN_IF_FAIL(data);
2396 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2400 LOGD("name = %s", name);
2402 if (strstr(name, "audio")) {
2403 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2405 if (player->audio_stream_changed_cb) {
2406 LOGE("call the audio stream changed cb");
2407 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2409 } else if (strstr(name, "video")) {
2410 if ((name = gst_structure_get_string(str, "format")))
2411 player->set_mode.video_zc = name[0] == 'S';
2413 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2414 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2416 LOGW("invalid caps info");
2421 gst_caps_unref(caps);
2429 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2434 MMPLAYER_RETURN_IF_FAIL(player);
2436 if (player->audio_stream_buff_list) {
2437 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2438 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2441 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2442 __mmplayer_audio_stream_send_data(player, tmp);
2444 MMPLAYER_FREEIF(tmp->pcm_data);
2445 MMPLAYER_FREEIF(tmp);
2448 g_list_free(player->audio_stream_buff_list);
2449 player->audio_stream_buff_list = NULL;
2456 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2458 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2461 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2463 audio_stream.bitrate = a_buffer->bitrate;
2464 audio_stream.channel = a_buffer->channel;
2465 audio_stream.channel_mask = a_buffer->channel_mask;
2466 audio_stream.data_size = a_buffer->data_size;
2467 audio_stream.data = a_buffer->pcm_data;
2468 audio_stream.pcm_format = a_buffer->pcm_format;
2470 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2472 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2478 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2480 mmplayer_t *player = (mmplayer_t *)data;
2481 const gchar *pcm_format = NULL;
2484 guint64 channel_mask = 0;
2485 void *a_data = NULL;
2487 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2488 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2492 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2494 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2495 a_data = mapinfo.data;
2496 a_size = mapinfo.size;
2498 GstCaps *caps = gst_pad_get_current_caps(pad);
2499 GstStructure *structure = gst_caps_get_structure(caps, 0);
2501 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2503 pcm_format = gst_structure_get_string(structure, "format");
2504 gst_structure_get_int(structure, "rate", &rate);
2505 gst_structure_get_int(structure, "channels", &channel);
2506 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2507 gst_caps_unref(GST_CAPS(caps));
2509 /* In case of the sync is false, use buffer list. *
2510 * The num of buffer list depends on the num of audio channels */
2511 if (player->audio_stream_buff_list) {
2512 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2513 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2515 if (channel_mask == tmp->channel_mask) {
2517 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2519 if (tmp->data_size + a_size < tmp->buff_size) {
2520 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2521 tmp->data_size += a_size;
2523 /* send data to client */
2524 __mmplayer_audio_stream_send_data(player, tmp);
2526 if (a_size > tmp->buff_size) {
2527 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2528 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2529 if (tmp->pcm_data == NULL) {
2530 LOGE("failed to realloc data.");
2533 tmp->buff_size = a_size;
2535 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2536 memcpy(tmp->pcm_data, a_data, a_size);
2537 tmp->data_size = a_size;
2542 LOGE("data is empty in list.");
2548 /* create new audio stream data for newly found audio channel */
2549 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2550 if (a_buffer == NULL) {
2551 LOGE("failed to alloc data.");
2554 a_buffer->bitrate = rate;
2555 a_buffer->channel = channel;
2556 a_buffer->channel_mask = channel_mask;
2557 a_buffer->data_size = a_size;
2558 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2560 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2561 /* If sync is FALSE, use buffer list to reduce the IPC. */
2562 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2563 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2564 if (a_buffer->pcm_data == NULL) {
2565 LOGE("failed to alloc data.");
2566 MMPLAYER_FREEIF(a_buffer);
2569 memcpy(a_buffer->pcm_data, a_data, a_size);
2571 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2573 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2575 /* If sync is TRUE, send data directly. */
2576 a_buffer->pcm_data = a_data;
2577 __mmplayer_audio_stream_send_data(player, a_buffer);
2578 MMPLAYER_FREEIF(a_buffer);
2582 gst_buffer_unmap(buffer, &mapinfo);
2587 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2589 mmplayer_t *player = (mmplayer_t *)data;
2590 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2591 GstPad *sinkpad = NULL;
2592 GstElement *queue = NULL, *sink = NULL;
2595 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2597 queue = gst_element_factory_make("queue", NULL);
2598 if (queue == NULL) {
2599 LOGD("fail make queue");
2603 sink = gst_element_factory_make("fakesink", NULL);
2605 LOGD("fail make fakesink");
2609 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2611 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2612 LOGW("failed to link queue & sink");
2616 sinkpad = gst_element_get_static_pad(queue, "sink");
2618 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2619 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2623 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2625 gst_object_unref(sinkpad);
2626 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2627 g_object_set(sink, "sync", TRUE, NULL);
2628 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2630 /* keep the first sink reference only */
2631 if (!audiobin[MMPLAYER_A_SINK].gst) {
2632 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2633 audiobin[MMPLAYER_A_SINK].gst = sink;
2637 _mmplayer_add_signal_connection(player,
2639 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2641 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2644 __mmplayer_add_sink(player, sink, FALSE);
2646 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2647 LOGE("failed to sync state");
2651 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2652 LOGE("failed to sync state");
2660 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2662 gst_object_unref(GST_OBJECT(queue));
2666 gst_object_unref(GST_OBJECT(sink));
2670 gst_object_unref(GST_OBJECT(sinkpad));
2678 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2680 mmplayer_t *player = (mmplayer_t *)data;
2683 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2685 player->no_more_pad = TRUE;
2686 _mmplayer_pipeline_complete(NULL, player);
2693 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2695 #define MAX_PROPS_LEN 128
2696 mmplayer_gst_element_t *audiobin = NULL;
2697 gint latency_mode = 0;
2698 gchar *stream_type = NULL;
2699 gchar *latency = NULL;
2701 gchar stream_props[MAX_PROPS_LEN] = {0,};
2702 GstStructure *props = NULL;
2705 * It should be set after player creation through attribute.
2706 * But, it can not be changed during playing.
2709 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2711 audiobin = player->pipeline->audiobin;
2713 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2714 if (player->sound.mute) {
2715 LOGD("mute enabled");
2716 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2719 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2720 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2723 snprintf(stream_props, sizeof(stream_props) - 1,
2724 "props,application.process.id.origin=%d", player->client_pid);
2726 snprintf(stream_props, sizeof(stream_props) - 1,
2727 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2728 stream_type, stream_id, player->client_pid);
2730 props = gst_structure_from_string(stream_props, NULL);
2731 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2732 LOGI("props result[%s].", stream_props);
2733 gst_structure_free(props);
2735 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2737 switch (latency_mode) {
2738 case AUDIO_LATENCY_MODE_LOW:
2739 latency = g_strdup("low");
2741 case AUDIO_LATENCY_MODE_MID:
2742 latency = g_strdup("mid");
2744 case AUDIO_LATENCY_MODE_HIGH:
2745 latency = g_strdup("high");
2748 latency = g_strdup("mid");
2752 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2754 LOGD("audiosink property - latency=%s", latency);
2756 MMPLAYER_FREEIF(latency);
2762 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2764 mmplayer_gst_element_t *audiobin = NULL;
2767 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2768 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2770 audiobin = player->pipeline->audiobin;
2772 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2773 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2774 LOGE("failed to create media stream info");
2775 return MM_ERROR_PLAYER_INTERNAL;
2778 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2780 if (player->video360_yaw_radians <= M_PI &&
2781 player->video360_yaw_radians >= -M_PI &&
2782 player->video360_pitch_radians <= M_PI_2 &&
2783 player->video360_pitch_radians >= -M_PI_2) {
2784 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2785 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2786 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2787 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2788 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2789 "source-orientation-y", player->video360_metadata.init_view_heading,
2790 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2794 return MM_ERROR_NONE;
2798 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2800 mmplayer_gst_element_t *audiobin = NULL;
2801 GstPad *sink_pad = NULL;
2802 GstCaps *acaps = NULL;
2804 int pitch_control = 0;
2805 double pitch_value = 1.0;
2808 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2809 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2811 audiobin = player->pipeline->audiobin;
2813 LOGD("make element for normal audio playback");
2815 /* audio bin structure for playback. {} means optional.
2816 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2818 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2819 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2822 /* for pitch control */
2823 mm_attrs_multiple_get(player->attrs, NULL,
2824 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2825 MM_PLAYER_PITCH_VALUE, &pitch_value,
2828 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2829 if (pitch_control && (player->videodec_linked == 0)) {
2830 GstElementFactory *factory;
2832 factory = gst_element_factory_find("pitch");
2834 gst_object_unref(factory);
2837 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2840 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2841 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2843 LOGW("there is no pitch element");
2848 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2850 /* replaygain volume */
2851 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2852 if (player->sound.rg_enable)
2853 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2855 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2858 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2860 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2861 /* currently, only openalsink uses volume element */
2862 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2863 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2865 if (player->sound.mute) {
2866 LOGD("mute enabled");
2867 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2871 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2873 /* audio effect element. if audio effect is enabled */
2874 if ((strcmp(player->ini.audioeffect_element, ""))
2876 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2877 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2879 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2881 if ((!player->bypass_audio_effect)
2882 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2883 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2884 if (!_mmplayer_audio_effect_custom_apply(player))
2885 LOGI("apply audio effect(custom) setting success");
2889 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2890 && (player->set_mode.rich_audio)) {
2891 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2895 /* create audio sink */
2896 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2897 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2898 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2900 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2901 if (player->is_360_feature_enabled &&
2902 player->is_content_spherical &&
2904 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2905 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2906 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2908 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2910 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2912 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2913 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2914 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2915 gst_caps_unref(acaps);
2917 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2919 player->is_openal_plugin_used = TRUE;
2921 if (player->is_360_feature_enabled && player->is_content_spherical)
2922 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2923 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2926 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2927 (player->videodec_linked && player->ini.use_system_clock)) {
2928 LOGD("system clock will be used.");
2929 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2932 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2933 __mmplayer_gst_set_pulsesink_property(player);
2934 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2935 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2940 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2941 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2943 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2944 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2945 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2946 gst_object_unref(GST_OBJECT(sink_pad));
2948 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2951 return MM_ERROR_NONE;
2953 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2955 return MM_ERROR_PLAYER_INTERNAL;
2959 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2961 mmplayer_gst_element_t *audiobin = NULL;
2962 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2964 gchar *dst_format = NULL;
2966 int dst_samplerate = 0;
2967 int dst_channels = 0;
2968 GstCaps *caps = NULL;
2969 char *caps_str = NULL;
2972 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2973 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2975 audiobin = player->pipeline->audiobin;
2977 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2979 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2981 [case 1] extract interleave audio pcm without playback
2982 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2983 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2985 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2987 [case 2] deinterleave for each channel without playback
2988 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2989 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2991 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2992 - fakesink (sync or not)
2995 [case 3] [case 1(sync only)] + playback
2996 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2998 * src - ... - tee - queue1 - playback path
2999 - queue2 - [case1 pipeline with sync]
3001 [case 4] [case 2(sync only)] + playback
3002 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3004 * src - ... - tee - queue1 - playback path
3005 - queue2 - [case2 pipeline with sync]
3009 /* 1. create tee and playback path
3010 'tee' should be added at first to copy the decoded stream
3012 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3013 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3014 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3016 /* tee - path 1 : for playback path */
3017 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3018 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3020 /* tee - path 2 : for extract path */
3021 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3022 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3025 /* if there is tee, 'tee - path 2' is linked here */
3027 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3030 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3032 /* 2. decide the extract pcm format */
3033 mm_attrs_multiple_get(player->attrs, NULL,
3034 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3035 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3036 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3039 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3040 dst_format, dst_len, dst_samplerate, dst_channels);
3042 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3043 mm_attrs_multiple_get(player->attrs, NULL,
3044 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3045 "content_audio_samplerate", &dst_samplerate,
3046 "content_audio_channels", &dst_channels,
3049 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3050 dst_format, dst_len, dst_samplerate, dst_channels);
3052 /* If there is no enough information, set it to platform default value. */
3053 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3054 LOGD("set platform default format");
3055 dst_format = DEFAULT_PCM_OUT_FORMAT;
3057 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3058 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3061 /* 3. create capsfilter */
3062 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3063 caps = gst_caps_new_simple("audio/x-raw",
3064 "format", G_TYPE_STRING, dst_format,
3065 "rate", G_TYPE_INT, dst_samplerate,
3066 "channels", G_TYPE_INT, dst_channels,
3069 caps_str = gst_caps_to_string(caps);
3070 LOGD("new caps : %s", caps_str);
3072 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3075 gst_caps_unref(caps);
3076 MMPLAYER_FREEIF(caps_str);
3078 /* 4-1. create deinterleave to extract pcm for each channel */
3079 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3080 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3081 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3083 /* audiosink will be added after getting signal for each channel */
3084 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3085 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3086 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3087 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3088 player->no_more_pad = FALSE;
3090 /* 4-2. create fakesink to extract interleaved pcm */
3091 LOGD("add audio fakesink for interleaved audio");
3092 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3093 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3094 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3095 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3097 _mmplayer_add_signal_connection(player,
3098 G_OBJECT(audiobin[extract_sink_id].gst),
3099 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3101 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3104 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3108 return MM_ERROR_NONE;
3110 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3112 return MM_ERROR_PLAYER_INTERNAL;
3116 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3118 int ret = MM_ERROR_NONE;
3119 mmplayer_gst_element_t *audiobin = NULL;
3120 GList *element_bucket = NULL;
3123 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3124 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3126 audiobin = player->pipeline->audiobin;
3128 if (player->build_audio_offload) { /* skip all the audio filters */
3129 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3131 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3132 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3133 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3135 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3139 /* FIXME: need to mention the supportable condition at API reference */
3140 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3141 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3143 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3145 if (ret != MM_ERROR_NONE)
3148 LOGD("success to make audio bin element");
3149 *bucket = element_bucket;
3152 return MM_ERROR_NONE;
3155 LOGE("failed to make audio bin element");
3156 g_list_free(element_bucket);
3160 return MM_ERROR_PLAYER_INTERNAL;
3164 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3166 mmplayer_gst_element_t *first_element = NULL;
3167 mmplayer_gst_element_t *audiobin = NULL;
3169 GstPad *ghostpad = NULL;
3170 GList *element_bucket = NULL;
3174 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3177 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3179 LOGE("failed to allocate memory for audiobin");
3180 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3184 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3185 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3186 if (!audiobin[MMPLAYER_A_BIN].gst) {
3187 LOGE("failed to create audiobin");
3192 player->pipeline->audiobin = audiobin;
3194 /* create audio filters and audiosink */
3195 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3198 /* adding created elements to bin */
3199 LOGD("adding created elements to bin");
3200 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3203 /* linking elements in the bucket by added order. */
3204 LOGD("Linking elements in the bucket by added order.");
3205 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3208 /* get first element's sinkpad for creating ghostpad */
3209 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3210 if (!first_element) {
3211 LOGE("failed to get first elem");
3215 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3217 LOGE("failed to get pad from first element of audiobin");
3221 ghostpad = gst_ghost_pad_new("sink", pad);
3223 LOGE("failed to create ghostpad");
3227 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3228 LOGE("failed to add ghostpad to audiobin");
3232 gst_object_unref(pad);
3234 g_list_free(element_bucket);
3237 return MM_ERROR_NONE;
3240 LOGD("ERROR : releasing audiobin");
3243 gst_object_unref(GST_OBJECT(pad));
3246 gst_object_unref(GST_OBJECT(ghostpad));
3249 g_list_free(element_bucket);
3251 /* release element which are not added to bin */
3252 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3253 /* NOTE : skip bin */
3254 if (audiobin[i].gst) {
3255 GstObject *parent = NULL;
3256 parent = gst_element_get_parent(audiobin[i].gst);
3259 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3260 audiobin[i].gst = NULL;
3262 gst_object_unref(GST_OBJECT(parent));
3266 /* release audiobin with it's children */
3267 if (audiobin[MMPLAYER_A_BIN].gst)
3268 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3270 MMPLAYER_FREEIF(audiobin);
3272 player->pipeline->audiobin = NULL;
3274 return MM_ERROR_PLAYER_INTERNAL;
3278 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3280 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3284 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3286 int ret = MM_ERROR_NONE;
3288 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3289 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3291 MMPLAYER_VIDEO_BO_LOCK(player);
3293 if (player->video_bo_list) {
3294 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3295 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3296 if (tmp && tmp->bo == bo) {
3298 LOGD("release bo %p", bo);
3299 tbm_bo_unref(tmp->bo);
3300 MMPLAYER_VIDEO_BO_UNLOCK(player);
3301 MMPLAYER_VIDEO_BO_SIGNAL(player);
3306 /* hw codec is running or the list was reset for DRC. */
3307 LOGW("there is no bo list.");
3309 MMPLAYER_VIDEO_BO_UNLOCK(player);
3311 LOGW("failed to find bo %p", bo);
3315 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3321 tbm_bo_unref(tmp->bo);
3326 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3329 MMPLAYER_RETURN_IF_FAIL(player);
3331 MMPLAYER_VIDEO_BO_LOCK(player);
3332 if (player->video_bo_list) {
3333 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3334 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3335 player->video_bo_list = NULL;
3337 player->video_bo_size = 0;
3338 MMPLAYER_VIDEO_BO_UNLOCK(player);
3345 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3348 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3349 gboolean ret = TRUE;
3350 gint64 end_time = 0;
3352 /* check DRC, if it is, destroy the prev bo list to create again */
3353 if (player->video_bo_size != size) {
3354 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3355 __mmplayer_video_stream_destroy_bo_list(player);
3356 player->video_bo_size = size;
3359 MMPLAYER_VIDEO_BO_LOCK(player);
3361 if ((!player->video_bo_list) ||
3362 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3364 /* create bo list */
3366 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3368 if (player->video_bo_list) {
3369 /* if bo list did not created all, try it again. */
3370 idx = g_list_length(player->video_bo_list);
3371 LOGD("bo list exist(len: %d)", idx);
3374 for (; idx < player->ini.num_of_video_bo; idx++) {
3375 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3377 LOGE("Fail to alloc bo_info.");
3380 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3382 LOGE("Fail to tbm_bo_alloc.");
3383 MMPLAYER_FREEIF(bo_info);
3386 bo_info->used = FALSE;
3387 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3390 /* update video num buffers */
3391 LOGD("video_num_buffers : %d", idx);
3392 mm_player_set_attribute((MMHandleType)player, NULL,
3393 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3394 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3398 MMPLAYER_VIDEO_BO_UNLOCK(player);
3403 if (player->ini.video_bo_timeout > 0)
3404 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3407 /* get bo from list*/
3408 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3409 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3410 if (tmp && (tmp->used == FALSE)) {
3411 LOGD("found bo %p to use", tmp->bo);
3413 MMPLAYER_VIDEO_BO_UNLOCK(player);
3414 return tbm_bo_ref(tmp->bo);
3418 if (player->ini.video_bo_timeout <= 0) {
3419 MMPLAYER_VIDEO_BO_WAIT(player);
3421 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3423 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3429 MMPLAYER_VIDEO_BO_UNLOCK(player);
3434 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3436 mmplayer_t *player = (mmplayer_t *)data;
3438 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3440 /* send prerolled pkt */
3441 player->video_stream_prerolled = false;
3443 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3445 /* not to send prerolled pkt again */
3446 player->video_stream_prerolled = true;
3450 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3452 mmplayer_t *player = (mmplayer_t *)data;
3453 mmplayer_video_decoded_data_info_t *stream = NULL;
3454 GstMemory *mem = NULL;
3457 MMPLAYER_RETURN_IF_FAIL(player);
3458 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3460 if (player->video_stream_prerolled) {
3461 player->video_stream_prerolled = false;
3462 LOGD("skip the prerolled pkt not to send it again");
3466 /* clear stream data structure */
3467 stream = __mmplayer_create_stream_from_pad(pad);
3469 LOGE("failed to alloc stream");
3473 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3475 /* set size and timestamp */
3476 mem = gst_buffer_peek_memory(buffer, 0);
3477 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3478 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3480 /* check zero-copy */
3481 if (player->set_mode.video_zc &&
3482 player->set_mode.video_export &&
3483 gst_is_tizen_memory(mem)) {
3484 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3485 stream->internal_buffer = gst_buffer_ref(buffer);
3486 } else { /* sw codec */
3487 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3490 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3494 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3495 LOGE("failed to send video decoded data.");
3502 LOGE("release video stream resource.");
3503 if (gst_is_tizen_memory(mem)) {
3505 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3507 tbm_bo_unref(stream->bo[i]);
3510 /* unref gst buffer */
3511 if (stream->internal_buffer)
3512 gst_buffer_unref(stream->internal_buffer);
3515 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3517 MMPLAYER_FREEIF(stream);
3522 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3524 mmplayer_gst_element_t *videobin = NULL;
3527 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3529 videobin = player->pipeline->videobin;
3531 /* Set spatial media metadata and/or user settings to the element.
3533 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3534 "projection-type", player->video360_metadata.projection_type, NULL);
3536 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3537 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3539 if (player->video360_metadata.full_pano_width_pixels &&
3540 player->video360_metadata.full_pano_height_pixels &&
3541 player->video360_metadata.cropped_area_image_width &&
3542 player->video360_metadata.cropped_area_image_height) {
3543 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3544 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3545 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3546 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3547 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3548 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3549 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3553 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3554 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3555 "horizontal-fov", player->video360_horizontal_fov,
3556 "vertical-fov", player->video360_vertical_fov, NULL);
3559 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3560 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3561 "zoom", 1.0f / player->video360_zoom, NULL);
3564 if (player->video360_yaw_radians <= M_PI &&
3565 player->video360_yaw_radians >= -M_PI &&
3566 player->video360_pitch_radians <= M_PI_2 &&
3567 player->video360_pitch_radians >= -M_PI_2) {
3568 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3569 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3570 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3571 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3572 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3573 "pose-yaw", player->video360_metadata.init_view_heading,
3574 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3577 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3578 "passthrough", !player->is_video360_enabled, NULL);
3585 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3587 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3588 GList *element_bucket = NULL;
3591 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3593 /* create video360 filter */
3594 if (player->is_360_feature_enabled && player->is_content_spherical) {
3595 LOGD("create video360 element");
3596 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3597 __mmplayer_gst_set_video360_property(player);
3601 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3602 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3603 player->set_mode.video_zc) {
3604 LOGD("skip creating the videoconv and rotator");
3605 return MM_ERROR_NONE;
3608 /* in case of sw codec & overlay surface type, except 360 playback.
3609 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3610 LOGD("create video converter: %s", video_csc);
3611 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3614 *bucket = element_bucket;
3616 return MM_ERROR_NONE;
3618 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3619 g_list_free(element_bucket);
3623 return MM_ERROR_PLAYER_INTERNAL;
3627 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3629 gchar *factory_name = NULL;
3631 switch (surface_type) {
3632 case MM_DISPLAY_SURFACE_OVERLAY:
3634 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3635 if (strlen(player->ini.videosink_element_overlay) > 0)
3636 factory_name = player->ini.videosink_element_overlay;
3638 case MM_DISPLAY_SURFACE_REMOTE:
3640 case MM_DISPLAY_SURFACE_NULL:
3641 if (strlen(player->ini.videosink_element_fake) > 0)
3642 factory_name = player->ini.videosink_element_fake;
3645 LOGE("unidentified surface type");
3649 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3650 return factory_name;
3654 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3656 gchar *factory_name = NULL;
3657 mmplayer_gst_element_t *videobin = NULL;
3662 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3664 videobin = player->pipeline->videobin;
3665 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3667 attrs = MMPLAYER_GET_ATTRS(player);
3669 LOGE("cannot get content attribute");
3670 return MM_ERROR_PLAYER_INTERNAL;
3673 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3674 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3675 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3676 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3677 "use-tbm", use_tbm, NULL);
3680 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3681 return MM_ERROR_PLAYER_INTERNAL;
3683 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3686 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3687 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3690 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3692 LOGD("disable last-sample");
3693 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3696 if (player->set_mode.video_export) {
3698 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3699 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3700 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3702 _mmplayer_add_signal_connection(player,
3703 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3704 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3706 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3709 _mmplayer_add_signal_connection(player,
3710 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3711 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3713 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3717 if (videobin[MMPLAYER_V_SINK].gst) {
3718 GstPad *sink_pad = NULL;
3719 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3721 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3722 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3723 gst_object_unref(GST_OBJECT(sink_pad));
3725 LOGE("failed to get sink pad from videosink");
3729 return MM_ERROR_NONE;
3734 * - video overlay surface(arm/x86) : tizenwlsink
3737 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3740 GList *element_bucket = NULL;
3741 mmplayer_gst_element_t *first_element = NULL;
3742 mmplayer_gst_element_t *videobin = NULL;
3743 gchar *videosink_factory_name = NULL;
3746 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3749 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3751 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3753 player->pipeline->videobin = videobin;
3756 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3757 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3758 if (!videobin[MMPLAYER_V_BIN].gst) {
3759 LOGE("failed to create videobin");
3763 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3766 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3767 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3769 /* additional setting for sink plug-in */
3770 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3771 LOGE("failed to set video property");
3775 /* store it as it's sink element */
3776 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3778 /* adding created elements to bin */
3779 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3780 LOGE("failed to add elements");
3784 /* Linking elements in the bucket by added order */
3785 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3786 LOGE("failed to link elements");
3790 /* get first element's sinkpad for creating ghostpad */
3791 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3792 if (!first_element) {
3793 LOGE("failed to get first element from bucket");
3797 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3799 LOGE("failed to get pad from first element");
3803 /* create ghostpad */
3804 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3805 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3806 LOGE("failed to add ghostpad to videobin");
3809 gst_object_unref(pad);
3811 /* done. free allocated variables */
3812 g_list_free(element_bucket);
3816 return MM_ERROR_NONE;
3819 LOGE("ERROR : releasing videobin");
3820 g_list_free(element_bucket);
3823 gst_object_unref(GST_OBJECT(pad));
3825 /* release videobin with it's children */
3826 if (videobin[MMPLAYER_V_BIN].gst)
3827 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3829 MMPLAYER_FREEIF(videobin);
3830 player->pipeline->videobin = NULL;
3832 return MM_ERROR_PLAYER_INTERNAL;
3836 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3838 GList *element_bucket = NULL;
3839 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3841 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3842 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3843 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3844 "signal-handoffs", FALSE,
3847 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3848 _mmplayer_add_signal_connection(player,
3849 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3850 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3852 G_CALLBACK(__mmplayer_update_subtitle),
3855 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3856 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3858 if (!player->play_subtitle) {
3859 LOGD("add textbin sink as sink element of whole pipeline.");
3860 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3863 /* adding created elements to bin */
3864 LOGD("adding created elements to bin");
3865 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3866 LOGE("failed to add elements");
3870 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3871 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3872 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3874 /* linking elements in the bucket by added order. */
3875 LOGD("Linking elements in the bucket by added order.");
3876 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3877 LOGE("failed to link elements");
3881 if (textbin[MMPLAYER_T_QUEUE].gst) {
3883 GstPad *ghostpad = NULL;
3885 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3887 LOGE("failed to get sink pad of text queue");
3891 ghostpad = gst_ghost_pad_new("text_sink", pad);
3892 gst_object_unref(pad);
3895 LOGE("failed to create ghostpad of textbin");
3899 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3900 LOGE("failed to add ghostpad to textbin");
3901 gst_object_unref(ghostpad);
3906 g_list_free(element_bucket);
3908 return MM_ERROR_NONE;
3912 g_list_free(element_bucket);
3914 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3915 LOGE("remove textbin sink from sink list");
3916 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3919 /* release element at __mmplayer_gst_create_text_sink_bin */
3920 return MM_ERROR_PLAYER_INTERNAL;
3924 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3926 mmplayer_gst_element_t *textbin = NULL;
3927 int surface_type = 0;
3932 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3935 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3937 LOGE("failed to allocate memory for textbin");
3938 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3942 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3943 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3944 if (!textbin[MMPLAYER_T_BIN].gst) {
3945 LOGE("failed to create textbin");
3950 player->pipeline->textbin = textbin;
3953 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3954 LOGD("surface type for subtitle : %d", surface_type);
3955 switch (surface_type) {
3956 case MM_DISPLAY_SURFACE_OVERLAY:
3957 case MM_DISPLAY_SURFACE_NULL:
3958 case MM_DISPLAY_SURFACE_REMOTE:
3959 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3960 LOGE("failed to make plain text elements");
3971 return MM_ERROR_NONE;
3975 LOGD("ERROR : releasing textbin");
3977 /* release signal */
3978 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3980 /* release element which are not added to bin */
3981 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3982 /* NOTE : skip bin */
3983 if (textbin[i].gst) {
3984 GstObject *parent = NULL;
3985 parent = gst_element_get_parent(textbin[i].gst);
3988 gst_object_unref(GST_OBJECT(textbin[i].gst));
3989 textbin[i].gst = NULL;
3991 gst_object_unref(GST_OBJECT(parent));
3996 /* release textbin with it's children */
3997 if (textbin[MMPLAYER_T_BIN].gst)
3998 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4000 MMPLAYER_FREEIF(textbin);
4001 player->pipeline->textbin = NULL;
4004 return MM_ERROR_PLAYER_INTERNAL;
4008 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4010 mmplayer_gst_element_t *mainbin = NULL;
4011 mmplayer_gst_element_t *textbin = NULL;
4012 MMHandleType attrs = 0;
4013 GstElement *subsrc = NULL;
4014 GstElement *subparse = NULL;
4015 gchar *subtitle_uri = NULL;
4016 const gchar *charset = NULL;
4022 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4024 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4026 mainbin = player->pipeline->mainbin;
4028 attrs = MMPLAYER_GET_ATTRS(player);
4030 LOGE("cannot get content attribute");
4031 return MM_ERROR_PLAYER_INTERNAL;
4034 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4035 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4036 LOGE("subtitle uri is not proper filepath.");
4037 return MM_ERROR_PLAYER_INVALID_URI;
4040 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4041 LOGE("failed to get storage info of subtitle path");
4042 return MM_ERROR_PLAYER_INVALID_URI;
4045 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4047 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4048 player->subtitle_language_list = NULL;
4049 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4051 /* create the subtitle source */
4052 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4054 LOGE("failed to create filesrc element");
4057 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4059 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4060 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4062 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4063 LOGW("failed to add queue");
4064 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4065 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4066 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4071 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4073 LOGE("failed to create subparse element");
4077 charset = _mmplayer_get_charset(subtitle_uri);
4079 LOGD("detected charset is %s", charset);
4080 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4083 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4084 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4086 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4087 LOGW("failed to add subparse");
4088 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4089 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4090 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4094 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4095 LOGW("failed to link subsrc and subparse");
4099 player->play_subtitle = TRUE;
4100 player->adjust_subtitle_pos = 0;
4102 LOGD("play subtitle using subtitle file");
4104 if (player->pipeline->textbin == NULL) {
4105 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4106 LOGE("failed to create text sink bin. continuing without text");
4110 textbin = player->pipeline->textbin;
4112 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4113 LOGW("failed to add textbin");
4115 /* release signal */
4116 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4118 /* release textbin with it's children */
4119 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4120 MMPLAYER_FREEIF(player->pipeline->textbin);
4121 player->pipeline->textbin = textbin = NULL;
4125 LOGD("link text input selector and textbin ghost pad");
4127 player->textsink_linked = 1;
4128 player->external_text_idx = 0;
4129 LOGI("textsink is linked");
4131 textbin = player->pipeline->textbin;
4132 LOGD("text bin has been created. reuse it.");
4133 player->external_text_idx = 1;
4136 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4137 LOGW("failed to link subparse and textbin");
4141 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4143 LOGE("failed to get sink pad from textsink to probe data");
4147 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4148 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4150 gst_object_unref(pad);
4153 /* create dot. for debugging */
4154 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4157 return MM_ERROR_NONE;
4160 /* release text pipeline resource */
4161 player->textsink_linked = 0;
4163 /* release signal */
4164 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4166 if (player->pipeline->textbin) {
4167 LOGE("remove textbin");
4169 /* release textbin with it's children */
4170 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4171 MMPLAYER_FREEIF(player->pipeline->textbin);
4172 player->pipeline->textbin = NULL;
4176 /* release subtitle elem */
4177 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4178 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4180 return MM_ERROR_PLAYER_INTERNAL;
4184 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4186 mmplayer_t *player = (mmplayer_t *)data;
4187 MMMessageParamType msg = {0, };
4188 GstClockTime duration = 0;
4189 gpointer text = NULL;
4190 guint text_size = 0;
4191 gboolean ret = TRUE;
4192 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4196 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4197 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4199 if (player->is_subtitle_force_drop) {
4200 LOGW("subtitle is dropped forcedly.");
4204 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4205 text = mapinfo.data;
4206 text_size = mapinfo.size;
4208 if (player->set_mode.subtitle_off) {
4209 LOGD("subtitle is OFF.");
4213 if (!text || (text_size == 0)) {
4214 LOGD("There is no subtitle to be displayed.");
4218 msg.data = (void *)text;
4220 duration = GST_BUFFER_DURATION(buffer);
4222 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4223 if (player->duration > GST_BUFFER_PTS(buffer))
4224 duration = player->duration - GST_BUFFER_PTS(buffer);
4227 LOGI("subtitle duration is invalid, subtitle duration change "
4228 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4230 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4232 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4234 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4235 gst_buffer_unmap(buffer, &mapinfo);
4242 static GstPadProbeReturn
4243 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4245 mmplayer_t *player = (mmplayer_t *)u_data;
4246 GstClockTime cur_timestamp = 0;
4247 gint64 adjusted_timestamp = 0;
4248 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4250 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4252 if (player->set_mode.subtitle_off) {
4253 LOGD("subtitle is OFF.");
4257 if (player->adjust_subtitle_pos == 0) {
4258 LOGD("nothing to do");
4262 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4263 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4265 if (adjusted_timestamp < 0) {
4266 LOGD("adjusted_timestamp under zero");
4271 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4272 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4273 GST_TIME_ARGS(cur_timestamp),
4274 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4276 return GST_PAD_PROBE_OK;
4280 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4284 /* check player and subtitlebin are created */
4285 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4286 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4288 if (position == 0) {
4289 LOGD("nothing to do");
4291 return MM_ERROR_NONE;
4294 /* check current position */
4295 player->adjust_subtitle_pos = position;
4297 LOGD("save adjust_subtitle_pos in player");
4301 return MM_ERROR_NONE;
4305 * This function is to create audio or video pipeline for playing.
4307 * @param player [in] handle of player
4309 * @return This function returns zero on success.
4314 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4316 int ret = MM_ERROR_NONE;
4317 mmplayer_gst_element_t *mainbin = NULL;
4318 MMHandleType attrs = 0;
4321 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4323 /* get profile attribute */
4324 attrs = MMPLAYER_GET_ATTRS(player);
4326 LOGE("failed to get content attribute");
4330 /* create pipeline handles */
4331 if (player->pipeline) {
4332 LOGE("pipeline should be released before create new one");
4336 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4338 /* create mainbin */
4339 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4340 if (mainbin == NULL)
4343 /* create pipeline */
4344 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4345 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4346 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4347 LOGE("failed to create pipeline");
4352 player->pipeline->mainbin = mainbin;
4354 /* create the source and decoder elements */
4355 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4356 ret = _mmplayer_gst_build_es_pipeline(player);
4358 if (MMPLAYER_USE_DECODEBIN(player))
4359 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4361 ret = _mmplayer_gst_build_pipeline_with_src(player);
4364 if (ret != MM_ERROR_NONE) {
4365 LOGE("failed to create some elements");
4369 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4370 if (__mmplayer_check_subtitle(player)
4371 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4372 LOGE("failed to create text pipeline");
4375 ret = _mmplayer_gst_add_bus_watch(player);
4376 if (ret != MM_ERROR_NONE) {
4377 LOGE("failed to add bus watch");
4382 return MM_ERROR_NONE;
4385 _mmplayer_bus_watcher_remove(player);
4386 __mmplayer_gst_destroy_pipeline(player);
4387 return MM_ERROR_PLAYER_INTERNAL;
4391 __mmplayer_reset_gapless_state(mmplayer_t *player)
4394 MMPLAYER_RETURN_IF_FAIL(player
4396 && player->pipeline->audiobin
4397 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4399 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4406 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4409 int ret = MM_ERROR_NONE;
4413 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4415 /* cleanup stuffs */
4416 MMPLAYER_FREEIF(player->type);
4417 player->no_more_pad = FALSE;
4418 player->num_dynamic_pad = 0;
4420 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4421 player->subtitle_language_list = NULL;
4422 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4424 MMPLAYER_RECONFIGURE_LOCK(player);
4425 __mmplayer_reset_gapless_state(player);
4426 MMPLAYER_RECONFIGURE_UNLOCK(player);
4428 if (player->streamer) {
4429 _mm_player_streaming_initialize(player->streamer, FALSE);
4430 _mm_player_streaming_destroy(player->streamer);
4431 player->streamer = NULL;
4434 /* cleanup unlinked mime type */
4435 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4436 MMPLAYER_FREEIF(player->unlinked_video_mime);
4437 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4439 /* cleanup running stuffs */
4440 _mmplayer_cancel_eos_timer(player);
4442 /* cleanup gst stuffs */
4443 if (player->pipeline) {
4444 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4445 GstTagList *tag_list = player->pipeline->tag_list;
4447 /* first we need to disconnect all signal hander */
4448 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4451 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4452 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4453 gst_object_unref(bus);
4455 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4456 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4457 if (ret != MM_ERROR_NONE) {
4458 LOGE("fail to change state to NULL");
4459 return MM_ERROR_PLAYER_INTERNAL;
4462 LOGW("succeeded in changing state to NULL");
4464 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4467 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4468 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4470 MMPLAYER_FREEIF(player->pipeline->audiobin);
4471 MMPLAYER_FREEIF(player->pipeline->videobin);
4472 MMPLAYER_FREEIF(player->pipeline->textbin);
4473 MMPLAYER_FREEIF(mainbin);
4477 gst_tag_list_unref(tag_list);
4479 MMPLAYER_FREEIF(player->pipeline);
4481 MMPLAYER_FREEIF(player->album_art);
4483 if (player->type_caps) {
4484 gst_caps_unref(player->type_caps);
4485 player->type_caps = NULL;
4488 if (player->v_stream_caps) {
4489 gst_caps_unref(player->v_stream_caps);
4490 player->v_stream_caps = NULL;
4493 if (player->a_stream_caps) {
4494 gst_caps_unref(player->a_stream_caps);
4495 player->a_stream_caps = NULL;
4498 if (player->s_stream_caps) {
4499 gst_caps_unref(player->s_stream_caps);
4500 player->s_stream_caps = NULL;
4502 _mmplayer_track_destroy(player);
4504 if (player->sink_elements)
4505 g_list_free(player->sink_elements);
4506 player->sink_elements = NULL;
4508 if (player->bufmgr) {
4509 tbm_bufmgr_deinit(player->bufmgr);
4510 player->bufmgr = NULL;
4513 LOGW("finished destroy pipeline");
4521 __mmplayer_gst_realize(mmplayer_t *player)
4524 int ret = MM_ERROR_NONE;
4528 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4530 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4532 ret = __mmplayer_gst_create_pipeline(player);
4534 LOGE("failed to create pipeline");
4538 /* set pipeline state to READY */
4539 /* NOTE : state change to READY must be performed sync. */
4540 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4541 ret = _mmplayer_gst_set_state(player,
4542 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4544 if (ret != MM_ERROR_NONE) {
4545 /* return error if failed to set state */
4546 LOGE("failed to set READY state");
4550 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4552 /* create dot before error-return. for debugging */
4553 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4561 __mmplayer_gst_unrealize(mmplayer_t *player)
4563 int ret = MM_ERROR_NONE;
4567 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4569 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4570 MMPLAYER_PRINT_STATE(player);
4572 /* release miscellaneous information */
4573 __mmplayer_release_misc(player);
4575 /* destroy pipeline */
4576 ret = __mmplayer_gst_destroy_pipeline(player);
4577 if (ret != MM_ERROR_NONE) {
4578 LOGE("failed to destroy pipeline");
4582 /* release miscellaneous information.
4583 these info needs to be released after pipeline is destroyed. */
4584 __mmplayer_release_misc_post(player);
4586 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4594 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4599 LOGW("set_message_callback is called with invalid player handle");
4600 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4603 player->msg_cb = callback;
4604 player->msg_cb_param = user_param;
4606 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4610 return MM_ERROR_NONE;
4614 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4616 int ret = MM_ERROR_NONE;
4621 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4622 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4623 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4625 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4627 if (strstr(uri, "es_buff://")) {
4628 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4629 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4630 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4631 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4633 tmp = g_ascii_strdown(uri, strlen(uri));
4634 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4635 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4637 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4639 } else if (strstr(uri, "mms://")) {
4640 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4641 } else if ((path = strstr(uri, "mem://"))) {
4642 ret = __mmplayer_set_mem_uri(data, path, param);
4644 ret = __mmplayer_set_file_uri(data, uri);
4647 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4648 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4649 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4650 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4652 /* dump parse result */
4653 SECURE_LOGW("incoming uri : %s", uri);
4654 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4655 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4663 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4666 mmplayer_t *player = NULL;
4667 MMMessageParamType msg = {0, };
4669 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4674 LOGE("user_data is null");
4678 player = (mmplayer_t *)user_data;
4680 if (!player->pipeline || !player->attrs) {
4681 LOGW("not initialized");
4685 LOGD("cmd lock player, cmd state : %d", player->cmd);
4686 MMPLAYER_CMD_LOCK(player);
4687 LOGD("cmd locked player");
4689 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4690 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4691 LOGW("player already destroyed");
4692 MMPLAYER_CMD_UNLOCK(player);
4696 player->interrupted_by_resource = TRUE;
4698 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4700 /* get last play position */
4701 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4702 msg.union_type = MM_MSG_UNION_TIME;
4703 msg.time.elapsed = pos;
4704 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4706 LOGW("failed to get play position.");
4709 LOGD("video resource conflict so, resource will be freed by unrealizing");
4710 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4711 LOGE("failed to unrealize");
4713 MMPLAYER_CMD_UNLOCK(player);
4715 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4716 player->hw_resource[res_idx] = NULL;
4720 return TRUE; /* release all the resources */
4724 __mmplayer_initialize_video_roi(mmplayer_t *player)
4726 player->video_roi.scale_x = 0.0;
4727 player->video_roi.scale_y = 0.0;
4728 player->video_roi.scale_width = 1.0;
4729 player->video_roi.scale_height = 1.0;
4733 _mmplayer_create_player(MMHandleType handle)
4735 int ret = MM_ERROR_PLAYER_INTERNAL;
4736 bool enabled = false;
4738 mmplayer_t *player = MM_PLAYER_CAST(handle);
4742 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4744 /* initialize player state */
4745 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4746 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4747 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4748 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4750 /* check current state */
4751 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4753 /* construct attributes */
4754 player->attrs = _mmplayer_construct_attribute(handle);
4756 if (!player->attrs) {
4757 LOGE("Failed to construct attributes");
4761 /* initialize gstreamer with configured parameter */
4762 if (!__mmplayer_init_gstreamer(player)) {
4763 LOGE("Initializing gstreamer failed");
4764 _mmplayer_deconstruct_attribute(handle);
4768 /* create lock. note that g_tread_init() has already called in gst_init() */
4769 g_mutex_init(&player->fsink_lock);
4771 /* create update tag lock */
4772 g_mutex_init(&player->update_tag_lock);
4774 /* create gapless play mutex */
4775 g_mutex_init(&player->gapless_play_thread_mutex);
4777 /* create gapless play cond */
4778 g_cond_init(&player->gapless_play_thread_cond);
4780 /* create gapless play thread */
4781 player->gapless_play_thread =
4782 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4783 if (!player->gapless_play_thread) {
4784 LOGE("failed to create gapless play thread");
4785 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4786 g_mutex_clear(&player->gapless_play_thread_mutex);
4787 g_cond_clear(&player->gapless_play_thread_cond);
4791 player->bus_msg_q = g_queue_new();
4792 if (!player->bus_msg_q) {
4793 LOGE("failed to create queue for bus_msg");
4794 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4798 ret = _mmplayer_initialize_video_capture(player);
4799 if (ret != MM_ERROR_NONE) {
4800 LOGW("video capture is not supported");
4801 /* do not handle as error for headless profile */
4804 /* initialize resource manager */
4805 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4806 __resource_release_cb, player, &player->resource_manager)
4807 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4808 LOGE("failed to create resource manager");
4809 ret = MM_ERROR_PLAYER_INTERNAL;
4813 /* create video bo lock and cond */
4814 g_mutex_init(&player->video_bo_mutex);
4815 g_cond_init(&player->video_bo_cond);
4817 /* create subtitle info lock and cond */
4818 g_mutex_init(&player->subtitle_info_mutex);
4819 g_cond_init(&player->subtitle_info_cond);
4821 player->streaming_type = STREAMING_SERVICE_NONE;
4823 /* give default value of audio effect setting */
4824 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4825 player->sound.rg_enable = false;
4826 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4828 player->play_subtitle = FALSE;
4829 player->has_closed_caption = FALSE;
4830 player->pending_resume = FALSE;
4831 if (player->ini.dump_element_keyword[0][0] == '\0')
4832 player->ini.set_dump_element_flag = FALSE;
4834 player->ini.set_dump_element_flag = TRUE;
4836 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4837 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4838 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4840 /* Set video360 settings to their defaults for just-created player.
4843 player->is_360_feature_enabled = FALSE;
4844 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4845 LOGI("spherical feature info: %d", enabled);
4847 player->is_360_feature_enabled = TRUE;
4849 LOGE("failed to get spherical feature info");
4852 player->is_content_spherical = FALSE;
4853 player->is_video360_enabled = TRUE;
4854 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4855 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4856 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4857 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4858 player->video360_zoom = 1.0f;
4859 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4860 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4862 __mmplayer_initialize_video_roi(player);
4864 /* set player state to null */
4865 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4866 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4870 return MM_ERROR_NONE;
4874 g_mutex_clear(&player->fsink_lock);
4875 /* free update tag lock */
4876 g_mutex_clear(&player->update_tag_lock);
4877 g_queue_free(player->bus_msg_q);
4878 player->bus_msg_q = NULL;
4879 /* free gapless play thread */
4880 if (player->gapless_play_thread) {
4881 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4882 player->gapless_play_thread_exit = TRUE;
4883 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4884 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4886 g_thread_join(player->gapless_play_thread);
4887 player->gapless_play_thread = NULL;
4889 g_mutex_clear(&player->gapless_play_thread_mutex);
4890 g_cond_clear(&player->gapless_play_thread_cond);
4893 /* release attributes */
4894 _mmplayer_deconstruct_attribute(handle);
4902 __mmplayer_init_gstreamer(mmplayer_t *player)
4904 static gboolean initialized = FALSE;
4905 static const int max_argc = 50;
4907 gchar **argv = NULL;
4908 gchar **argv2 = NULL;
4914 LOGD("gstreamer already initialized.");
4919 argc = malloc(sizeof(int));
4920 argv = malloc(sizeof(gchar *) * max_argc);
4921 argv2 = malloc(sizeof(gchar *) * max_argc);
4923 if (!argc || !argv || !argv2)
4926 memset(argv, 0, sizeof(gchar *) * max_argc);
4927 memset(argv2, 0, sizeof(gchar *) * max_argc);
4931 argv[0] = g_strdup("mmplayer");
4934 for (i = 0; i < 5; i++) {
4935 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4936 if (strlen(player->ini.gst_param[i]) > 0) {
4937 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4942 /* we would not do fork for scanning plugins */
4943 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4946 /* check disable registry scan */
4947 if (player->ini.skip_rescan) {
4948 argv[*argc] = g_strdup("--gst-disable-registry-update");
4952 /* check disable segtrap */
4953 if (player->ini.disable_segtrap) {
4954 argv[*argc] = g_strdup("--gst-disable-segtrap");
4958 LOGD("initializing gstreamer with following parameter");
4959 LOGD("argc : %d", *argc);
4962 for (i = 0; i < arg_count; i++) {
4964 LOGD("argv[%d] : %s", i, argv2[i]);
4967 /* initializing gstreamer */
4968 if (!gst_init_check(argc, &argv, &err)) {
4969 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4976 for (i = 0; i < arg_count; i++) {
4978 LOGD("release - argv[%d] : %s", i, argv2[i]);
4980 MMPLAYER_FREEIF(argv2[i]);
4983 MMPLAYER_FREEIF(argv);
4984 MMPLAYER_FREEIF(argv2);
4985 MMPLAYER_FREEIF(argc);
4995 for (i = 0; i < arg_count; i++) {
4996 LOGD("free[%d] : %s", i, argv2[i]);
4997 MMPLAYER_FREEIF(argv2[i]);
5000 MMPLAYER_FREEIF(argv);
5001 MMPLAYER_FREEIF(argv2);
5002 MMPLAYER_FREEIF(argc);
5008 __mmplayer_check_async_state_transition(mmplayer_t *player)
5010 GstState element_state = GST_STATE_VOID_PENDING;
5011 GstState element_pending_state = GST_STATE_VOID_PENDING;
5012 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5013 GstElement *element = NULL;
5014 gboolean async = FALSE;
5016 /* check player handle */
5017 MMPLAYER_RETURN_IF_FAIL(player &&
5019 player->pipeline->mainbin &&
5020 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5023 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5025 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5026 LOGD("don't need to check the pipeline state");
5030 MMPLAYER_PRINT_STATE(player);
5032 /* wait for state transition */
5033 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5034 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5036 if (ret == GST_STATE_CHANGE_FAILURE) {
5037 LOGE(" [%s] state : %s pending : %s",
5038 GST_ELEMENT_NAME(element),
5039 gst_element_state_get_name(element_state),
5040 gst_element_state_get_name(element_pending_state));
5042 /* dump state of all element */
5043 _mmplayer_dump_pipeline_state(player);
5048 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5053 _mmplayer_destroy(MMHandleType handle)
5055 mmplayer_t *player = MM_PLAYER_CAST(handle);
5059 /* check player handle */
5060 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5062 /* destroy can called at anytime */
5063 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5065 /* check async state transition */
5066 __mmplayer_check_async_state_transition(player);
5068 /* release gapless play thread */
5069 if (player->gapless_play_thread) {
5070 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5071 player->gapless_play_thread_exit = TRUE;
5072 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5073 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5075 LOGD("waiting for gapless play thread exit");
5076 g_thread_join(player->gapless_play_thread);
5077 g_mutex_clear(&player->gapless_play_thread_mutex);
5078 g_cond_clear(&player->gapless_play_thread_cond);
5079 LOGD("gapless play thread released");
5082 _mmplayer_release_video_capture(player);
5084 /* release miscellaneous information */
5085 __mmplayer_release_misc(player);
5087 /* release pipeline */
5088 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5089 LOGE("failed to destroy pipeline");
5090 return MM_ERROR_PLAYER_INTERNAL;
5093 __mmplayer_destroy_hw_resource(player);
5095 g_queue_free(player->bus_msg_q);
5097 /* release subtitle info lock and cond */
5098 g_mutex_clear(&player->subtitle_info_mutex);
5099 g_cond_clear(&player->subtitle_info_cond);
5101 __mmplayer_release_dump_list(player->dump_list);
5103 /* release miscellaneous information.
5104 these info needs to be released after pipeline is destroyed. */
5105 __mmplayer_release_misc_post(player);
5107 /* release attributes */
5108 _mmplayer_deconstruct_attribute(handle);
5110 if (player->uri_info.uri_list) {
5111 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5112 player->uri_info.uri_list = NULL;
5116 g_mutex_clear(&player->fsink_lock);
5119 g_mutex_clear(&player->update_tag_lock);
5121 /* release video bo lock and cond */
5122 g_mutex_clear(&player->video_bo_mutex);
5123 g_cond_clear(&player->video_bo_cond);
5127 return MM_ERROR_NONE;
5131 _mmplayer_realize(MMHandleType hplayer)
5133 mmplayer_t *player = (mmplayer_t *)hplayer;
5134 int ret = MM_ERROR_NONE;
5137 MMHandleType attrs = 0;
5141 /* check player handle */
5142 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5144 /* check current state */
5145 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5147 attrs = MMPLAYER_GET_ATTRS(player);
5149 LOGE("fail to get attributes.");
5150 return MM_ERROR_PLAYER_INTERNAL;
5152 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5153 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5155 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5156 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5158 if (ret != MM_ERROR_NONE) {
5159 LOGE("failed to parse profile");
5164 if (uri && (strstr(uri, "es_buff://"))) {
5165 if (strstr(uri, "es_buff://push_mode"))
5166 player->es_player_push_mode = TRUE;
5168 player->es_player_push_mode = FALSE;
5171 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5172 LOGW("mms protocol is not supported format.");
5173 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5176 if (MMPLAYER_IS_STREAMING(player))
5177 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5179 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5181 player->smooth_streaming = FALSE;
5182 player->videodec_linked = 0;
5183 player->audiodec_linked = 0;
5184 player->textsink_linked = 0;
5185 player->is_external_subtitle_present = FALSE;
5186 player->is_external_subtitle_added_now = FALSE;
5187 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5188 player->video360_metadata.is_spherical = -1;
5189 player->is_openal_plugin_used = FALSE;
5190 player->subtitle_language_list = NULL;
5191 player->is_subtitle_force_drop = FALSE;
5193 _mmplayer_track_initialize(player);
5194 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5196 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5197 gint prebuffer_ms = 0, rebuffer_ms = 0;
5199 player->streamer = _mm_player_streaming_create();
5200 _mm_player_streaming_initialize(player->streamer, TRUE);
5202 mm_attrs_multiple_get(player->attrs, NULL,
5203 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5204 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5206 if (prebuffer_ms > 0) {
5207 prebuffer_ms = MAX(prebuffer_ms, 1000);
5208 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5211 if (rebuffer_ms > 0) {
5212 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5213 rebuffer_ms = MAX(rebuffer_ms, 1000);
5214 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5217 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5218 player->streamer->buffering_req.rebuffer_time);
5221 /* realize pipeline */
5222 ret = __mmplayer_gst_realize(player);
5223 if (ret != MM_ERROR_NONE)
5224 LOGE("fail to realize the player.");
5226 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5234 _mmplayer_unrealize(MMHandleType hplayer)
5236 mmplayer_t *player = (mmplayer_t *)hplayer;
5237 int ret = MM_ERROR_NONE;
5238 int rm_ret = MM_ERROR_NONE;
5239 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5243 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5245 MMPLAYER_CMD_UNLOCK(player);
5246 _mmplayer_bus_watcher_remove(player);
5247 /* destroy the gst bus msg thread which is created during realize.
5248 this funct have to be called before getting cmd lock. */
5249 _mmplayer_bus_msg_thread_destroy(player);
5250 MMPLAYER_CMD_LOCK(player);
5252 /* check current state */
5253 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5255 /* check async state transition */
5256 __mmplayer_check_async_state_transition(player);
5258 /* unrealize pipeline */
5259 ret = __mmplayer_gst_unrealize(player);
5261 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5262 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5263 if (rm_ret != MM_ERROR_NONE)
5264 LOGE("failed to release [%d] resources", res_idx);
5267 player->interrupted_by_resource = FALSE;
5274 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5276 mmplayer_t *player = (mmplayer_t *)hplayer;
5278 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5280 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5284 _mmplayer_get_state(MMHandleType hplayer, int *state)
5286 mmplayer_t *player = (mmplayer_t *)hplayer;
5288 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5290 *state = MMPLAYER_CURRENT_STATE(player);
5292 return MM_ERROR_NONE;
5296 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5298 GstElement *vol_element = NULL;
5299 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5302 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5303 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5305 /* check pipeline handle */
5306 if (!player->pipeline || !player->pipeline->audiobin) {
5307 LOGD("'%s' will be applied when audiobin is created", prop_name);
5309 /* NOTE : stored value will be used in create_audiobin
5310 * returning MM_ERROR_NONE here makes application to able to
5311 * set audio volume or mute at anytime.
5313 return MM_ERROR_NONE;
5316 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5317 volume_elem_id = MMPLAYER_A_SINK;
5319 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5321 LOGE("failed to get vol element %d", volume_elem_id);
5322 return MM_ERROR_PLAYER_INTERNAL;
5325 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5327 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5328 LOGE("there is no '%s' property", prop_name);
5329 return MM_ERROR_PLAYER_INTERNAL;
5332 if (!strcmp(prop_name, "volume")) {
5333 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5334 } else if (!strcmp(prop_name, "mute")) {
5335 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5337 LOGE("invalid property %s", prop_name);
5338 return MM_ERROR_PLAYER_INTERNAL;
5341 return MM_ERROR_NONE;
5345 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5347 int ret = MM_ERROR_NONE;
5348 mmplayer_t *player = (mmplayer_t *)hplayer;
5351 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5353 LOGD("volume = %f", volume);
5355 /* invalid factor range or not */
5356 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5357 LOGE("Invalid volume value");
5358 return MM_ERROR_INVALID_ARGUMENT;
5361 player->sound.volume = volume;
5363 ret = __mmplayer_gst_set_volume_property(player, "volume");
5370 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5372 mmplayer_t *player = (mmplayer_t *)hplayer;
5376 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5377 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5379 *volume = player->sound.volume;
5381 LOGD("current vol = %f", *volume);
5384 return MM_ERROR_NONE;
5388 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5390 int ret = MM_ERROR_NONE;
5391 mmplayer_t *player = (mmplayer_t *)hplayer;
5394 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5396 LOGD("mute = %d", mute);
5398 player->sound.mute = mute;
5400 ret = __mmplayer_gst_set_volume_property(player, "mute");
5407 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5409 mmplayer_t *player = (mmplayer_t *)hplayer;
5413 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5414 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5416 *mute = player->sound.mute;
5418 LOGD("current mute = %d", *mute);
5422 return MM_ERROR_NONE;
5426 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5428 mmplayer_t *player = (mmplayer_t *)hplayer;
5432 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5434 player->audio_stream_changed_cb = callback;
5435 player->audio_stream_changed_cb_user_param = user_param;
5436 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5440 return MM_ERROR_NONE;
5444 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5446 mmplayer_t *player = (mmplayer_t *)hplayer;
5450 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5452 player->audio_decoded_cb = callback;
5453 player->audio_decoded_cb_user_param = user_param;
5454 player->audio_extract_opt = opt;
5455 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5459 return MM_ERROR_NONE;
5463 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5465 mmplayer_t *player = (mmplayer_t *)hplayer;
5469 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5471 if (callback && !player->bufmgr)
5472 player->bufmgr = tbm_bufmgr_init(-1);
5474 player->set_mode.video_export = (callback) ? true : false;
5475 player->video_decoded_cb = callback;
5476 player->video_decoded_cb_user_param = user_param;
5478 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5482 return MM_ERROR_NONE;
5486 _mmplayer_start(MMHandleType hplayer)
5488 mmplayer_t *player = (mmplayer_t *)hplayer;
5489 gint ret = MM_ERROR_NONE;
5493 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5495 /* check current state */
5496 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5498 /* start pipeline */
5499 ret = _mmplayer_gst_start(player);
5500 if (ret != MM_ERROR_NONE)
5501 LOGE("failed to start player.");
5503 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5504 LOGD("force playing start even during buffering");
5505 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5513 /* NOTE: post "not supported codec message" to application
5514 * when one codec is not found during AUTOPLUGGING in MSL.
5515 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5516 * And, if any codec is not found, don't send message here.
5517 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5520 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5522 MMMessageParamType msg_param;
5523 memset(&msg_param, 0, sizeof(MMMessageParamType));
5524 gboolean post_msg_direct = FALSE;
5528 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5530 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5531 player->not_supported_codec, player->can_support_codec);
5533 if (player->not_found_demuxer) {
5534 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5535 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5537 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5538 MMPLAYER_FREEIF(msg_param.data);
5540 return MM_ERROR_NONE;
5543 if (player->not_supported_codec) {
5544 if (player->can_support_codec) {
5545 // There is one codec to play
5546 post_msg_direct = TRUE;
5548 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5549 post_msg_direct = TRUE;
5552 if (post_msg_direct) {
5553 MMMessageParamType msg_param;
5554 memset(&msg_param, 0, sizeof(MMMessageParamType));
5556 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5557 LOGW("not found AUDIO codec, posting error code to application.");
5559 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5560 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5561 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5562 LOGW("not found VIDEO codec, posting error code to application.");
5564 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5565 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5568 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5570 MMPLAYER_FREEIF(msg_param.data);
5572 return MM_ERROR_NONE;
5574 // no any supported codec case
5575 LOGW("not found any codec, posting error code to application.");
5577 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5578 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5579 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5581 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5582 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5585 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5587 MMPLAYER_FREEIF(msg_param.data);
5593 return MM_ERROR_NONE;
5596 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5598 GstState element_state = GST_STATE_VOID_PENDING;
5599 GstState element_pending_state = GST_STATE_VOID_PENDING;
5600 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5601 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5603 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5605 MMPLAYER_RECONFIGURE_LOCK(player);
5606 if (!player->gapless.reconfigure) {
5607 MMPLAYER_RECONFIGURE_UNLOCK(player);
5611 LOGI("reconfigure is under process");
5612 MMPLAYER_RECONFIGURE_WAIT(player);
5613 MMPLAYER_RECONFIGURE_UNLOCK(player);
5614 LOGI("reconfigure is completed.");
5616 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5617 &element_state, &element_pending_state, timeout * GST_SECOND);
5618 if (result == GST_STATE_CHANGE_FAILURE)
5619 LOGW("failed to get pipeline state in %d sec", timeout);
5624 /* NOTE : it should be able to call 'stop' anytime*/
5626 _mmplayer_stop(MMHandleType hplayer)
5628 mmplayer_t *player = (mmplayer_t *)hplayer;
5629 int ret = MM_ERROR_NONE;
5633 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5635 /* check current state */
5636 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5638 /* need to wait till the rebuilding pipeline is completed */
5639 __mmplayer_check_pipeline_reconfigure_state(player);
5640 MMPLAYER_RECONFIGURE_LOCK(player);
5641 __mmplayer_reset_gapless_state(player);
5642 MMPLAYER_RECONFIGURE_UNLOCK(player);
5644 /* NOTE : application should not wait for EOS after calling STOP */
5645 _mmplayer_cancel_eos_timer(player);
5648 player->seek_state = MMPLAYER_SEEK_NONE;
5651 ret = _mmplayer_gst_stop(player);
5653 if (ret != MM_ERROR_NONE)
5654 LOGE("failed to stop player.");
5662 _mmplayer_pause(MMHandleType hplayer)
5664 mmplayer_t *player = (mmplayer_t *)hplayer;
5665 gint64 pos_nsec = 0;
5666 gboolean async = FALSE;
5667 gint ret = MM_ERROR_NONE;
5671 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5673 /* check current state */
5674 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5676 /* check pipeline reconfigure state */
5677 __mmplayer_check_pipeline_reconfigure_state(player);
5679 switch (MMPLAYER_CURRENT_STATE(player)) {
5680 case MM_PLAYER_STATE_READY:
5682 /* check prepare async or not.
5683 * In the case of streaming playback, it's recommended to avoid blocking wait.
5685 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5686 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5688 /* Changing back sync of rtspsrc to async */
5689 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5690 LOGD("async prepare working mode for rtsp");
5696 case MM_PLAYER_STATE_PLAYING:
5698 /* NOTE : store current point to overcome some bad operation
5699 *(returning zero when getting current position in paused state) of some
5702 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5703 LOGW("getting current position failed in paused");
5705 player->last_position = pos_nsec;
5707 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5708 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5709 This causes problem is position calculation during normal pause resume scenarios also.
5710 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5711 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5712 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5713 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5719 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5720 LOGD("doing async pause in case of ms buff src");
5724 /* pause pipeline */
5725 ret = _mmplayer_gst_pause(player, async);
5726 if (ret != MM_ERROR_NONE) {
5727 LOGE("failed to pause player. ret : 0x%x", ret);
5728 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5732 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5733 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5734 LOGE("failed to update display_rotation");
5738 return MM_ERROR_NONE;
5741 /* in case of streaming, pause could take long time.*/
5743 _mmplayer_abort_pause(MMHandleType hplayer)
5745 mmplayer_t *player = (mmplayer_t *)hplayer;
5746 int ret = MM_ERROR_NONE;
5750 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5752 player->pipeline->mainbin,
5753 MM_ERROR_PLAYER_NOT_INITIALIZED);
5755 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5756 LOGD("set the videobin state to READY");
5757 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5758 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5762 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5763 LOGD("set the audiobin state to READY");
5764 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5765 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5769 LOGD("set the pipeline state to READY");
5770 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5771 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5773 if (ret != MM_ERROR_NONE) {
5774 LOGE("fail to change state to READY");
5775 return MM_ERROR_PLAYER_INTERNAL;
5778 LOGD("succeeded in changing state to READY");
5783 _mmplayer_resume(MMHandleType hplayer)
5785 mmplayer_t *player = (mmplayer_t *)hplayer;
5786 int ret = MM_ERROR_NONE;
5787 gboolean async = FALSE;
5791 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5793 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5794 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5795 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5799 /* Changing back sync mode rtspsrc to async */
5800 LOGD("async resume for rtsp case");
5804 /* check current state */
5805 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5807 ret = _mmplayer_gst_resume(player, async);
5808 if (ret != MM_ERROR_NONE)
5809 LOGE("failed to resume player.");
5811 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5812 LOGD("force resume even during buffering");
5813 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5822 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5824 mmplayer_t *player = (mmplayer_t *)hplayer;
5825 gint64 pos_nsec = 0;
5826 int ret = MM_ERROR_NONE;
5828 signed long long start = 0, stop = 0;
5829 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5832 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5833 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5835 /* The sound of video is not supported under 0.0 and over 2.0. */
5836 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5837 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5840 _mmplayer_set_mute(hplayer, mute);
5842 if (player->playback_rate == rate)
5843 return MM_ERROR_NONE;
5845 /* If the position is reached at start potion during fast backward, EOS is posted.
5846 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5848 player->playback_rate = rate;
5850 current_state = MMPLAYER_CURRENT_STATE(player);
5852 if (current_state != MM_PLAYER_STATE_PAUSED)
5853 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5855 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5857 if ((current_state == MM_PLAYER_STATE_PAUSED)
5858 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5859 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5860 pos_nsec = player->last_position;
5865 stop = GST_CLOCK_TIME_NONE;
5867 start = GST_CLOCK_TIME_NONE;
5871 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5872 player->playback_rate,
5874 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5875 GST_SEEK_TYPE_SET, start,
5876 GST_SEEK_TYPE_SET, stop)) {
5877 LOGE("failed to set speed playback");
5878 return MM_ERROR_PLAYER_SEEK;
5881 LOGD("succeeded to set speed playback as %0.1f", rate);
5885 return MM_ERROR_NONE;;
5889 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5891 mmplayer_t *player = (mmplayer_t *)hplayer;
5892 int ret = MM_ERROR_NONE;
5896 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5898 /* check pipeline reconfigure state */
5899 __mmplayer_check_pipeline_reconfigure_state(player);
5901 ret = _mmplayer_gst_set_position(player, position, FALSE);
5909 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5911 mmplayer_t *player = (mmplayer_t *)hplayer;
5912 int ret = MM_ERROR_NONE;
5914 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5915 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5917 if (g_strrstr(player->type, "video/mpegts"))
5918 __mmplayer_update_duration_value(player);
5920 *duration = player->duration;
5925 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5927 mmplayer_t *player = (mmplayer_t *)hplayer;
5928 int ret = MM_ERROR_NONE;
5930 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5932 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5938 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5940 mmplayer_t *player = (mmplayer_t *)hplayer;
5941 int ret = MM_ERROR_NONE;
5945 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5947 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5955 __mmplayer_is_midi_type(gchar *str_caps)
5957 if ((g_strrstr(str_caps, "audio/midi")) ||
5958 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5959 (g_strrstr(str_caps, "application/x-smaf")) ||
5960 (g_strrstr(str_caps, "audio/x-imelody")) ||
5961 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5962 (g_strrstr(str_caps, "audio/xmf")) ||
5963 (g_strrstr(str_caps, "audio/mxmf"))) {
5972 __mmplayer_is_only_mp3_type(gchar *str_caps)
5974 if (g_strrstr(str_caps, "application/x-id3") ||
5975 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5981 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5983 GstStructure *caps_structure = NULL;
5984 gint samplerate = 0;
5988 MMPLAYER_RETURN_IF_FAIL(player && caps);
5990 caps_structure = gst_caps_get_structure(caps, 0);
5992 /* set stream information */
5993 gst_structure_get_int(caps_structure, "rate", &samplerate);
5994 gst_structure_get_int(caps_structure, "channels", &channels);
5996 mm_player_set_attribute((MMHandleType)player, NULL,
5997 "content_audio_samplerate", samplerate,
5998 "content_audio_channels", channels, NULL);
6000 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6004 __mmplayer_update_content_type_info(mmplayer_t *player)
6007 MMPLAYER_RETURN_IF_FAIL(player && player->type);
6009 if (__mmplayer_is_midi_type(player->type)) {
6010 player->bypass_audio_effect = TRUE;
6014 if (!player->streamer) {
6015 LOGD("no need to check streaming type");
6019 if (g_strrstr(player->type, "application/x-hls")) {
6020 /* If it can't know exact type when it parses uri because of redirection case,
6021 * it will be fixed by typefinder or when doing autoplugging.
6023 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6024 player->streamer->is_adaptive_streaming = TRUE;
6025 } else if (g_strrstr(player->type, "application/dash+xml")) {
6026 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6027 player->streamer->is_adaptive_streaming = TRUE;
6030 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6031 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
6032 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6034 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6035 if (player->streamer->is_adaptive_streaming)
6036 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6038 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6042 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6047 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6048 GstCaps *caps, gpointer data)
6050 mmplayer_t *player = (mmplayer_t *)data;
6054 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6056 /* store type string */
6057 if (player->type_caps) {
6058 gst_caps_unref(player->type_caps);
6059 player->type_caps = NULL;
6062 player->type_caps = gst_caps_copy(caps);
6063 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
6065 MMPLAYER_FREEIF(player->type);
6066 player->type = gst_caps_to_string(caps);
6068 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6069 player, player->type, probability, gst_caps_get_size(caps));
6071 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6072 (g_strrstr(player->type, "audio/x-raw-int"))) {
6073 LOGE("not support media format");
6075 if (player->msg_posted == FALSE) {
6076 MMMessageParamType msg_param;
6077 memset(&msg_param, 0, sizeof(MMMessageParamType));
6079 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6080 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6082 /* don't post more if one was sent already */
6083 player->msg_posted = TRUE;
6088 __mmplayer_update_content_type_info(player);
6090 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6093 pad = gst_element_get_static_pad(tf, "src");
6095 LOGE("fail to get typefind src pad.");
6099 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6100 gboolean async = FALSE;
6101 LOGE("failed to autoplug %s", player->type);
6103 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6105 if (async && player->msg_posted == FALSE)
6106 __mmplayer_handle_missed_plugin(player);
6108 gst_object_unref(GST_OBJECT(pad));
6115 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6117 GstElement *decodebin = NULL;
6121 /* create decodebin */
6122 decodebin = gst_element_factory_make("decodebin", NULL);
6125 LOGE("fail to create decodebin");
6129 /* raw pad handling signal */
6130 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6131 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6133 /* no-more-pad pad handling signal */
6134 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6135 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6137 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6138 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6140 /* This signal is emitted when a pad for which there is no further possible
6141 decoding is added to the decodebin.*/
6142 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6143 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6145 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6146 before looking for any elements that can handle that stream.*/
6147 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6148 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6150 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6151 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6152 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6154 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6155 before looking for any elements that can handle that stream.*/
6156 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6157 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6159 /* This signal is emitted once decodebin has finished decoding all the data.*/
6160 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6161 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6163 /* This signal is emitted when a element is added to the bin.*/
6164 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6165 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6172 __mmplayer_gst_make_queue2(mmplayer_t *player)
6174 GstElement *queue2 = NULL;
6175 gint64 dur_bytes = 0L;
6176 mmplayer_gst_element_t *mainbin = NULL;
6177 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6180 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6182 mainbin = player->pipeline->mainbin;
6184 queue2 = gst_element_factory_make("queue2", "queue2");
6186 LOGE("failed to create buffering queue element");
6190 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6191 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6193 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6195 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6196 * skip the pull mode(file or ring buffering) setting. */
6197 if (dur_bytes > 0) {
6198 if (!g_strrstr(player->type, "video/mpegts")) {
6199 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6200 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6206 _mm_player_streaming_set_queue2(player->streamer,
6210 (guint64)dur_bytes); /* no meaning at the moment */
6216 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6218 mmplayer_gst_element_t *mainbin = NULL;
6219 GstElement *decodebin = NULL;
6220 GstElement *queue2 = NULL;
6221 GstPad *sinkpad = NULL;
6222 GstPad *qsrcpad = NULL;
6225 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6227 mainbin = player->pipeline->mainbin;
6229 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6231 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6232 LOGW("need to check: muxed buffer is not null");
6235 queue2 = __mmplayer_gst_make_queue2(player);
6237 LOGE("failed to make queue2");
6241 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6242 LOGE("failed to add buffering queue");
6246 sinkpad = gst_element_get_static_pad(queue2, "sink");
6247 qsrcpad = gst_element_get_static_pad(queue2, "src");
6249 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6250 LOGE("failed to link [%s:%s]-[%s:%s]",
6251 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6255 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6256 LOGE("failed to sync queue2 state with parent");
6260 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6261 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6265 gst_object_unref(GST_OBJECT(sinkpad));
6269 /* create decodebin */
6270 decodebin = _mmplayer_gst_make_decodebin(player);
6272 LOGE("failed to make decodebin");
6276 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6277 LOGE("failed to add decodebin");
6281 /* to force caps on the decodebin element and avoid reparsing stuff by
6282 * typefind. It also avoids a deadlock in the way typefind activates pads in
6283 * the state change */
6284 g_object_set(decodebin, "sink-caps", caps, NULL);
6286 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6288 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6289 LOGE("failed to link [%s:%s]-[%s:%s]",
6290 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6294 gst_object_unref(GST_OBJECT(sinkpad));
6296 gst_object_unref(GST_OBJECT(qsrcpad));
6299 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6300 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6302 /* set decodebin property about buffer in streaming playback. *
6303 * in case of HLS/DASH, it does not need to have big buffer *
6304 * because it is kind of adaptive streaming. */
6305 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6306 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6307 gint high_percent = 0;
6309 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6310 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6312 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6314 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6316 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6317 "high-percent", high_percent,
6318 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6319 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6320 "max-size-buffers", 0, NULL); // disable or automatic
6323 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6324 LOGE("failed to sync decodebin state with parent");
6335 gst_object_unref(GST_OBJECT(sinkpad));
6338 gst_object_unref(GST_OBJECT(qsrcpad));
6341 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6342 * You need to explicitly set elements to the NULL state before
6343 * dropping the final reference, to allow them to clean up.
6345 gst_element_set_state(queue2, GST_STATE_NULL);
6347 /* And, it still has a parent "player".
6348 * You need to let the parent manage the object instead of unreffing the object directly.
6350 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6351 LOGE("failed to remove queue2");
6352 gst_object_unref(queue2);
6358 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6359 * You need to explicitly set elements to the NULL state before
6360 * dropping the final reference, to allow them to clean up.
6362 gst_element_set_state(decodebin, GST_STATE_NULL);
6364 /* And, it still has a parent "player".
6365 * You need to let the parent manage the object instead of unreffing the object directly.
6368 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6369 LOGE("failed to remove decodebin");
6370 gst_object_unref(decodebin);
6379 _mmplayer_update_not_supported_codec_info(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6383 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6384 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6386 LOGD("class : %s, mime : %s", factory_class, mime);
6388 /* add missing plugin */
6389 /* NOTE : msl should check missing plugin for image mime type.
6390 * Some motion jpeg clips can have playable audio track.
6391 * So, msl have to play audio after displaying popup written video format not supported.
6393 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6394 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6395 LOGD("not found demuxer");
6396 player->not_found_demuxer = TRUE;
6397 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6403 if (!g_strrstr(factory_class, "Demuxer")) {
6404 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6405 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6406 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6408 /* check that clip have multi tracks or not */
6409 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6410 LOGD("video plugin is already linked");
6412 LOGW("add VIDEO to missing plugin");
6413 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6414 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6416 } else if (g_str_has_prefix(mime, "audio")) {
6417 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6418 LOGD("audio plugin is already linked");
6420 LOGW("add AUDIO to missing plugin");
6421 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6422 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6430 return MM_ERROR_NONE;
6434 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6436 mmplayer_t *player = (mmplayer_t *)data;
6440 MMPLAYER_RETURN_IF_FAIL(player);
6442 /* remove fakesink. */
6443 if (!_mmplayer_gst_remove_fakesink(player,
6444 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6445 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6446 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6447 * source element are not same. To overcome this situation, this function will called
6448 * several places and several times. Therefore, this is not an error case.
6453 LOGD("[handle: %p] pipeline has completely constructed", player);
6455 if ((player->msg_posted == FALSE) &&
6456 (player->cmd >= MMPLAYER_COMMAND_START))
6457 __mmplayer_handle_missed_plugin(player);
6459 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6463 __mmplayer_check_profile(void)
6466 static int profile_tv = -1;
6468 if (__builtin_expect(profile_tv != -1, 1))
6471 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6472 switch (*profileName) {
6487 __mmplayer_get_next_uri(mmplayer_t *player)
6489 mmplayer_parse_profile_t profile;
6491 guint num_of_list = 0;
6494 num_of_list = g_list_length(player->uri_info.uri_list);
6495 uri_idx = player->uri_info.uri_idx;
6497 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6498 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6499 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6501 LOGW("next uri does not exist");
6505 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6506 LOGE("failed to parse profile");
6510 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6511 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6512 LOGW("uri type is not supported(%d)", profile.uri_type);
6516 LOGD("success to find next uri %d", uri_idx);
6520 if (!uri || uri_idx == num_of_list) {
6521 LOGE("failed to find next uri");
6525 player->uri_info.uri_idx = uri_idx;
6526 if (mm_player_set_attribute((MMHandleType)player, NULL,
6527 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6528 LOGE("failed to set attribute");
6532 SECURE_LOGD("next playback uri: %s", uri);
6537 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6539 #define REPEAT_COUNT_INFINITE -1
6540 #define REPEAT_COUNT_MIN 2
6541 #define ORIGINAL_URI_ONLY 1
6543 MMHandleType attrs = 0;
6547 guint num_of_uri = 0;
6548 int profile_tv = -1;
6552 LOGD("checking for gapless play option");
6554 if (player->build_audio_offload) {
6555 LOGE("offload path is not supportable.");
6559 if (player->pipeline->textbin) {
6560 LOGE("subtitle path is enabled. gapless play is not supported.");
6564 attrs = MMPLAYER_GET_ATTRS(player);
6566 LOGE("fail to get attributes.");
6570 mm_attrs_multiple_get(player->attrs, NULL,
6571 "content_video_found", &video,
6572 "profile_play_count", &count,
6573 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6575 /* gapless playback is not supported in case of video at TV profile. */
6576 profile_tv = __mmplayer_check_profile();
6577 if (profile_tv && video) {
6578 LOGW("not support video gapless playback");
6582 /* check repeat count in case of audio */
6584 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6585 LOGW("gapless is disabled");
6589 num_of_uri = g_list_length(player->uri_info.uri_list);
6591 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6593 if (num_of_uri == ORIGINAL_URI_ONLY) {
6594 /* audio looping path */
6595 if (count >= REPEAT_COUNT_MIN) {
6596 /* decrease play count */
6597 /* we succeeded to rewind. update play count and then wait for next EOS */
6599 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6600 } else if (count != REPEAT_COUNT_INFINITE) {
6601 LOGD("there is no next uri and no repeat");
6604 LOGD("looping cnt %d", count);
6606 /* gapless playback path */
6607 if (!__mmplayer_get_next_uri(player)) {
6608 LOGE("failed to get next uri");
6615 LOGE("unable to play gapless path. EOS will be posted soon");
6620 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6622 GstPad *sinkpad = g_value_get_object (item);
6623 GstElement *element = GST_ELEMENT(user_data);
6624 if (!sinkpad || !element) {
6625 LOGE("invalid parameter");
6629 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6630 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6634 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6636 mmplayer_gst_element_t *sinkbin = NULL;
6637 main_element_id_e concatId = MMPLAYER_M_NUM;
6638 main_element_id_e sinkId = MMPLAYER_M_NUM;
6639 gboolean send_notice = FALSE;
6640 GstElement *element;
6644 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6646 LOGD("type %d", type);
6649 case MM_PLAYER_TRACK_TYPE_AUDIO:
6650 concatId = MMPLAYER_M_A_CONCAT;
6651 sinkId = MMPLAYER_A_BIN;
6652 sinkbin = player->pipeline->audiobin;
6654 case MM_PLAYER_TRACK_TYPE_VIDEO:
6655 concatId = MMPLAYER_M_V_CONCAT;
6656 sinkId = MMPLAYER_V_BIN;
6657 sinkbin = player->pipeline->videobin;
6660 case MM_PLAYER_TRACK_TYPE_TEXT:
6661 concatId = MMPLAYER_M_T_CONCAT;
6662 sinkId = MMPLAYER_T_BIN;
6663 sinkbin = player->pipeline->textbin;
6666 LOGE("requested type is not supportable");
6671 element = player->pipeline->mainbin[concatId].gst;
6675 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6676 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6677 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6678 if (srcpad && sinkpad) {
6679 /* after getting drained signal there is no data flows, so no need to do pad_block */
6680 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6681 gst_pad_unlink(srcpad, sinkpad);
6683 /* send custom event to sink pad to handle it at video sink */
6685 LOGD("send custom event to sinkpad");
6686 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6687 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6688 gst_pad_send_event(sinkpad, event);
6691 gst_object_unref(srcpad);
6692 gst_object_unref(sinkpad);
6695 LOGD("release concat request pad");
6696 /* release and unref requests pad from the selector */
6697 iter = gst_element_iterate_sink_pads(element);
6698 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6699 gst_iterator_resync(iter);
6700 gst_iterator_free(iter);
6706 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6708 mmplayer_track_t *selector = &player->track[type];
6709 mmplayer_gst_element_t *sinkbin = NULL;
6710 main_element_id_e selectorId = MMPLAYER_M_NUM;
6711 main_element_id_e sinkId = MMPLAYER_M_NUM;
6712 GstPad *srcpad = NULL;
6713 GstPad *sinkpad = NULL;
6714 gboolean send_notice = FALSE;
6717 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6719 LOGD("type %d", type);
6722 case MM_PLAYER_TRACK_TYPE_AUDIO:
6723 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6724 sinkId = MMPLAYER_A_BIN;
6725 sinkbin = player->pipeline->audiobin;
6727 case MM_PLAYER_TRACK_TYPE_VIDEO:
6728 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6729 sinkId = MMPLAYER_V_BIN;
6730 sinkbin = player->pipeline->videobin;
6733 case MM_PLAYER_TRACK_TYPE_TEXT:
6734 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6735 sinkId = MMPLAYER_T_BIN;
6736 sinkbin = player->pipeline->textbin;
6739 LOGE("requested type is not supportable");
6744 if (player->pipeline->mainbin[selectorId].gst) {
6747 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6749 if (selector->event_probe_id != 0)
6750 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6751 selector->event_probe_id = 0;
6753 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6754 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6756 if (srcpad && sinkpad) {
6757 /* after getting drained signal there is no data flows, so no need to do pad_block */
6758 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6759 gst_pad_unlink(srcpad, sinkpad);
6761 /* send custom event to sink pad to handle it at video sink */
6763 LOGD("send custom event to sinkpad");
6764 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6765 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6766 gst_pad_send_event(sinkpad, event);
6770 gst_object_unref(sinkpad);
6773 gst_object_unref(srcpad);
6776 LOGD("selector release");
6778 /* release and unref requests pad from the selector */
6779 for (n = 0; n < selector->streams->len; n++) {
6780 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6781 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6784 g_ptr_array_set_size(selector->streams, 0);
6786 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6787 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6788 player->pipeline->mainbin[selectorId].gst)) {
6789 LOGE("failed to remove selector");
6790 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6793 player->pipeline->mainbin[selectorId].gst = NULL;
6801 __mmplayer_deactivate_old_path(mmplayer_t *player)
6804 MMPLAYER_RETURN_IF_FAIL(player);
6806 if (MMPLAYER_USE_DECODEBIN(player)) {
6807 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6808 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6809 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6810 LOGE("deactivate selector error");
6814 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6815 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6816 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6817 LOGE("deactivate concat error");
6822 _mmplayer_track_destroy(player);
6823 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6825 if (player->streamer) {
6826 _mm_player_streaming_initialize(player->streamer, FALSE);
6827 _mm_player_streaming_destroy(player->streamer);
6828 player->streamer = NULL;
6831 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6837 if (!player->msg_posted) {
6838 MMMessageParamType msg = {0,};
6841 msg.code = MM_ERROR_PLAYER_INTERNAL;
6842 LOGE("gapless_uri_play> deactivate error");
6844 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6845 player->msg_posted = TRUE;
6851 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6853 int result = MM_ERROR_NONE;
6854 mmplayer_t *player = (mmplayer_t *)hplayer;
6857 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6858 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6860 if (mm_player_set_attribute(hplayer, NULL,
6861 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6862 LOGE("failed to set attribute");
6863 result = MM_ERROR_PLAYER_INTERNAL;
6865 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6866 LOGE("failed to add the original uri in the uri list.");
6874 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6876 mmplayer_t *player = (mmplayer_t *)hplayer;
6877 guint num_of_list = 0;
6881 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6882 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6884 if (player->pipeline && player->pipeline->textbin) {
6885 LOGE("subtitle path is enabled.");
6886 return MM_ERROR_PLAYER_INVALID_STATE;
6889 num_of_list = g_list_length(player->uri_info.uri_list);
6891 if (is_first_path) {
6892 if (num_of_list == 0) {
6893 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6894 SECURE_LOGD("add original path : %s", uri);
6896 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6897 player->uri_info.uri_list = g_list_prepend(
6898 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6899 SECURE_LOGD("change original path : %s", uri);
6902 MMHandleType attrs = 0;
6903 attrs = MMPLAYER_GET_ATTRS(player);
6905 if (num_of_list == 0) {
6906 char *original_uri = NULL;
6909 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6911 if (!original_uri) {
6912 LOGE("there is no original uri.");
6913 return MM_ERROR_PLAYER_INVALID_STATE;
6916 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6917 player->uri_info.uri_idx = 0;
6919 SECURE_LOGD("add original path at first : %s", original_uri);
6923 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6924 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6928 return MM_ERROR_NONE;
6932 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6934 mmplayer_t *player = (mmplayer_t *)hplayer;
6935 char *next_uri = NULL;
6936 guint num_of_list = 0;
6939 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6941 num_of_list = g_list_length(player->uri_info.uri_list);
6943 if (num_of_list > 0) {
6944 gint uri_idx = player->uri_info.uri_idx;
6946 if (uri_idx < num_of_list - 1)
6951 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6952 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6954 *uri = g_strdup(next_uri);
6958 return MM_ERROR_NONE;
6962 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6963 GstCaps *caps, gpointer data)
6965 mmplayer_t *player = (mmplayer_t *)data;
6966 const gchar *klass = NULL;
6967 const gchar *mime = NULL;
6968 gchar *caps_str = NULL;
6970 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6971 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6972 caps_str = gst_caps_to_string(caps);
6974 LOGW("unknown type of caps : %s from %s",
6975 caps_str, GST_ELEMENT_NAME(elem));
6977 MMPLAYER_FREEIF(caps_str);
6979 /* There is no available codec. */
6980 _mmplayer_update_not_supported_codec_info(player, klass, mime);
6984 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6985 GstCaps *caps, gpointer data)
6987 mmplayer_t *player = (mmplayer_t *)data;
6988 const char *mime = NULL;
6989 gboolean ret = TRUE;
6991 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6992 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6994 if (g_str_has_prefix(mime, "audio")) {
6995 GstStructure *caps_structure = NULL;
6996 gint samplerate = 0;
6998 gchar *caps_str = NULL;
7000 caps_structure = gst_caps_get_structure(caps, 0);
7001 gst_structure_get_int(caps_structure, "rate", &samplerate);
7002 gst_structure_get_int(caps_structure, "channels", &channels);
7004 if ((channels > 0 && samplerate == 0)) {
7005 LOGD("exclude audio...");
7009 caps_str = gst_caps_to_string(caps);
7010 /* set it directly because not sent by TAG */
7011 if (g_strrstr(caps_str, "mobile-xmf"))
7012 mm_player_set_attribute((MMHandleType)player, NULL,
7013 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7015 MMPLAYER_FREEIF(caps_str);
7016 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7017 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7018 LOGD("video is already linked, allow the stream switch");
7021 LOGD("video is already linked");
7025 LOGD("found new stream");
7032 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7034 gboolean ret = FALSE;
7035 GDBusConnection *conn = NULL;
7037 GVariant *result = NULL;
7038 const gchar *dbus_device_type = NULL;
7039 const gchar *dbus_ret = NULL;
7042 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7044 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7049 result = g_dbus_connection_call_sync(conn,
7050 "org.pulseaudio.Server",
7051 "/org/pulseaudio/StreamManager",
7052 "org.pulseaudio.StreamManager",
7053 "GetCurrentMediaRoutingPath",
7054 g_variant_new("(s)", "out"),
7055 G_VARIANT_TYPE("(ss)"),
7056 G_DBUS_CALL_FLAGS_NONE,
7060 if (!result || err) {
7061 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7066 /* device type is listed in stream-map.json at mmfw-sysconf */
7067 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7069 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7070 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7073 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7074 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7075 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7076 LOGD("audio offload is supportable");
7082 LOGD("audio offload is not supportable");
7085 g_variant_unref(result);
7087 g_object_unref(conn);
7092 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7094 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7095 gint64 position = 0;
7097 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7098 player->pipeline && player->pipeline->mainbin);
7100 MMPLAYER_CMD_LOCK(player);
7101 current_state = MMPLAYER_CURRENT_STATE(player);
7103 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7104 LOGW("getting current position failed in paused");
7106 _mmplayer_unrealize((MMHandleType)player);
7107 _mmplayer_realize((MMHandleType)player);
7109 _mmplayer_set_position((MMHandleType)player, position);
7111 /* async not to be blocked in streaming case */
7112 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7114 _mmplayer_pause((MMHandleType)player);
7116 if (current_state == MM_PLAYER_STATE_PLAYING)
7117 _mmplayer_start((MMHandleType)player);
7118 MMPLAYER_CMD_UNLOCK(player);
7120 LOGD("rebuilding audio pipeline is completed.");
7123 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7125 mmplayer_t *player = (mmplayer_t *)user_data;
7126 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7127 gboolean is_supportable = FALSE;
7129 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7130 LOGW("failed to get device type");
7132 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7134 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7135 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7136 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7137 LOGD("ignore this dev connected info");
7141 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7142 if (player->build_audio_offload == is_supportable) {
7143 LOGD("keep current pipeline without re-building");
7147 /* rebuild pipeline */
7148 LOGD("re-build pipeline - offload: %d", is_supportable);
7149 player->build_audio_offload = FALSE;
7150 __mmplayer_rebuild_audio_pipeline(player);
7156 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7158 unsigned int id = 0;
7160 if (player->audio_device_cb_id != 0) {
7161 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7165 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7166 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7167 LOGD("added device connected cb (%u)", id);
7168 player->audio_device_cb_id = id;
7170 LOGW("failed to add device connected cb");
7177 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7179 mmplayer_t *player = (mmplayer_t *)hplayer;
7182 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7183 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7185 *activated = player->build_audio_offload;
7187 LOGD("offload activated : %d", (int)*activated);
7190 return MM_ERROR_NONE;
7194 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7197 this function need to be updated according to the supported media format
7198 @see player->ini.audio_offload_media_format */
7200 if (__mmplayer_is_only_mp3_type(player->type)) {
7201 LOGD("offload supportable media format type");
7209 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7211 gboolean ret = FALSE;
7212 GstElementFactory *factory = NULL;
7215 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7217 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7218 if (!__mmplayer_is_offload_supported_type(player))
7221 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7222 LOGD("there is no audio offload sink");
7226 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7227 LOGW("there is no audio device type to support offload");
7231 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7233 LOGW("there is no installed audio offload sink element");
7236 gst_object_unref(factory);
7238 if (_mmplayer_acquire_hw_resource(player,
7239 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7240 LOGE("failed to acquire audio offload decoder resource");
7244 if (!__mmplayer_add_audio_device_connected_cb(player))
7247 if (!__mmplayer_is_audio_offload_device_type(player))
7250 LOGD("audio offload can be built");
7255 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7261 static GstAutoplugSelectResult
7262 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7264 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7265 int audio_offload = 0;
7267 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7268 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7270 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7271 LOGD("expose audio path to build offload output path");
7272 player->build_audio_offload = TRUE;
7273 /* update codec info */
7274 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7275 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7276 player->audiodec_linked = 1;
7278 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7282 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7283 And need to consider the multi-track audio content.
7284 There is no HW audio decoder in public. */
7286 /* set stream information */
7287 if (!player->audiodec_linked)
7288 _mmplayer_set_audio_attrs(player, caps);
7290 /* update codec info */
7291 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7292 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7293 player->audiodec_linked = 1;
7295 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7297 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7298 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7300 /* mark video decoder for acquire */
7301 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7302 LOGW("video decoder resource is already acquired, skip it.");
7303 ret = GST_AUTOPLUG_SELECT_SKIP;
7307 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7308 LOGE("failed to acquire video decoder resource");
7309 ret = GST_AUTOPLUG_SELECT_SKIP;
7312 player->interrupted_by_resource = FALSE;
7315 /* update codec info */
7316 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7317 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7318 player->videodec_linked = 1;
7326 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7327 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7329 #define DEFAULT_IDX 0xFFFF
7330 #define MIN_FACTORY_NUM 2
7331 mmplayer_t *player = (mmplayer_t *)data;
7332 GValueArray *new_factories = NULL;
7333 GValue val = { 0, };
7334 GstElementFactory *factory = NULL;
7335 const gchar *klass = NULL;
7336 gchar *factory_name = NULL;
7337 guint hw_dec_idx = DEFAULT_IDX;
7338 guint first_sw_dec_idx = DEFAULT_IDX;
7339 guint last_sw_dec_idx = DEFAULT_IDX;
7340 guint new_pos = DEFAULT_IDX;
7341 guint rm_pos = DEFAULT_IDX;
7342 int audio_codec_type;
7343 int video_codec_type;
7344 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7346 if (factories->n_values < MIN_FACTORY_NUM)
7349 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7350 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7353 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7355 for (int i = 0 ; i < factories->n_values ; i++) {
7356 gchar *hw_dec_info = NULL;
7357 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7359 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7361 LOGW("failed to get factory object");
7364 klass = gst_element_factory_get_klass(factory);
7365 factory_name = GST_OBJECT_NAME(factory);
7368 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7370 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7371 if (!player->need_audio_dec_sorting) {
7372 LOGD("sorting is not required");
7375 codec_type = audio_codec_type;
7376 hw_dec_info = player->ini.audiocodec_element_hw;
7377 sw_dec_info = player->ini.audiocodec_element_sw;
7378 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7379 if (!player->need_video_dec_sorting) {
7380 LOGD("sorting is not required");
7383 codec_type = video_codec_type;
7384 hw_dec_info = player->ini.videocodec_element_hw;
7385 sw_dec_info = player->ini.videocodec_element_sw;
7390 if (g_strrstr(factory_name, hw_dec_info)) {
7393 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7394 if (strstr(factory_name, sw_dec_info[j])) {
7395 last_sw_dec_idx = i;
7396 if (first_sw_dec_idx == DEFAULT_IDX) {
7397 first_sw_dec_idx = i;
7402 if (first_sw_dec_idx == DEFAULT_IDX)
7403 LOGW("unknown codec %s", factory_name);
7407 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7410 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7411 if (hw_dec_idx < first_sw_dec_idx)
7413 new_pos = first_sw_dec_idx;
7414 rm_pos = hw_dec_idx + 1;
7415 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7416 if (last_sw_dec_idx < hw_dec_idx)
7418 new_pos = last_sw_dec_idx + 1;
7419 rm_pos = hw_dec_idx;
7424 /* change position - insert H/W decoder according to the new position */
7425 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7427 LOGW("failed to get factory object");
7430 new_factories = g_value_array_copy(factories);
7431 g_value_init (&val, G_TYPE_OBJECT);
7432 g_value_set_object (&val, factory);
7433 g_value_array_insert(new_factories, new_pos, &val);
7434 g_value_unset (&val);
7435 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7437 for (int i = 0 ; i < new_factories->n_values ; i++) {
7438 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7440 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7441 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7443 LOGE("[Re-arranged] failed to get factory object");
7446 return new_factories;
7450 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7451 GstCaps *caps, GstElementFactory *factory, gpointer data)
7453 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7454 mmplayer_t *player = (mmplayer_t *)data;
7456 gchar *factory_name = NULL;
7457 gchar *caps_str = NULL;
7458 const gchar *klass = NULL;
7461 factory_name = GST_OBJECT_NAME(factory);
7462 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7463 caps_str = gst_caps_to_string(caps);
7465 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7467 /* store type string */
7468 if (player->type == NULL) {
7469 player->type = gst_caps_to_string(caps);
7470 __mmplayer_update_content_type_info(player);
7473 /* filtering exclude keyword */
7474 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7475 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7476 LOGW("skipping [%s] by exclude keyword [%s]",
7477 factory_name, player->ini.exclude_element_keyword[idx]);
7479 result = GST_AUTOPLUG_SELECT_SKIP;
7484 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7485 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7486 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7487 factory_name, player->ini.unsupported_codec_keyword[idx]);
7488 result = GST_AUTOPLUG_SELECT_SKIP;
7493 /* exclude webm format */
7494 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7495 * because webm format is not supportable.
7496 * If webm is disabled in "autoplug-continue", there is no state change
7497 * failure or error because the decodebin will expose the pad directly.
7498 * It make MSL invoke _prepare_async_callback.
7499 * So, we need to disable webm format in "autoplug-select" */
7500 if (caps_str && strstr(caps_str, "webm")) {
7501 LOGW("webm is not supported");
7502 result = GST_AUTOPLUG_SELECT_SKIP;
7506 /* check factory class for filtering */
7507 /* NOTE : msl don't need to use image plugins.
7508 * So, those plugins should be skipped for error handling.
7510 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7511 LOGD("skipping [%s] by not required", factory_name);
7512 result = GST_AUTOPLUG_SELECT_SKIP;
7516 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7517 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7518 // TO CHECK : subtitle if needed, add subparse exception.
7519 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7520 result = GST_AUTOPLUG_SELECT_SKIP;
7524 if (g_strrstr(factory_name, "mpegpsdemux")) {
7525 LOGD("skipping PS container - not support");
7526 result = GST_AUTOPLUG_SELECT_SKIP;
7530 if (g_strrstr(factory_name, "mssdemux"))
7531 player->smooth_streaming = TRUE;
7533 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7534 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7537 GstStructure *str = NULL;
7538 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7540 /* don't make video because of not required */
7541 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7542 (!player->set_mode.video_export)) {
7543 LOGD("no need video decoding, expose pad");
7544 result = GST_AUTOPLUG_SELECT_EXPOSE;
7548 /* get w/h for omx state-tune */
7549 /* FIXME: deprecated? */
7550 str = gst_caps_get_structure(caps, 0);
7551 gst_structure_get_int(str, "width", &width);
7554 if (player->v_stream_caps) {
7555 gst_caps_unref(player->v_stream_caps);
7556 player->v_stream_caps = NULL;
7559 player->v_stream_caps = gst_caps_copy(caps);
7560 LOGD("take caps for video state tune");
7561 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7565 if (g_strrstr(klass, "Codec/Decoder")) {
7566 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7567 if (result != GST_AUTOPLUG_SELECT_TRY) {
7568 LOGW("skip add decoder");
7574 MMPLAYER_FREEIF(caps_str);
7580 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7583 int ret = MM_ERROR_NONE;
7584 mmplayer_t *player = (mmplayer_t *)data;
7585 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7586 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7587 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7590 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7592 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7594 if (MMPLAYER_USE_DECODEBIN(player))
7597 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7600 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7602 __mmplayer_del_sink(player, videobin[MMPLAYER_V_SINK].gst);
7604 LOGD("remove videobin");
7605 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst,
7606 GST_STATE_NULL, FALSE, timeout);
7607 if (ret != MM_ERROR_NONE) {
7608 LOGE("fail to change state of videobin to NULL");
7612 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7613 LOGE("failed to remove videobin");
7614 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7617 LOGD("remove concat");
7618 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst,
7619 GST_STATE_NULL, FALSE, timeout);
7620 if (ret != MM_ERROR_NONE) {
7621 LOGE("fail to change state of concat to NULL");
7625 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7626 LOGE("failed to remove video concat");
7627 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7630 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7631 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7632 MMPLAYER_FREEIF(player->pipeline->videobin);
7634 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7635 if (ret != MM_ERROR_NONE)
7636 LOGE("failed to release overlay resources");
7638 player->videodec_linked = 0;
7640 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7645 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7647 mmplayer_t *player = (mmplayer_t *)data;
7650 MMPLAYER_RETURN_IF_FAIL(player);
7652 LOGD("got about to finish signal");
7654 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7655 LOGW("Fail to get cmd lock");
7659 if (!__mmplayer_verify_gapless_play_path(player)) {
7660 LOGD("decoding is finished.");
7661 MMPLAYER_CMD_UNLOCK(player);
7665 _mmplayer_set_reconfigure_state(player, TRUE);
7666 MMPLAYER_CMD_UNLOCK(player);
7668 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7669 __mmplayer_deactivate_old_path(player);
7675 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7677 mmplayer_t *player = (mmplayer_t *)data;
7678 GstIterator *iter = NULL;
7679 GValue item = { 0, };
7681 gboolean done = FALSE;
7682 gboolean is_all_drained = TRUE;
7685 MMPLAYER_RETURN_IF_FAIL(player);
7687 LOGD("got drained signal");
7689 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7690 LOGW("Fail to get cmd lock");
7694 if (!__mmplayer_verify_gapless_play_path(player)) {
7695 LOGD("decoding is finished.");
7696 MMPLAYER_CMD_UNLOCK(player);
7700 _mmplayer_set_reconfigure_state(player, TRUE);
7701 MMPLAYER_CMD_UNLOCK(player);
7703 /* check decodebin src pads whether they received EOS or not */
7704 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7707 switch (gst_iterator_next(iter, &item)) {
7708 case GST_ITERATOR_OK:
7709 pad = g_value_get_object(&item);
7710 if (pad && !GST_PAD_IS_EOS(pad)) {
7711 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7712 is_all_drained = FALSE;
7715 g_value_reset(&item);
7717 case GST_ITERATOR_RESYNC:
7718 gst_iterator_resync(iter);
7720 case GST_ITERATOR_ERROR:
7721 case GST_ITERATOR_DONE:
7726 g_value_unset(&item);
7727 gst_iterator_free(iter);
7729 if (!is_all_drained) {
7730 LOGD("Wait util the all pads get EOS.");
7735 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7736 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7738 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7739 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7740 __mmplayer_deactivate_old_path(player);
7746 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7748 mmplayer_t *player = (mmplayer_t *)data;
7749 const gchar *klass = NULL;
7750 gchar *factory_name = NULL;
7752 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7753 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7755 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7757 if (__mmplayer_add_dump_buffer_probe(player, element))
7758 LOGD("add buffer probe");
7760 if (g_strrstr(klass, "Decoder")) {
7761 if (g_strrstr(klass, "Audio")) {
7762 player->audio_decoders = g_list_append(player->audio_decoders,
7763 g_strdup(GST_ELEMENT_NAME(element)));
7765 /* update codec info */
7766 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7767 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7768 player->audiodec_linked = 1;
7769 } else if (g_strrstr(klass, "Video")) {
7770 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7771 /* update codec info */
7772 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7773 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7774 player->videodec_linked = 1;
7777 GstPad *srcpad = gst_element_get_static_pad (video_parse, "src");
7779 GstCaps *caps = NULL;
7780 GstStructure *str = NULL;
7781 const gchar *name = NULL;
7782 gboolean caps_ret = TRUE;
7784 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD (srcpad, caps, str, name, caps_ret);
7785 if (caps_ret && str) {
7786 const gchar *stream_format = gst_structure_get_string (str, "stream-format");
7787 if (stream_format && g_strrstr(stream_format, "byte-stream")) {
7788 if ((g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7789 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7790 LOGD("Send SPS and PPS Insertion every IDR frame");
7794 gst_object_unref(GST_OBJECT(srcpad));
7798 } else if (g_strrstr(klass, "Demuxer")) {
7799 if (g_strrstr(klass, "Adaptive")) {
7800 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7801 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7803 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7804 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7806 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7807 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7808 "max-video-width", player->adaptive_info.limit.width,
7809 "max-video-height", player->adaptive_info.limit.height, NULL);
7812 LOGD("plugged element is demuxer. take it");
7814 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7815 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7817 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7818 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7819 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7822 if (g_strrstr(factory_name, "mpegaudioparse")) {
7823 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7824 (__mmplayer_is_only_mp3_type(player->type))) {
7825 LOGD("[mpegaudioparse] set streaming pull mode.");
7826 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7828 } else if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7829 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7830 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7832 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7833 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7835 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7836 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7837 (MMPLAYER_IS_DASH_STREAMING(player))) {
7838 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7839 _mm_player_streaming_set_multiqueue(player->streamer, element);
7840 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7848 __mmplayer_release_misc(mmplayer_t *player)
7851 bool cur_mode = player->set_mode.rich_audio;
7854 MMPLAYER_RETURN_IF_FAIL(player);
7856 player->sent_bos = FALSE;
7857 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7859 player->seek_state = MMPLAYER_SEEK_NONE;
7861 player->total_bitrate = 0;
7862 player->total_maximum_bitrate = 0;
7864 player->not_found_demuxer = 0;
7866 player->last_position = 0;
7867 player->duration = 0;
7868 player->http_content_size = 0;
7869 player->not_supported_codec = MISSING_PLUGIN_NONE;
7870 player->can_support_codec = FOUND_PLUGIN_NONE;
7871 player->pending_seek.is_pending = false;
7872 player->pending_seek.pos = 0;
7873 player->msg_posted = FALSE;
7874 player->has_many_types = FALSE;
7875 player->is_subtitle_force_drop = FALSE;
7876 player->play_subtitle = FALSE;
7877 player->adjust_subtitle_pos = 0;
7878 player->has_closed_caption = FALSE;
7879 player->set_mode.video_export = false;
7880 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7881 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7883 player->set_mode.rich_audio = cur_mode;
7885 if (player->audio_device_cb_id > 0 &&
7886 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7887 LOGW("failed to remove audio device_connected_callback");
7888 player->audio_device_cb_id = 0;
7890 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7891 player->bitrate[i] = 0;
7892 player->maximum_bitrate[i] = 0;
7895 /* free memory related to audio effect */
7896 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7898 if (player->adaptive_info.var_list) {
7899 g_list_free_full(player->adaptive_info.var_list, g_free);
7900 player->adaptive_info.var_list = NULL;
7903 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7904 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7905 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7907 /* Reset video360 settings to their defaults in case if the pipeline is to be
7910 player->video360_metadata.is_spherical = -1;
7911 player->is_openal_plugin_used = FALSE;
7913 player->is_content_spherical = FALSE;
7914 player->is_video360_enabled = TRUE;
7915 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7916 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7917 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7918 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7919 player->video360_zoom = 1.0f;
7920 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7921 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7923 player->sound.rg_enable = false;
7925 __mmplayer_initialize_video_roi(player);
7930 __mmplayer_release_misc_post(mmplayer_t *player)
7932 gchar *original_uri = NULL;
7935 /* player->pipeline is already released before. */
7936 MMPLAYER_RETURN_IF_FAIL(player);
7938 player->video_decoded_cb = NULL;
7939 player->video_decoded_cb_user_param = NULL;
7940 player->video_stream_prerolled = false;
7942 player->audio_decoded_cb = NULL;
7943 player->audio_decoded_cb_user_param = NULL;
7944 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7946 player->audio_stream_changed_cb = NULL;
7947 player->audio_stream_changed_cb_user_param = NULL;
7949 mm_player_set_attribute((MMHandleType)player, NULL,
7950 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7952 /* clean found audio decoders */
7953 if (player->audio_decoders) {
7954 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7955 player->audio_decoders = NULL;
7958 /* clean the uri list except original uri */
7959 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7961 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7962 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7963 g_list_free_full(tmp, (GDestroyNotify)g_free);
7966 LOGW("failed to get original uri info");
7968 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7969 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7970 MMPLAYER_FREEIF(original_uri);
7973 /* clear the audio stream buffer list */
7974 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7976 /* clear the video stream bo list */
7977 __mmplayer_video_stream_destroy_bo_list(player);
7978 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7980 if (player->profile.input_mem.buf) {
7981 free(player->profile.input_mem.buf);
7982 player->profile.input_mem.buf = NULL;
7984 player->profile.input_mem.len = 0;
7985 player->profile.input_mem.offset = 0;
7987 player->uri_info.uri_idx = 0;
7992 __mmplayer_check_subtitle(mmplayer_t *player)
7994 MMHandleType attrs = 0;
7995 char *subtitle_uri = NULL;
7999 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8001 /* get subtitle attribute */
8002 attrs = MMPLAYER_GET_ATTRS(player);
8006 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8007 if (!subtitle_uri || !strlen(subtitle_uri))
8010 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
8011 player->is_external_subtitle_present = TRUE;
8019 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8021 MMPLAYER_RETURN_IF_FAIL(player);
8023 if (player->eos_timer) {
8024 LOGD("cancel eos timer");
8025 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8026 player->eos_timer = 0;
8033 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8037 MMPLAYER_RETURN_IF_FAIL(player);
8038 MMPLAYER_RETURN_IF_FAIL(sink);
8041 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8043 player->sink_elements = g_list_append(player->sink_elements, sink);
8049 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8053 MMPLAYER_RETURN_IF_FAIL(player);
8054 MMPLAYER_RETURN_IF_FAIL(sink);
8056 player->sink_elements = g_list_remove(player->sink_elements, sink);
8062 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8063 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8065 mmplayer_signal_item_t *item = NULL;
8068 MMPLAYER_RETURN_IF_FAIL(player);
8070 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8071 LOGE("invalid signal type [%d]", type);
8075 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8077 LOGE("cannot connect signal [%s]", signal);
8082 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8083 player->signals[type] = g_list_append(player->signals[type], item);
8089 /* NOTE : be careful with calling this api. please refer to below glib comment
8090 * glib comment : Note that there is a bug in GObject that makes this function much
8091 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8092 * will no longer be called, but, the signal handler is not currently disconnected.
8093 * If the instance is itself being freed at the same time than this doesn't matter,
8094 * since the signal will automatically be removed, but if instance persists,
8095 * then the signal handler will leak. You should not remove the signal yourself
8096 * because in a future versions of GObject, the handler will automatically be
8099 * It's possible to work around this problem in a way that will continue to work
8100 * with future versions of GObject by checking that the signal handler is still
8101 * connected before disconnected it:
8103 * if (g_signal_handler_is_connected(instance, id))
8104 * g_signal_handler_disconnect(instance, id);
8107 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8109 GList *sig_list = NULL;
8110 mmplayer_signal_item_t *item = NULL;
8114 MMPLAYER_RETURN_IF_FAIL(player);
8116 LOGD("release signals type : %d", type);
8118 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8119 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8120 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8121 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8122 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8123 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8127 sig_list = player->signals[type];
8129 for (; sig_list; sig_list = sig_list->next) {
8130 item = sig_list->data;
8132 if (item && item->obj) {
8133 if (g_signal_handler_is_connected(item->obj, item->sig))
8134 g_signal_handler_disconnect(item->obj, item->sig);
8137 MMPLAYER_FREEIF(item);
8140 g_list_free(player->signals[type]);
8141 player->signals[type] = NULL;
8149 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8151 mmplayer_t *player = 0;
8152 int prev_display_surface_type = 0;
8156 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8158 player = MM_PLAYER_CAST(handle);
8160 /* check video sinkbin is created */
8161 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8162 LOGW("Videosink is already created");
8163 return MM_ERROR_NONE;
8166 LOGD("videosink element is not yet ready");
8168 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8169 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8171 return MM_ERROR_INVALID_ARGUMENT;
8174 /* load previous attributes */
8175 if (player->attrs) {
8176 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8177 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8178 if (prev_display_surface_type == surface_type) {
8179 LOGD("incoming display surface type is same as previous one, do nothing..");
8181 return MM_ERROR_NONE;
8184 LOGE("failed to load attributes");
8186 return MM_ERROR_PLAYER_INTERNAL;
8189 /* videobin is not created yet, so we just set attributes related to display surface */
8190 LOGD("store display attribute for given surface type(%d)", surface_type);
8191 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8192 "display_overlay", wl_surface_id, NULL);
8195 return MM_ERROR_NONE;
8198 /* Note : if silent is true, then subtitle would not be displayed. :*/
8200 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8202 mmplayer_t *player = (mmplayer_t *)hplayer;
8206 /* check player handle */
8207 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8209 player->set_mode.subtitle_off = silent;
8211 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8215 return MM_ERROR_NONE;
8219 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8221 mmplayer_gst_element_t *mainbin = NULL;
8222 mmplayer_gst_element_t *textbin = NULL;
8223 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8224 GstState current_state = GST_STATE_VOID_PENDING;
8225 GstState element_state = GST_STATE_VOID_PENDING;
8226 GstState element_pending_state = GST_STATE_VOID_PENDING;
8228 GstEvent *event = NULL;
8229 int result = MM_ERROR_NONE;
8231 GstClock *curr_clock = NULL;
8232 GstClockTime base_time, start_time, curr_time;
8237 /* check player handle */
8238 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8240 player->pipeline->mainbin &&
8241 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8243 mainbin = player->pipeline->mainbin;
8244 textbin = player->pipeline->textbin;
8246 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8248 // sync clock with current pipeline
8249 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8250 curr_time = gst_clock_get_time(curr_clock);
8252 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8253 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8255 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8256 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8258 if (current_state > GST_STATE_READY) {
8259 // sync state with current pipeline
8260 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8261 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8262 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8264 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8265 if (GST_STATE_CHANGE_FAILURE == ret) {
8266 LOGE("fail to state change.");
8267 result = MM_ERROR_PLAYER_INTERNAL;
8271 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8272 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8275 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8276 gst_object_unref(curr_clock);
8279 // seek to current position
8280 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8281 result = MM_ERROR_PLAYER_INVALID_STATE;
8282 LOGE("gst_element_query_position failed, invalid state");
8286 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8287 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);
8289 _mmplayer_gst_send_event_to_sink(player, event);
8291 result = MM_ERROR_PLAYER_INTERNAL;
8292 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8296 /* sync state with current pipeline */
8297 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8298 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8299 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8301 return MM_ERROR_NONE;
8304 /* release text pipeline resource */
8305 player->textsink_linked = 0;
8307 /* release signal */
8308 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8310 /* release textbin with it's children */
8311 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8312 MMPLAYER_FREEIF(player->pipeline->textbin);
8313 player->pipeline->textbin = NULL;
8315 /* release subtitle elem */
8316 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8317 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8323 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8325 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8326 GstState current_state = GST_STATE_VOID_PENDING;
8328 MMHandleType attrs = 0;
8329 mmplayer_gst_element_t *mainbin = NULL;
8330 mmplayer_gst_element_t *textbin = NULL;
8332 gchar *subtitle_uri = NULL;
8333 int result = MM_ERROR_NONE;
8334 const gchar *charset = NULL;
8338 /* check player handle */
8339 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8341 player->pipeline->mainbin &&
8342 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8343 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8345 mainbin = player->pipeline->mainbin;
8346 textbin = player->pipeline->textbin;
8348 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8349 if (current_state < GST_STATE_READY) {
8350 result = MM_ERROR_PLAYER_INVALID_STATE;
8351 LOGE("Pipeline is not in proper state");
8355 attrs = MMPLAYER_GET_ATTRS(player);
8357 LOGE("cannot get content attribute");
8358 result = MM_ERROR_PLAYER_INTERNAL;
8362 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8363 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8364 LOGE("subtitle uri is not proper filepath");
8365 result = MM_ERROR_PLAYER_INVALID_URI;
8369 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8370 LOGE("failed to get storage info of subtitle path");
8371 result = MM_ERROR_PLAYER_INVALID_URI;
8375 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8376 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8378 if (!strcmp(filepath, subtitle_uri)) {
8379 LOGD("subtitle path is not changed");
8382 if (mm_player_set_attribute((MMHandleType)player, NULL,
8383 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8384 LOGE("failed to set attribute");
8389 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8390 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8391 player->subtitle_language_list = NULL;
8392 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8394 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8395 if (ret != GST_STATE_CHANGE_SUCCESS) {
8396 LOGE("failed to change state of textbin to READY");
8397 result = MM_ERROR_PLAYER_INTERNAL;
8401 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8402 if (ret != GST_STATE_CHANGE_SUCCESS) {
8403 LOGE("failed to change state of subparse to READY");
8404 result = MM_ERROR_PLAYER_INTERNAL;
8408 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8409 if (ret != GST_STATE_CHANGE_SUCCESS) {
8410 LOGE("failed to change state of filesrc to READY");
8411 result = MM_ERROR_PLAYER_INTERNAL;
8415 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8417 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8419 charset = _mmplayer_get_charset(filepath);
8421 LOGD("detected charset is %s", charset);
8422 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8425 result = _mmplayer_sync_subtitle_pipeline(player);
8432 /* API to switch between external subtitles */
8434 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8436 int result = MM_ERROR_NONE;
8437 mmplayer_t *player = (mmplayer_t *)hplayer;
8442 /* check player handle */
8443 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8445 /* filepath can be null in idle state */
8447 /* check file path */
8448 if ((path = strstr(filepath, "file://")))
8449 result = _mmplayer_exist_file_path(path + 7);
8451 result = _mmplayer_exist_file_path(filepath);
8453 if (result != MM_ERROR_NONE) {
8454 LOGE("invalid subtitle path 0x%X", result);
8455 return result; /* file not found or permission denied */
8459 if (!player->pipeline) {
8461 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8462 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8463 LOGE("failed to set attribute");
8464 return MM_ERROR_PLAYER_INTERNAL;
8467 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8468 /* check filepath */
8469 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8471 if (!__mmplayer_check_subtitle(player)) {
8472 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8473 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8474 LOGE("failed to set attribute");
8475 return MM_ERROR_PLAYER_INTERNAL;
8478 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8479 LOGE("fail to create text pipeline");
8480 return MM_ERROR_PLAYER_INTERNAL;
8483 result = _mmplayer_sync_subtitle_pipeline(player);
8485 result = __mmplayer_change_external_subtitle_language(player, filepath);
8488 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8489 player->is_external_subtitle_added_now = TRUE;
8491 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8492 if (!player->subtitle_language_list) {
8493 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8494 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8495 LOGW("subtitle language list is not updated yet");
8497 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8505 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8507 guint active_idx = 0;
8508 GstStream *stream = NULL;
8509 GList *streams = NULL;
8510 GstCaps *caps = NULL;
8513 LOGD("Switching Streams... type: %d, index: %d", type, index);
8515 player->track[type].active_track_index = index;
8517 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8518 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8519 LOGD("track type:%d, total: %d, active: %d", i,
8520 player->track[i].total_track_num, player->track[i].active_track_index);
8521 if (player->track[i].total_track_num > 0 &&
8522 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8523 active_idx = player->track[i].active_track_index;
8524 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8525 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8526 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8528 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8529 caps = gst_stream_get_caps(stream);
8531 _mmplayer_set_audio_attrs(player, caps);
8532 gst_caps_unref(caps);
8539 LOGD("send select stream event");
8540 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8541 gst_event_new_select_streams(streams));
8542 g_list_free(streams);
8545 /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8546 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8547 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8549 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8550 pos_nsec = player->last_position;
8552 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8554 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8555 player->playback_rate, GST_FORMAT_TIME,
8556 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8557 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8558 LOGW("failed to seek");
8559 return MM_ERROR_PLAYER_INTERNAL;
8564 return MM_ERROR_NONE;
8568 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8570 int result = MM_ERROR_NONE;
8571 gchar *change_pad_name = NULL;
8572 GstPad *sinkpad = NULL;
8573 mmplayer_gst_element_t *mainbin = NULL;
8574 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8575 GstCaps *caps = NULL;
8576 gint total_track_num = 0;
8580 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8581 MM_ERROR_PLAYER_NOT_INITIALIZED);
8583 LOGD("Change Track(%d) to %d", type, index);
8585 mainbin = player->pipeline->mainbin;
8587 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8588 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8589 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8590 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8592 /* Changing Video Track is not supported. */
8593 LOGE("Track Type Error");
8597 if (mainbin[elem_idx].gst == NULL) {
8598 result = MM_ERROR_PLAYER_NO_OP;
8599 LOGD("Req track doesn't exist");
8603 total_track_num = player->track[type].total_track_num;
8604 if (total_track_num <= 0) {
8605 result = MM_ERROR_PLAYER_NO_OP;
8606 LOGD("Language list is not available");
8610 if ((index < 0) || (index >= total_track_num)) {
8611 result = MM_ERROR_INVALID_ARGUMENT;
8612 LOGD("Not a proper index : %d", index);
8616 /*To get the new pad from the selector*/
8617 change_pad_name = g_strdup_printf("sink_%u", index);
8618 if (change_pad_name == NULL) {
8619 result = MM_ERROR_PLAYER_INTERNAL;
8620 LOGD("Pad does not exists");
8624 LOGD("new active pad name: %s", change_pad_name);
8626 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8627 if (sinkpad == NULL) {
8628 LOGD("sinkpad is NULL");
8629 result = MM_ERROR_PLAYER_INTERNAL;
8633 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8634 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8636 caps = gst_pad_get_current_caps(sinkpad);
8637 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8640 gst_object_unref(sinkpad);
8642 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8643 _mmplayer_set_audio_attrs(player, caps);
8646 gst_caps_unref(caps);
8649 MMPLAYER_FREEIF(change_pad_name);
8654 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8656 int result = MM_ERROR_NONE;
8657 mmplayer_t *player = NULL;
8658 mmplayer_gst_element_t *mainbin = NULL;
8660 gint current_active_index = 0;
8662 GstState current_state = GST_STATE_VOID_PENDING;
8667 player = (mmplayer_t *)hplayer;
8668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8670 if (!player->pipeline) {
8671 LOGE("Track %d pre setting -> %d", type, index);
8673 player->track[type].active_track_index = index;
8677 mainbin = player->pipeline->mainbin;
8679 current_active_index = player->track[type].active_track_index;
8681 /*If index is same as running index no need to change the pad*/
8682 if (current_active_index == index)
8685 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8686 result = MM_ERROR_PLAYER_INVALID_STATE;
8690 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8691 if (current_state < GST_STATE_PAUSED) {
8692 result = MM_ERROR_PLAYER_INVALID_STATE;
8693 LOGW("Pipeline not in proper state");
8697 if (MMPLAYER_USE_DECODEBIN(player))
8698 result = __mmplayer_change_selector_pad(player, type, index);
8700 result = __mmplayer_switch_stream(player, type, index);
8702 if (result != MM_ERROR_NONE) {
8703 LOGE("failed to change track");
8707 player->track[type].active_track_index = index;
8709 if (MMPLAYER_USE_DECODEBIN(player)) {
8710 GstEvent *event = NULL;
8711 if (current_state == GST_STATE_PLAYING) {
8712 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8713 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8714 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8716 _mmplayer_gst_send_event_to_sink(player, event);
8718 result = MM_ERROR_PLAYER_INTERNAL;
8729 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8731 mmplayer_t *player = (mmplayer_t *)hplayer;
8735 /* check player handle */
8736 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8738 *silent = player->set_mode.subtitle_off;
8740 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8744 return MM_ERROR_NONE;
8748 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8750 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8751 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8753 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8754 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8758 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8759 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8760 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8761 mmplayer_dump_t *dump_s;
8762 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8763 if (dump_s == NULL) {
8764 LOGE("malloc fail");
8768 dump_s->dump_element_file = NULL;
8769 dump_s->dump_pad = NULL;
8770 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8772 if (dump_s->dump_pad) {
8773 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8774 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]);
8775 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8776 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);
8777 /* add list for removed buffer probe and close FILE */
8778 player->dump_list = g_list_append(player->dump_list, dump_s);
8779 LOGD("%s sink pad added buffer probe for dump", factory_name);
8782 MMPLAYER_FREEIF(dump_s);
8783 LOGE("failed to get %s sink pad added", factory_name);
8790 static GstPadProbeReturn
8791 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8793 FILE *dump_data = (FILE *)u_data;
8795 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8796 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8798 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8800 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8802 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8804 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8806 gst_buffer_unmap(buffer, &probe_info);
8808 return GST_PAD_PROBE_OK;
8812 __mmplayer_release_dump_list(GList *dump_list)
8814 GList *d_list = dump_list;
8819 for (; d_list; d_list = g_list_next(d_list)) {
8820 mmplayer_dump_t *dump_s = d_list->data;
8821 if (dump_s->dump_pad) {
8822 if (dump_s->probe_handle_id)
8823 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8824 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8826 if (dump_s->dump_element_file) {
8827 fclose(dump_s->dump_element_file);
8828 dump_s->dump_element_file = NULL;
8830 MMPLAYER_FREEIF(dump_s);
8832 g_list_free(dump_list);
8837 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8839 mmplayer_t *player = (mmplayer_t *)hplayer;
8843 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8844 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8846 *exist = (bool)player->has_closed_caption;
8850 return MM_ERROR_NONE;
8854 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8859 LOGD("unref internal gst buffer %p", buffer);
8861 gst_buffer_unref((GstBuffer *)buffer);
8868 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8870 mmplayer_t *player = (mmplayer_t *)hplayer;
8874 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8875 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8877 if (MMPLAYER_IS_STREAMING(player))
8878 *timeout = (int)player->ini.live_state_change_timeout;
8880 *timeout = (int)player->ini.localplayback_state_change_timeout;
8882 LOGD("timeout = %d", *timeout);
8885 return MM_ERROR_NONE;
8889 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8893 MMPLAYER_RETURN_IF_FAIL(player);
8895 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8897 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8898 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8899 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8900 player->storage_info[i].id = -1;
8901 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8903 if (path_type != MMPLAYER_PATH_MAX)
8912 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8914 int ret = MM_ERROR_NONE;
8915 mmplayer_t *player = (mmplayer_t *)hplayer;
8916 MMMessageParamType msg_param = {0, };
8919 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8921 LOGW("state changed storage %d:%d", id, state);
8923 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8924 return MM_ERROR_NONE;
8926 /* FIXME: text path should be handled separately. */
8927 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8928 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8929 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8930 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8931 LOGW("external storage is removed");
8933 if (player->msg_posted == FALSE) {
8934 memset(&msg_param, 0, sizeof(MMMessageParamType));
8935 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8936 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8937 player->msg_posted = TRUE;
8940 /* unrealize the player */
8941 ret = _mmplayer_unrealize(hplayer);
8942 if (ret != MM_ERROR_NONE)
8943 LOGE("failed to unrealize");
8951 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8953 int ret = MM_ERROR_NONE;
8954 mmplayer_t *player = (mmplayer_t *)hplayer;
8955 int idx = 0, total = 0;
8956 gchar *result = NULL, *tmp = NULL;
8959 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8960 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8962 total = *num = g_list_length(player->adaptive_info.var_list);
8964 LOGW("There is no stream variant info.");
8968 result = g_strdup("");
8969 for (idx = 0 ; idx < total ; idx++) {
8970 stream_variant_t *v_data = NULL;
8971 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8974 gchar data[64] = {0};
8975 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8977 tmp = g_strconcat(result, data, NULL);
8981 LOGW("There is no variant data in %d", idx);
8986 *var_info = (char *)result;
8988 LOGD("variant info %d:%s", *num, *var_info);
8994 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8996 int ret = MM_ERROR_NONE;
8997 mmplayer_t *player = (mmplayer_t *)hplayer;
9000 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9002 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9004 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9005 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9006 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9008 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9009 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9010 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9011 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9013 /* FIXME: seek to current position for applying new variant limitation */
9022 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9024 int ret = MM_ERROR_NONE;
9025 mmplayer_t *player = (mmplayer_t *)hplayer;
9028 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9029 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9031 *bandwidth = player->adaptive_info.limit.bandwidth;
9032 *width = player->adaptive_info.limit.width;
9033 *height = player->adaptive_info.limit.height;
9035 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9042 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9044 int ret = MM_ERROR_NONE;
9045 mmplayer_t *player = (mmplayer_t *)hplayer;
9048 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9049 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9050 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9052 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9054 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9055 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9056 else /* live case */
9057 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9059 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9066 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9068 #define IDX_FIRST_SW_CODEC 0
9069 mmplayer_t *player = (mmplayer_t *)hplayer;
9070 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9071 const char *attr_name = NULL;
9072 const char *default_type = NULL;
9073 const char *element_hw = NULL;
9074 const char *element_sw = NULL;
9077 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9079 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9081 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9082 switch (stream_type) {
9083 case MM_PLAYER_STREAM_TYPE_AUDIO:
9084 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9085 default_type = player->ini.audiocodec_default_type;
9086 element_hw = player->ini.audiocodec_element_hw;
9087 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9089 case MM_PLAYER_STREAM_TYPE_VIDEO:
9090 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9091 default_type = player->ini.videocodec_default_type;
9092 element_hw = player->ini.videocodec_element_hw;
9093 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9096 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9097 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9101 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9103 if (!strcmp(default_type, "sw"))
9104 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9106 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9108 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9109 codec_type = default_codec_type;
9111 /* to support codec selection, codec info have to be added in ini file.
9112 in case of hw codec is selected, filter elements should be applied
9113 depending on the hw capabilities. */
9114 if (codec_type != default_codec_type) {
9115 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9116 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9117 LOGE("There is no codec for type %d", codec_type);
9118 return MM_ERROR_PLAYER_NO_OP;
9121 LOGD("sorting is required");
9122 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9123 player->need_audio_dec_sorting = TRUE;
9125 player->need_video_dec_sorting = TRUE;
9128 LOGD("update %s codec_type to %d", attr_name, codec_type);
9129 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9132 return MM_ERROR_NONE;
9136 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9138 mmplayer_t *player = (mmplayer_t *)hplayer;
9139 GstElement *rg_vol_element = NULL;
9143 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9145 player->sound.rg_enable = enabled;
9147 /* just hold rgvolume enable value if pipeline is not ready */
9148 if (!player->pipeline || !player->pipeline->audiobin) {
9149 LOGD("pipeline is not ready. holding rgvolume enable value");
9150 return MM_ERROR_NONE;
9153 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9155 if (!rg_vol_element) {
9156 LOGD("rgvolume element is not created");
9157 return MM_ERROR_PLAYER_INTERNAL;
9161 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9163 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9167 return MM_ERROR_NONE;
9171 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9173 mmplayer_t *player = (mmplayer_t *)hplayer;
9174 GstElement *rg_vol_element = NULL;
9175 gboolean enable = FALSE;
9179 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9180 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9182 /* just hold enable_rg value if pipeline is not ready */
9183 if (!player->pipeline || !player->pipeline->audiobin) {
9184 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9185 *enabled = player->sound.rg_enable;
9186 return MM_ERROR_NONE;
9189 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9191 if (!rg_vol_element) {
9192 LOGD("rgvolume element is not created");
9193 return MM_ERROR_PLAYER_INTERNAL;
9196 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9197 *enabled = (bool)enable;
9201 return MM_ERROR_NONE;
9205 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9207 mmplayer_t *player = (mmplayer_t *)hplayer;
9208 MMHandleType attrs = 0;
9210 int ret = MM_ERROR_NONE;
9214 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9216 attrs = MMPLAYER_GET_ATTRS(player);
9217 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9219 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9221 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9222 return MM_ERROR_PLAYER_INTERNAL;
9225 player->video_roi.scale_x = scale_x;
9226 player->video_roi.scale_y = scale_y;
9227 player->video_roi.scale_width = scale_width;
9228 player->video_roi.scale_height = scale_height;
9230 /* check video sinkbin is created */
9231 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9232 return MM_ERROR_NONE;
9234 if (!gst_video_overlay_set_video_roi_area(
9235 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9236 scale_x, scale_y, scale_width, scale_height))
9237 ret = MM_ERROR_PLAYER_INTERNAL;
9239 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9240 scale_x, scale_y, scale_width, scale_height);
9248 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9250 mmplayer_t *player = (mmplayer_t *)hplayer;
9251 int ret = MM_ERROR_NONE;
9255 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9256 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9258 *scale_x = player->video_roi.scale_x;
9259 *scale_y = player->video_roi.scale_y;
9260 *scale_width = player->video_roi.scale_width;
9261 *scale_height = player->video_roi.scale_height;
9263 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9264 *scale_x, *scale_y, *scale_width, *scale_height);
9270 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9272 mmplayer_t *player = (mmplayer_t *)hplayer;
9276 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9278 player->client_pid = pid;
9280 LOGD("client pid[%d] %p", pid, player);
9284 return MM_ERROR_NONE;
9288 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9290 mmplayer_t *player = (mmplayer_t *)hplayer;
9291 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9292 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9296 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9297 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9300 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9302 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9304 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9305 return MM_ERROR_NONE;
9307 /* in case of audio codec default type is HW */
9309 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9310 if (player->ini.support_audio_effect)
9311 return MM_ERROR_NONE;
9312 elem_id = MMPLAYER_A_FILTER;
9314 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9315 if (player->ini.support_replaygain_control)
9316 return MM_ERROR_NONE;
9317 elem_id = MMPLAYER_A_RGVOL;
9319 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9320 if (player->ini.support_pitch_control)
9321 return MM_ERROR_NONE;
9322 elem_id = MMPLAYER_A_PITCH;
9324 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9325 if (player->ini.support_audio_effect)
9326 return MM_ERROR_NONE;
9328 /* default case handling is not required */
9331 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9332 LOGW("audio control option [%d] is not available", opt);
9335 /* setting pcm exporting option is allowed before READY state */
9336 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9337 return MM_ERROR_PLAYER_INVALID_STATE;
9339 /* check whether the audio filter exist or not after READY state,
9340 because the sw codec could be added during auto-plugging in some cases */
9341 if (!player->pipeline ||
9342 !player->pipeline->audiobin ||
9343 !player->pipeline->audiobin[elem_id].gst) {
9344 LOGW("there is no audio elem [%d]", elem_id);
9349 LOGD("audio control opt %d, available %d", opt, *available);
9353 return MM_ERROR_NONE;
9357 __mmplayer_update_duration_value(mmplayer_t *player)
9359 gboolean ret = FALSE;
9360 gint64 dur_nsec = 0;
9361 LOGD("try to update duration");
9363 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9364 player->duration = dur_nsec;
9365 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9369 if (player->duration < 0) {
9370 LOGW("duration is Non-Initialized !!!");
9371 player->duration = 0;
9374 /* update streaming service type */
9375 player->streaming_type = _mmplayer_get_stream_service_type(player);
9377 /* check duration is OK */
9378 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9379 /* FIXIT : find another way to get duration here. */
9380 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9386 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9388 /* update audio params
9389 NOTE : We need original audio params and it can be only obtained from src pad of audio
9390 decoder. Below code only valid when we are not using 'resampler' just before
9391 'audioconverter'. */
9392 GstCaps *caps_a = NULL;
9394 gint samplerate = 0, channels = 0;
9395 GstStructure *p = NULL;
9396 GstElement *aconv = NULL;
9398 LOGD("try to update audio attrs");
9400 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9402 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9403 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9404 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9405 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9407 LOGE("there is no audio converter");
9411 pad = gst_element_get_static_pad(aconv, "sink");
9414 LOGW("failed to get pad from audio converter");
9418 caps_a = gst_pad_get_current_caps(pad);
9420 LOGW("not ready to get audio caps");
9421 gst_object_unref(pad);
9425 p = gst_caps_get_structure(caps_a, 0);
9426 gst_structure_get_int(p, "rate", &samplerate);
9427 gst_structure_get_int(p, "channels", &channels);
9429 mm_player_set_attribute((MMHandleType)player, NULL,
9430 "content_audio_samplerate", samplerate,
9431 "content_audio_channels", channels, NULL);
9433 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9435 gst_caps_unref(caps_a);
9436 gst_object_unref(pad);
9442 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9444 LOGD("try to update video attrs");
9446 GstCaps *caps_v = NULL;
9450 GstStructure *p = NULL;
9452 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9453 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9455 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9457 LOGD("no videosink sink pad");
9461 caps_v = gst_pad_get_current_caps(pad);
9462 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9463 if (!caps_v && player->v_stream_caps) {
9464 caps_v = player->v_stream_caps;
9465 gst_caps_ref(caps_v);
9469 LOGD("no negotiated caps from videosink");
9470 gst_object_unref(pad);
9474 p = gst_caps_get_structure(caps_v, 0);
9475 gst_structure_get_int(p, "width", &width);
9476 gst_structure_get_int(p, "height", &height);
9478 mm_player_set_attribute((MMHandleType)player, NULL,
9479 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9481 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9483 SECURE_LOGD("width : %d height : %d", width, height);
9485 gst_caps_unref(caps_v);
9486 gst_object_unref(pad);
9489 mm_player_set_attribute((MMHandleType)player, NULL,
9490 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9491 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9498 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9500 gboolean ret = FALSE;
9501 guint64 data_size = 0;
9505 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9506 if (!player->duration)
9509 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9510 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9511 if (stat(path, &sb) == 0)
9512 data_size = (guint64)sb.st_size;
9514 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9515 data_size = player->http_content_size;
9518 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9521 guint64 bitrate = 0;
9522 guint64 msec_dur = 0;
9524 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9526 bitrate = data_size * 8 * 1000 / msec_dur;
9527 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9528 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9529 mm_player_set_attribute((MMHandleType)player, NULL,
9530 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9533 LOGD("player duration is less than 0");
9537 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9538 if (player->total_bitrate) {
9539 mm_player_set_attribute((MMHandleType)player, NULL,
9540 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9549 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9551 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9552 data->uri_type = uri_type;
9556 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9558 int ret = MM_ERROR_PLAYER_INVALID_URI;
9560 char *buffer = NULL;
9561 char *seperator = strchr(path, ',');
9562 char ext[100] = {0,}, size[100] = {0,};
9565 if ((buffer = strstr(path, "ext="))) {
9566 buffer += strlen("ext=");
9568 if (strlen(buffer)) {
9569 strncpy(ext, buffer, 99);
9571 if ((seperator = strchr(ext, ','))
9572 || (seperator = strchr(ext, ' '))
9573 || (seperator = strchr(ext, '\0'))) {
9574 seperator[0] = '\0';
9579 if ((buffer = strstr(path, "size="))) {
9580 buffer += strlen("size=");
9582 if (strlen(buffer) > 0) {
9583 strncpy(size, buffer, 99);
9585 if ((seperator = strchr(size, ','))
9586 || (seperator = strchr(size, ' '))
9587 || (seperator = strchr(size, '\0'))) {
9588 seperator[0] = '\0';
9591 mem_size = atoi(size);
9596 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9598 if (mem_size && param) {
9599 if (data->input_mem.buf)
9600 free(data->input_mem.buf);
9601 data->input_mem.buf = malloc(mem_size);
9603 if (data->input_mem.buf) {
9604 memcpy(data->input_mem.buf, param, mem_size);
9605 data->input_mem.len = mem_size;
9606 ret = MM_ERROR_NONE;
9608 LOGE("failed to alloc mem %d", mem_size);
9609 ret = MM_ERROR_PLAYER_INTERNAL;
9612 data->input_mem.offset = 0;
9613 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9620 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9622 gchar *location = NULL;
9625 int ret = MM_ERROR_NONE;
9627 if ((path = strstr(uri, "file://"))) {
9628 location = g_filename_from_uri(uri, NULL, &err);
9629 if (!location || (err != NULL)) {
9630 LOGE("Invalid URI '%s' for filesrc: %s", path,
9631 (err != NULL) ? err->message : "unknown error");
9635 MMPLAYER_FREEIF(location);
9637 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9638 return MM_ERROR_PLAYER_INVALID_URI;
9640 LOGD("path from uri: %s", location);
9643 path = (location != NULL) ? (location) : ((char *)uri);
9646 ret = _mmplayer_exist_file_path(path);
9648 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9649 if (ret == MM_ERROR_NONE) {
9650 if (_mmplayer_is_sdp_file(path)) {
9651 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9652 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9653 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9655 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9656 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9658 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9659 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9661 LOGE("invalid uri, could not play..");
9662 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9665 MMPLAYER_FREEIF(location);
9670 static mmplayer_video_decoded_data_info_t *
9671 __mmplayer_create_stream_from_pad(GstPad *pad)
9673 GstCaps *caps = NULL;
9674 GstStructure *structure = NULL;
9675 unsigned int fourcc = 0;
9676 const gchar *string_format = NULL;
9677 mmplayer_video_decoded_data_info_t *stream = NULL;
9679 MMPixelFormatType format;
9682 caps = gst_pad_get_current_caps(pad);
9684 LOGE("Caps is NULL.");
9689 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9691 structure = gst_caps_get_structure(caps, 0);
9692 gst_structure_get_int(structure, "width", &width);
9693 gst_structure_get_int(structure, "height", &height);
9694 string_format = gst_structure_get_string(structure, "format");
9697 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9698 format = _mmplayer_get_pixtype(fourcc);
9699 gst_video_info_from_caps(&info, caps);
9700 gst_caps_unref(caps);
9703 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9704 LOGE("Wrong condition!!");
9708 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9710 LOGE("failed to alloc mem for video data");
9714 stream->width = width;
9715 stream->height = height;
9716 stream->format = format;
9717 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9723 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9725 unsigned int pitch = 0;
9726 unsigned int size = 0;
9728 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9731 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9732 bo = gst_tizen_memory_get_bos(mem, index);
9734 stream->bo[index] = tbm_bo_ref(bo);
9736 LOGE("failed to get bo for index %d", index);
9739 for (index = 0; index < stream->plane_num; index++) {
9740 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9741 stream->stride[index] = pitch;
9743 stream->elevation[index] = size / pitch;
9745 stream->elevation[index] = stream->height;
9750 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9752 if (stream->format == MM_PIXEL_FORMAT_I420) {
9753 int ret = TBM_SURFACE_ERROR_NONE;
9754 tbm_surface_h surface;
9755 tbm_surface_info_s info;
9757 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9759 ret = tbm_surface_get_info(surface, &info);
9760 if (ret != TBM_SURFACE_ERROR_NONE) {
9761 tbm_surface_destroy(surface);
9765 tbm_surface_destroy(surface);
9766 stream->stride[0] = info.planes[0].stride;
9767 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9768 stream->stride[1] = info.planes[1].stride;
9769 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9770 stream->stride[2] = info.planes[2].stride;
9771 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9772 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9773 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9774 stream->stride[0] = stream->width * 4;
9775 stream->elevation[0] = stream->height;
9776 stream->bo_size = stream->stride[0] * stream->height;
9778 LOGE("Not support format %d", stream->format);
9786 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9788 tbm_bo_handle thandle;
9790 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9791 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9792 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9796 unsigned char *src = NULL;
9797 unsigned char *dest = NULL;
9798 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9800 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9802 LOGE("fail to gst_memory_map");
9806 if (!mapinfo.data) {
9807 LOGE("data pointer is wrong");
9811 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9812 if (!stream->bo[0]) {
9813 LOGE("Fail to tbm_bo_alloc!!");
9817 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9819 LOGE("thandle pointer is wrong");
9823 if (stream->format == MM_PIXEL_FORMAT_I420) {
9824 src_stride[0] = GST_ROUND_UP_4(stream->width);
9825 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9826 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9827 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9830 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9831 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9833 for (i = 0; i < 3; i++) {
9834 src = mapinfo.data + src_offset[i];
9835 dest = thandle.ptr + dest_offset[i];
9840 for (j = 0; j < stream->height >> k; j++) {
9841 memcpy(dest, src, stream->width>>k);
9842 src += src_stride[i];
9843 dest += stream->stride[i];
9846 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9847 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9849 LOGE("Not support format %d", stream->format);
9853 tbm_bo_unmap(stream->bo[0]);
9854 gst_memory_unmap(mem, &mapinfo);
9860 tbm_bo_unmap(stream->bo[0]);
9863 gst_memory_unmap(mem, &mapinfo);
9869 __mmplayer_set_pause_state(mmplayer_t *player)
9871 if (player->sent_bos)
9874 /* rtsp case, get content attrs by GstMessage */
9875 if (MMPLAYER_IS_RTSP_STREAMING(player))
9878 /* it's first time to update all content attrs. */
9879 _mmplayer_update_content_attrs(player, ATTR_ALL);
9883 __mmplayer_set_playing_state(mmplayer_t *player)
9885 gchar *audio_codec = NULL;
9887 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9888 /* initialize because auto resume is done well. */
9889 player->resumed_by_rewind = FALSE;
9890 player->playback_rate = 1.0;
9893 if (player->sent_bos)
9896 /* try to get content metadata */
9898 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9899 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9900 * legacy mmfw-player api
9902 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9904 if ((player->cmd == MMPLAYER_COMMAND_START)
9905 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9906 __mmplayer_handle_missed_plugin(player);
9909 /* check audio codec field is set or not
9910 * we can get it from typefinder or codec's caps.
9912 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9914 /* The codec format can't be sent for audio only case like amr, mid etc.
9915 * Because, parser don't make related TAG.
9916 * So, if it's not set yet, fill it with found data.
9919 if (g_strrstr(player->type, "audio/midi"))
9920 audio_codec = "MIDI";
9921 else if (g_strrstr(player->type, "audio/x-amr"))
9922 audio_codec = "AMR";
9923 else if (g_strrstr(player->type, "audio/mpeg")
9924 && !g_strrstr(player->type, "mpegversion=(int)1"))
9925 audio_codec = "AAC";
9927 audio_codec = "unknown";
9929 if (mm_player_set_attribute((MMHandleType)player, NULL,
9930 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9931 LOGE("failed to set attribute");
9933 LOGD("set audio codec type with caps");