4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related function will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
143 static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
144 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void __mmplayer_release_misc(mmplayer_t *player);
150 static void __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
160 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
161 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
162 static gpointer __mmplayer_gapless_play_thread(gpointer data);
163 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
164 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
165 static void __mmplayer_release_dump_list(GList *dump_list);
166 static int __mmplayer_gst_realize(mmplayer_t *player);
167 static int __mmplayer_gst_unrealize(mmplayer_t *player);
168 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
169 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
172 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
173 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
174 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
175 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
176 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
177 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
178 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
179 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
180 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
181 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
182 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
183 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
184 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
187 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
188 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
189 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
191 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
192 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
193 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
194 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
196 static void __mmplayer_set_pause_state(mmplayer_t *player);
197 static void __mmplayer_set_playing_state(mmplayer_t *player);
198 static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
199 /*===========================================================================================
201 | FUNCTION DEFINITIONS |
203 ========================================================================================== */
205 /* This function should be called after the pipeline goes PAUSED or higher
208 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
210 static gboolean has_duration = FALSE;
211 static gboolean has_video_attrs = FALSE;
212 static gboolean has_audio_attrs = FALSE;
213 static gboolean has_bitrate = FALSE;
214 gboolean missing_only = FALSE;
215 gboolean all = FALSE;
216 MMHandleType attrs = 0;
220 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
222 /* check player state here */
223 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
224 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
225 /* give warning now only */
226 LOGW("be careful. content attributes may not available in this state ");
229 /* get content attribute first */
230 attrs = MMPLAYER_GET_ATTRS(player);
232 LOGE("cannot get content attribute");
236 /* get update flag */
238 if (flag & ATTR_MISSING_ONLY) {
240 LOGD("updating missed attr only");
243 if (flag & ATTR_ALL) {
245 has_duration = FALSE;
246 has_video_attrs = FALSE;
247 has_audio_attrs = FALSE;
250 LOGD("updating all attrs");
253 if (missing_only && all) {
254 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
255 missing_only = FALSE;
258 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
259 has_duration = __mmplayer_update_duration_value(player);
261 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
262 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
264 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
265 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
267 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
268 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
276 _mmplayer_get_stream_service_type(mmplayer_t *player)
278 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
282 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
284 player->pipeline->mainbin &&
285 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
286 STREAMING_SERVICE_NONE);
288 /* streaming service type if streaming */
289 if (!MMPLAYER_IS_STREAMING(player))
290 return STREAMING_SERVICE_NONE;
292 streaming_type = (player->duration == 0) ?
293 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
295 switch (streaming_type) {
296 case STREAMING_SERVICE_LIVE:
297 LOGD("it's live streaming");
299 case STREAMING_SERVICE_VOD:
300 LOGD("it's vod streaming");
303 LOGE("should not get here");
309 return streaming_type;
312 /* this function sets the player state and also report
313 * it to application by calling callback function
316 _mmplayer_set_state(mmplayer_t *player, int state)
318 MMMessageParamType msg = {0, };
320 MMPLAYER_RETURN_IF_FAIL(player);
322 if (MMPLAYER_CURRENT_STATE(player) == state) {
323 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
324 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
328 /* update player states */
329 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
330 MMPLAYER_CURRENT_STATE(player) = state;
332 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
333 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
336 MMPLAYER_PRINT_STATE(player);
338 switch (MMPLAYER_CURRENT_STATE(player)) {
339 case MM_PLAYER_STATE_NULL:
340 case MM_PLAYER_STATE_READY:
342 case MM_PLAYER_STATE_PAUSED:
343 __mmplayer_set_pause_state(player);
345 case MM_PLAYER_STATE_PLAYING:
346 __mmplayer_set_playing_state(player);
348 case MM_PLAYER_STATE_NONE:
350 LOGW("invalid target state, there is nothing to do.");
355 /* post message to application */
356 if (MMPLAYER_TARGET_STATE(player) == state) {
357 /* fill the message with state of player */
358 msg.union_type = MM_MSG_UNION_STATE;
359 msg.state.previous = MMPLAYER_PREV_STATE(player);
360 msg.state.current = MMPLAYER_CURRENT_STATE(player);
362 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
364 /* state changed by resource callback */
365 if (player->interrupted_by_resource)
366 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
367 else /* state changed by usecase */
368 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
371 LOGD("intermediate state, do nothing.");
372 MMPLAYER_PRINT_STATE(player);
376 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
377 && !player->sent_bos) {
378 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
379 player->sent_bos = TRUE;
386 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
388 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
389 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
391 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
393 LOGD("incoming command : %d ", command);
395 current_state = MMPLAYER_CURRENT_STATE(player);
396 pending_state = MMPLAYER_PENDING_STATE(player);
398 MMPLAYER_PRINT_STATE(player);
401 case MMPLAYER_COMMAND_CREATE:
403 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
405 if (current_state == MM_PLAYER_STATE_NULL ||
406 current_state == MM_PLAYER_STATE_READY ||
407 current_state == MM_PLAYER_STATE_PAUSED ||
408 current_state == MM_PLAYER_STATE_PLAYING)
413 case MMPLAYER_COMMAND_DESTROY:
415 /* destroy can called anytime */
417 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
421 case MMPLAYER_COMMAND_REALIZE:
423 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
425 if (pending_state != MM_PLAYER_STATE_NONE) {
428 /* need ready state to realize */
429 if (current_state == MM_PLAYER_STATE_READY)
432 if (current_state != MM_PLAYER_STATE_NULL)
438 case MMPLAYER_COMMAND_UNREALIZE:
440 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
442 if (current_state == MM_PLAYER_STATE_NULL)
447 case MMPLAYER_COMMAND_START:
449 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
451 if (pending_state == MM_PLAYER_STATE_NONE) {
452 if (current_state == MM_PLAYER_STATE_PLAYING)
454 else if (current_state != MM_PLAYER_STATE_READY &&
455 current_state != MM_PLAYER_STATE_PAUSED)
457 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
459 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
460 LOGD("player is going to paused state, just change the pending state as playing");
467 case MMPLAYER_COMMAND_STOP:
469 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
471 if (current_state == MM_PLAYER_STATE_READY)
474 /* need playing/paused state to stop */
475 if (current_state != MM_PLAYER_STATE_PLAYING &&
476 current_state != MM_PLAYER_STATE_PAUSED)
481 case MMPLAYER_COMMAND_PAUSE:
483 if (MMPLAYER_IS_LIVE_STREAMING(player))
486 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
487 goto NOT_COMPLETED_SEEK;
489 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
491 if (pending_state == MM_PLAYER_STATE_NONE) {
492 if (current_state == MM_PLAYER_STATE_PAUSED)
494 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
496 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
499 if (current_state == MM_PLAYER_STATE_PAUSED)
500 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
507 case MMPLAYER_COMMAND_RESUME:
509 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
510 goto NOT_COMPLETED_SEEK;
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
514 if (pending_state == MM_PLAYER_STATE_NONE) {
515 if (current_state == MM_PLAYER_STATE_PLAYING)
517 else if (current_state != MM_PLAYER_STATE_PAUSED)
519 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
521 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
522 LOGD("player is going to paused state, just change the pending state as playing");
532 player->cmd = command;
534 return MM_ERROR_NONE;
537 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
538 MMPLAYER_STATE_GET_NAME(current_state), command);
539 return MM_ERROR_PLAYER_INVALID_STATE;
542 LOGW("not completed seek");
543 return MM_ERROR_PLAYER_DOING_SEEK;
546 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
547 return MM_ERROR_PLAYER_NO_OP;
550 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
551 return MM_ERROR_PLAYER_NO_OP;
554 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
556 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
557 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
560 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
561 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
563 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
564 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
566 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
567 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
570 LOGE("invalid mmplayer resource type %d", type);
571 return MM_ERROR_PLAYER_INTERNAL;
574 if (player->hw_resource[type] != NULL) {
575 LOGD("[%d type] resource was already acquired", type);
576 return MM_ERROR_NONE;
579 LOGD("mark for acquire [%d type] resource", type);
580 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
581 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
582 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
583 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
584 return MM_ERROR_PLAYER_INTERNAL;
587 LOGD("commit [%d type] resource", type);
588 rm_ret = mm_resource_manager_commit(player->resource_manager);
589 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
590 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
591 return MM_ERROR_PLAYER_INTERNAL;
595 return MM_ERROR_NONE;
598 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
600 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
602 MMPLAYER_RETURN_IF_FAIL(player);
603 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
605 rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
606 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
607 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
611 rm_ret = mm_resource_manager_commit(player->resource_manager);
612 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
613 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
616 /* de-initialize resource manager */
617 rm_ret = mm_resource_manager_destroy(player->resource_manager);
618 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
619 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
623 player->resource_manager = NULL;
625 LOGD("resource manager is destroyed");
628 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
630 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
634 if (player->hw_resource[type] == NULL) {
635 LOGD("there is no acquired [%d type] resource", type);
636 return MM_ERROR_NONE;
639 LOGD("mark for release [%d type] resource", type);
640 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
641 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
642 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
643 return MM_ERROR_PLAYER_INTERNAL;
646 player->hw_resource[type] = NULL;
648 LOGD("commit [%d type] resource", type);
649 rm_ret = mm_resource_manager_commit(player->resource_manager);
650 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
651 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
652 return MM_ERROR_PLAYER_INTERNAL;
656 return MM_ERROR_NONE;
660 __mmplayer_initialize_gapless_play(mmplayer_t *player)
666 player->smooth_streaming = FALSE;
667 player->videodec_linked = 0;
668 player->audiodec_linked = 0;
669 player->textsink_linked = 0;
670 player->is_external_subtitle_present = FALSE;
671 player->is_external_subtitle_added_now = FALSE;
672 player->not_supported_codec = MISSING_PLUGIN_NONE;
673 player->can_support_codec = FOUND_PLUGIN_NONE;
674 player->pending_seek.is_pending = false;
675 player->pending_seek.pos = 0;
676 player->msg_posted = FALSE;
677 player->has_many_types = FALSE;
678 player->no_more_pad = FALSE;
679 player->not_found_demuxer = 0;
680 player->seek_state = MMPLAYER_SEEK_NONE;
681 player->is_subtitle_force_drop = FALSE;
682 player->play_subtitle = FALSE;
683 player->adjust_subtitle_pos = 0;
685 player->total_bitrate = 0;
686 player->total_maximum_bitrate = 0;
688 _mmplayer_track_initialize(player);
689 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
691 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
692 player->bitrate[i] = 0;
693 player->maximum_bitrate[i] = 0;
696 if (player->v_stream_caps) {
697 gst_caps_unref(player->v_stream_caps);
698 player->v_stream_caps = NULL;
701 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
703 /* clean found audio decoders */
704 if (player->audio_decoders) {
705 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
706 player->audio_decoders = NULL;
709 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
714 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
716 LOGI("set pipeline reconfigure state %d", state);
717 MMPLAYER_RECONFIGURE_LOCK(player);
718 player->gapless.reconfigure = state;
719 if (!state) /* wake up the waiting job */
720 MMPLAYER_RECONFIGURE_SIGNAL(player);
721 MMPLAYER_RECONFIGURE_UNLOCK(player);
725 __mmplayer_gapless_play_thread(gpointer data)
727 mmplayer_t *player = (mmplayer_t *)data;
728 mmplayer_gst_element_t *mainbin = NULL;
730 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
732 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
733 while (!player->gapless_play_thread_exit) {
734 LOGD("gapless play thread started. waiting for signal.");
735 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
737 LOGD("reconfigure pipeline for gapless play.");
739 if (player->gapless_play_thread_exit) {
740 _mmplayer_set_reconfigure_state(player, FALSE);
741 LOGD("exiting gapless play thread");
745 mainbin = player->pipeline->mainbin;
747 if (MMPLAYER_USE_DECODEBIN(player)) {
748 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
749 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* decodebin */
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
753 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG); /* uridecodebin */
754 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = NULL;
755 mainbin[MMPLAYER_M_TYPEFIND].gst = NULL;
756 mainbin[MMPLAYER_M_SRC].gst = NULL;
759 /* Initialize Player values */
760 __mmplayer_initialize_gapless_play(player);
762 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
764 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
770 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
772 GSource *source = NULL;
776 source = g_main_context_find_source_by_id(context, source_id);
777 if (source != NULL) {
778 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
779 g_source_destroy(source);
786 _mmplayer_watcher_removed_notify(gpointer data)
788 mmplayer_t *player = (mmplayer_t *)data;
789 MMPLAYER_RETURN_IF_FAIL(player);
791 MMPLAYER_BUS_WATCHER_LOCK(player);
792 player->bus_watcher = 0;
793 MMPLAYER_BUS_WATCHER_SIGNAL(player);
794 MMPLAYER_BUS_WATCHER_UNLOCK(player);
798 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
800 mmplayer_t *player = (mmplayer_t *)hplayer;
803 MMPLAYER_RETURN_IF_FAIL(player);
805 /* disconnecting bus watch */
806 if (player->bus_watcher > 0) {
807 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
808 MMPLAYER_BUS_WATCHER_LOCK(player);
809 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
810 while (player->bus_watcher > 0) {
811 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
812 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
813 player->bus_watcher);
817 MMPLAYER_BUS_WATCHER_UNLOCK(player);
818 g_mutex_clear(&player->bus_watcher_mutex);
819 g_cond_clear(&player->bus_watcher_cond);
826 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
828 mmplayer_t *player = (mmplayer_t *)hplayer;
829 GstMessage *msg = NULL;
830 GQueue *queue = NULL;
833 MMPLAYER_RETURN_IF_FAIL(player);
835 /* destroy the gst bus msg thread */
836 if (player->bus_msg_thread) {
837 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
838 player->bus_msg_thread_exit = TRUE;
839 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
840 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
842 LOGD("gst bus msg thread exit.");
843 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
844 player->bus_msg_thread = NULL;
846 g_mutex_clear(&player->bus_msg_thread_mutex);
847 g_cond_clear(&player->bus_msg_thread_cond);
850 g_mutex_lock(&player->bus_msg_q_lock);
851 queue = player->bus_msg_q;
852 while (!g_queue_is_empty(queue)) {
853 msg = (GstMessage *)g_queue_pop_head(queue);
858 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
859 gst_message_unref(msg);
861 g_mutex_unlock(&player->bus_msg_q_lock);
867 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
869 GstElement *parent = NULL;
871 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
872 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
875 MMPLAYER_FSINK_LOCK(player);
877 /* get parent of fakesink */
878 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
880 LOGD("fakesink already removed");
884 gst_element_set_locked_state(fakesink->gst, TRUE);
886 /* setting the state to NULL never returns async
887 * so no need to wait for completion of state transition
889 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
890 LOGE("fakesink state change failure!");
891 /* FIXIT : should I return here? or try to proceed to next? */
894 /* remove fakesink from it's parent */
895 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
896 LOGE("failed to remove fakesink");
898 gst_object_unref(parent);
903 gst_object_unref(parent);
905 LOGD("state-holder removed");
907 gst_element_set_locked_state(fakesink->gst, FALSE);
909 MMPLAYER_FSINK_UNLOCK(player);
914 gst_element_set_locked_state(fakesink->gst, FALSE);
916 MMPLAYER_FSINK_UNLOCK(player);
920 static GstPadProbeReturn
921 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
923 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
924 return GST_PAD_PROBE_OK;
928 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
930 gint64 stop_running_time = 0;
931 gint64 position_running_time = 0;
935 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
936 if ((player->gapless.update_segment[idx] == TRUE) ||
937 !(player->track[idx].event_probe_id)) {
939 LOGW("[%d] skip", idx);
944 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
946 gst_segment_to_running_time(&player->gapless.segment[idx],
947 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
948 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
950 gst_segment_to_running_time(&player->gapless.segment[idx],
951 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
953 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
955 gst_segment_to_running_time(&player->gapless.segment[idx],
956 GST_FORMAT_TIME, player->duration);
959 position_running_time =
960 gst_segment_to_running_time(&player->gapless.segment[idx],
961 GST_FORMAT_TIME, player->gapless.segment[idx].position);
963 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
964 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
966 GST_TIME_ARGS(stop_running_time),
967 GST_TIME_ARGS(position_running_time),
968 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
969 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
971 position_running_time = MAX(position_running_time, stop_running_time);
972 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
973 GST_FORMAT_TIME, player->gapless.segment[idx].start);
974 position_running_time = MAX(0, position_running_time);
975 position = MAX(position, position_running_time);
979 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
980 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
981 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
983 player->gapless.start_time[stream_type] += position;
989 static GstPadProbeReturn
990 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
992 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
993 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
994 mmplayer_t *player = (mmplayer_t *)data;
995 GstCaps *caps = NULL;
996 GstStructure *str = NULL;
997 const gchar *name = NULL;
998 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
999 gboolean caps_ret = TRUE;
1001 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1002 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1003 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1004 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1005 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1008 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1012 if (strstr(name, "audio")) {
1013 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1014 } else if (strstr(name, "video")) {
1015 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1017 /* text track is not supportable */
1018 LOGE("invalid name %s", name);
1022 switch (GST_EVENT_TYPE(event)) {
1025 /* in case of gapless, drop eos event not to send it to sink */
1026 if (player->gapless.reconfigure && !player->msg_posted) {
1027 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1028 ret = GST_PAD_PROBE_DROP;
1032 case GST_EVENT_STREAM_START:
1034 __mmplayer_gst_selector_update_start_time(player, stream_type);
1037 case GST_EVENT_FLUSH_STOP:
1039 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1040 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1041 player->gapless.start_time[stream_type] = 0;
1044 case GST_EVENT_SEGMENT:
1049 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1050 gst_event_copy_segment(event, &segment);
1052 if (segment.format != GST_FORMAT_TIME)
1055 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1056 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1057 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1058 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1059 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1060 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1062 /* keep the all the segment ev to cover the seeking */
1063 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1064 player->gapless.update_segment[stream_type] = TRUE;
1066 if (!player->gapless.running)
1069 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1071 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1073 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1074 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1075 gst_event_unref(event);
1076 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1082 gdouble proportion = 0.0;
1083 GstClockTimeDiff diff = 0;
1084 GstClockTime timestamp = 0;
1085 gint64 running_time_diff = -1;
1086 GstQOSType type = 0;
1087 GstEvent *tmpev = NULL;
1089 running_time_diff = player->gapless.segment[stream_type].base;
1091 if (running_time_diff <= 0) /* don't need to adjust */
1094 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1095 gst_event_unref(event);
1097 if (timestamp < running_time_diff) {
1098 LOGW("QOS event from previous group");
1099 ret = GST_PAD_PROBE_DROP;
1104 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1105 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1106 stream_type, GST_TIME_ARGS(timestamp),
1107 GST_TIME_ARGS(running_time_diff),
1108 GST_TIME_ARGS(timestamp - running_time_diff));
1111 timestamp -= running_time_diff;
1113 /* That case is invalid for QoS events */
1114 if (diff < 0 && -diff > timestamp) {
1115 LOGW("QOS event from previous group");
1116 ret = GST_PAD_PROBE_DROP;
1120 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1121 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1131 gst_caps_unref(caps);
1135 /* create fakesink for audio or video path without audiobin or videobin */
1137 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1139 GstElement *pipeline = NULL;
1140 GstElement *fakesink = NULL;
1141 GstPad *sinkpad = NULL;
1144 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1146 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1149 fakesink = gst_element_factory_make("fakesink", NULL);
1150 if (fakesink == NULL) {
1151 LOGE("failed to create fakesink");
1155 /* store it as it's sink element */
1156 __mmplayer_add_sink(player, fakesink, FALSE);
1158 gst_bin_add(GST_BIN(pipeline), fakesink);
1161 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1163 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1165 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1166 LOGE("failed to link fakesink");
1167 gst_object_unref(GST_OBJECT(fakesink));
1171 if (strstr(name, "video")) {
1172 if (player->v_stream_caps) {
1173 gst_caps_unref(player->v_stream_caps);
1174 player->v_stream_caps = NULL;
1176 if (player->ini.set_dump_element_flag)
1177 __mmplayer_add_dump_buffer_probe(player, fakesink);
1180 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1181 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1185 gst_object_unref(GST_OBJECT(sinkpad));
1192 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1194 GstElement *pipeline = NULL;
1195 GstElement *concat = NULL;
1198 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1200 concat = gst_element_factory_make("concat", NULL);
1202 LOGE("failed to create concat");
1206 LOGD("Create concat [%d] element", elem_idx);
1208 player->pipeline->mainbin[elem_idx].id = elem_idx;
1209 player->pipeline->mainbin[elem_idx].gst = concat;
1211 gst_element_set_state(concat, GST_STATE_PAUSED);
1213 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1214 gst_bin_add(GST_BIN(pipeline), concat);
1221 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1223 GstElement *pipeline = NULL;
1224 GstElement *selector = NULL;
1225 GstPad *srcpad = NULL;
1228 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1230 selector = gst_element_factory_make("input-selector", NULL);
1232 LOGE("failed to create input-selector");
1235 g_object_set(selector, "sync-streams", TRUE, NULL);
1237 player->pipeline->mainbin[elem_idx].id = elem_idx;
1238 player->pipeline->mainbin[elem_idx].gst = selector;
1240 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1242 srcpad = gst_element_get_static_pad(selector, "src");
1244 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1245 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1246 __mmplayer_gst_selector_blocked, NULL, NULL);
1247 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1248 __mmplayer_gst_selector_event_probe, player, NULL);
1250 gst_element_set_state(selector, GST_STATE_PAUSED);
1252 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1253 gst_bin_add(GST_BIN(pipeline), selector);
1255 gst_object_unref(GST_OBJECT(srcpad));
1262 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1264 mmplayer_t *player = (mmplayer_t *)data;
1265 GstElement *combiner = NULL;
1266 GstCaps *caps = NULL;
1267 GstStructure *str = NULL;
1268 const gchar *name = NULL;
1269 GstPad *sinkpad = NULL;
1270 gboolean first_track = FALSE;
1271 gboolean caps_ret = TRUE;
1273 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1274 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1277 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1278 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1280 LOGD("pad-added signal handling");
1282 /* get mimetype from caps */
1283 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1287 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1289 LOGD("detected mimetype : %s", name);
1292 if (strstr(name, "video")) {
1294 gchar *caps_str = NULL;
1296 caps_str = gst_caps_to_string(caps);
1297 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1298 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1299 player->set_mode.video_zc = true;
1301 MMPLAYER_FREEIF(caps_str);
1303 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1304 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1306 LOGD("surface type : %d", stype);
1308 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1309 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1313 /* in case of exporting video frame, it requires the 360 video filter.
1314 * it will be handled in _no_more_pads(). */
1315 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1316 __mmplayer_gst_make_fakesink(player, pad, name);
1320 if (MMPLAYER_USE_DECODEBIN(player)) {
1321 LOGD("video selector is required");
1322 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1324 LOGD("video concat is required");
1325 elem_idx = MMPLAYER_M_V_CONCAT;
1327 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1328 } else if (strstr(name, "audio")) {
1329 gint samplerate = 0;
1332 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1333 if (player->build_audio_offload)
1334 player->no_more_pad = TRUE; /* remove state holder */
1335 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1339 gst_structure_get_int(str, "rate", &samplerate);
1340 gst_structure_get_int(str, "channels", &channels);
1342 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1343 __mmplayer_gst_make_fakesink(player, pad, name);
1346 if (MMPLAYER_USE_DECODEBIN(player)) {
1347 LOGD("audio selector is required");
1348 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1350 LOGD("audio concat is required");
1351 elem_idx = MMPLAYER_M_A_CONCAT;
1353 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1355 } else if (strstr(name, "text")) {
1356 if (MMPLAYER_USE_DECODEBIN(player)) {
1357 LOGD("text selector is required");
1358 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1360 LOGD("text concat is required");
1361 elem_idx = MMPLAYER_M_T_CONCAT;
1363 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1365 LOGE("invalid caps info");
1369 /* check selector and create it */
1370 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1371 if (MMPLAYER_USE_DECODEBIN(player))
1372 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1374 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1380 LOGD("Combiner element is already created.");
1384 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1386 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1388 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1389 LOGE("failed to link combiner");
1390 gst_object_unref(GST_OBJECT(combiner));
1395 if (MMPLAYER_USE_DECODEBIN(player)) {
1396 LOGD("this track will be activated");
1397 g_object_set(combiner, "active-pad", sinkpad, NULL);
1401 if (MMPLAYER_USE_DECODEBIN(player)) {
1402 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1404 /* apply the text track information */
1405 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1406 mm_player_set_attribute((MMHandleType)player, NULL,
1407 "content_text_track_num", player->track[stream_type].total_track_num,
1408 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1409 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1416 gst_caps_unref(caps);
1419 gst_object_unref(GST_OBJECT(sinkpad));
1427 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1429 GstPad *srcpad = NULL;
1432 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1434 LOGD("type %d", type);
1437 LOGD("there is no %d track", type);
1441 srcpad = gst_element_get_static_pad(combiner, "src");
1443 LOGE("failed to get srcpad from combiner");
1447 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1449 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1451 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1452 if (player->track[type].block_id) {
1453 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1454 player->track[type].block_id = 0;
1458 gst_object_unref(GST_OBJECT(srcpad));
1467 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1469 gint active_index = 0;
1472 MMPLAYER_RETURN_IF_FAIL(player);
1474 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1476 /* change track to active pad */
1477 active_index = player->track[type].active_track_index;
1478 if ((active_index != DEFAULT_TRACK_INDEX) &&
1479 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1480 LOGW("failed to change %d type track to %d", type, active_index);
1481 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1485 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1486 mm_player_set_attribute((MMHandleType)player, NULL,
1487 "content_text_track_num", player->track[type].total_track_num,
1488 "current_text_track_index", player->track[type].active_track_index, NULL);
1495 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1498 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1500 if (!audio_selector) {
1501 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1503 /* in case the source is changed, output can be changed. */
1504 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1505 LOGD("remove previous audiobin if it exist");
1507 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1508 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1510 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1511 MMPLAYER_FREEIF(player->pipeline->audiobin);
1514 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1515 _mmplayer_pipeline_complete(NULL, player);
1520 /* apply the audio track information */
1521 if (MMPLAYER_USE_DECODEBIN(player))
1522 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1524 /* create audio sink path */
1525 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1526 LOGE("failed to create audio sink path");
1535 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1538 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1540 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1541 LOGD("text path is not supported");
1545 /* apply the text track information */
1546 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1548 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1549 player->has_closed_caption = TRUE;
1551 /* create text decode path */
1552 player->no_more_pad = TRUE;
1554 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1555 LOGE("failed to create text sink path");
1564 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1566 gint64 dur_bytes = 0L;
1569 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1570 player->pipeline->mainbin && player->streamer, FALSE);
1572 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1573 LOGE("fail to get duration.");
1575 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1576 * use file information was already set on Q2 when it was created. */
1577 _mm_player_streaming_set_queue2(player->streamer,
1578 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1579 TRUE, /* use_buffering */
1580 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1581 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1588 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1590 mmplayer_t *player = NULL;
1591 GstElement *video_selector = NULL;
1592 GstElement *audio_selector = NULL;
1593 GstElement *text_selector = NULL;
1596 player = (mmplayer_t *)data;
1598 LOGD("no-more-pad signal handling");
1600 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1601 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1602 LOGW("player is shutting down");
1606 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1607 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1608 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1609 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1610 LOGE("failed to set queue2 buffering");
1615 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1616 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1617 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1619 if (!video_selector && !audio_selector && !text_selector) {
1620 LOGW("there is no selector");
1621 player->no_more_pad = TRUE;
1625 /* create video path followed by video-select */
1626 if (video_selector && !audio_selector && !text_selector)
1627 player->no_more_pad = TRUE;
1629 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1632 /* create audio path followed by audio-select */
1633 if (audio_selector && !text_selector)
1634 player->no_more_pad = TRUE;
1636 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1639 /* create text path followed by text-select */
1640 __mmplayer_create_text_sink_path(player, text_selector);
1643 _mmplayer_set_reconfigure_state(player, FALSE);
1648 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1650 gboolean ret = FALSE;
1651 GstElement *pipeline = NULL;
1652 GstPad *sinkpad = NULL;
1655 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1656 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1658 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1660 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1662 LOGE("failed to get pad from sinkbin");
1668 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1669 LOGE("failed to link sinkbin for reusing");
1670 goto EXIT; /* exit either pass or fail */
1674 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1675 LOGE("failed to set state(READY) to sinkbin");
1680 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1681 LOGE("failed to add sinkbin to pipeline");
1686 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1687 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1692 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1693 LOGE("failed to set state(PAUSED) to sinkbin");
1702 gst_object_unref(GST_OBJECT(sinkpad));
1710 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1712 mmplayer_t *player = NULL;
1713 GstCaps *caps = NULL;
1714 gchar *caps_str = NULL;
1715 GstStructure *str = NULL;
1716 const gchar *name = NULL;
1717 GstElement *sinkbin = NULL;
1718 gboolean reusing = FALSE;
1719 gboolean caps_ret = TRUE;
1720 gchar *sink_pad_name = "sink";
1723 player = (mmplayer_t *)data;
1726 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1727 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1728 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1730 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1734 gst_caps_unref(caps);
1735 caps = gst_caps_ref(ref_caps);
1738 caps_str = gst_caps_to_string(caps);
1740 LOGD("detected mimetype : %s", name);
1742 if (strstr(name, "audio")) {
1743 if (player->pipeline->audiobin == NULL) {
1744 const gchar *audio_format = gst_structure_get_string(str, "format");
1746 LOGD("original audio format %s", audio_format);
1747 mm_player_set_attribute((MMHandleType)player, NULL,
1748 "content_audio_format", audio_format, strlen(audio_format), NULL);
1751 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1752 LOGE("failed to create audiobin. continuing without audio");
1756 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1757 LOGD("creating audiobin success");
1760 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1761 LOGD("reusing audiobin");
1762 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1764 } else if (strstr(name, "video")) {
1765 /* 1. zero copy is updated at _decode_pad_added()
1766 * 2. NULL surface type is handled in _decode_pad_added() */
1767 LOGD("zero copy %d", player->set_mode.video_zc);
1768 if (player->pipeline->videobin == NULL) {
1769 int surface_type = 0;
1770 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1771 LOGD("display_surface_type (%d)", surface_type);
1773 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1774 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1775 LOGE("failed to acquire video overlay resource");
1779 player->interrupted_by_resource = FALSE;
1781 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1782 LOGE("failed to create videobin. continuing without video");
1786 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1787 LOGD("creating videosink bin success");
1790 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1791 LOGD("re-using videobin");
1792 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1794 } else if (strstr(name, "text")) {
1795 if (player->pipeline->textbin == NULL) {
1796 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1797 LOGE("failed to create text sink bin. continuing without text");
1801 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1802 player->textsink_linked = 1;
1803 LOGD("creating textsink bin success");
1805 if (!player->textsink_linked) {
1806 LOGD("re-using textbin");
1808 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1809 player->textsink_linked = 1;
1811 /* linked textbin exist which means that the external subtitle path exist already */
1812 LOGW("ignoring internal subtitle since external subtitle is available");
1815 sink_pad_name = "text_sink";
1817 LOGW("unknown mime type %s, ignoring it", name);
1821 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1824 LOGD("[handle: %p] success to create and link sink bin", player);
1826 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1827 * streaming task. if the task blocked, then buffer will not flow to the next element
1828 *(autoplugging element). so this is special hack for streaming. please try to remove it
1830 /* dec stream count. we can remove fakesink if it's zero */
1831 if (player->num_dynamic_pad)
1832 player->num_dynamic_pad--;
1834 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1836 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1837 _mmplayer_pipeline_complete(NULL, player);
1841 MMPLAYER_FREEIF(caps_str);
1844 gst_caps_unref(caps);
1850 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1852 int required_angle = 0; /* Angle required for straight view */
1853 int rotation_angle = 0;
1855 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1856 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1858 /* Counter clockwise */
1859 switch (orientation) {
1864 required_angle = 270;
1867 required_angle = 180;
1870 required_angle = 90;
1874 rotation_angle = display_angle + required_angle;
1875 if (rotation_angle >= 360)
1876 rotation_angle -= 360;
1878 /* check if supported or not */
1879 if (rotation_angle % 90) {
1880 LOGD("not supported rotation angle = %d", rotation_angle);
1884 switch (rotation_angle) {
1886 *value = MM_DISPLAY_ROTATION_NONE;
1889 *value = MM_DISPLAY_ROTATION_90;
1892 *value = MM_DISPLAY_ROTATION_180;
1895 *value = MM_DISPLAY_ROTATION_270;
1899 LOGD("setting rotation property value : %d", *value);
1905 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1907 int display_rotation = 0;
1908 gchar *org_orient = NULL;
1909 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1912 LOGE("cannot get content attribute");
1913 return MM_ERROR_PLAYER_INTERNAL;
1916 if (display_angle) {
1917 /* update user rotation */
1918 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1920 /* Counter clockwise */
1921 switch (display_rotation) {
1922 case MM_DISPLAY_ROTATION_NONE:
1925 case MM_DISPLAY_ROTATION_90:
1926 *display_angle = 90;
1928 case MM_DISPLAY_ROTATION_180:
1929 *display_angle = 180;
1931 case MM_DISPLAY_ROTATION_270:
1932 *display_angle = 270;
1935 LOGW("wrong angle type : %d", display_rotation);
1938 LOGD("check user angle: %d", *display_angle);
1942 /* Counter clockwise */
1943 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1946 if (!strcmp(org_orient, "rotate-90"))
1948 else if (!strcmp(org_orient, "rotate-180"))
1950 else if (!strcmp(org_orient, "rotate-270"))
1953 LOGD("original rotation is %s", org_orient);
1955 LOGD("content_video_orientation get fail");
1958 LOGD("check orientation: %d", *orientation);
1961 return MM_ERROR_NONE;
1964 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1966 int rotation_value = 0;
1967 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1968 int display_angle = 0;
1971 /* check video sinkbin is created */
1972 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1975 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1977 /* get rotation value to set */
1978 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1979 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1980 LOGD("set video param : rotate %d", rotation_value);
1983 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1985 MMHandleType attrs = 0;
1989 /* check video sinkbin is created */
1990 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1993 attrs = MMPLAYER_GET_ATTRS(player);
1994 MMPLAYER_RETURN_IF_FAIL(attrs);
1996 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1997 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1998 LOGD("set video param : visible %d", visible);
2001 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2003 MMHandleType attrs = 0;
2004 int display_method = 0;
2007 /* check video sinkbin is created */
2008 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2011 attrs = MMPLAYER_GET_ATTRS(player);
2012 MMPLAYER_RETURN_IF_FAIL(attrs);
2014 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2015 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2016 LOGD("set video param : method %d", display_method);
2019 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2021 MMHandleType attrs = 0;
2025 /* check video sinkbin is created */
2026 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2029 attrs = MMPLAYER_GET_ATTRS(player);
2030 MMPLAYER_RETURN_IF_FAIL(attrs);
2032 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2033 MMPLAYER_RETURN_IF_FAIL(handle);
2035 gst_video_overlay_set_video_roi_area(
2036 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2037 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2038 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2039 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2042 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2044 MMHandleType attrs = 0;
2049 int win_roi_width = 0;
2050 int win_roi_height = 0;
2053 /* check video sinkbin is created */
2054 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2057 attrs = MMPLAYER_GET_ATTRS(player);
2058 MMPLAYER_RETURN_IF_FAIL(attrs);
2060 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2061 MMPLAYER_RETURN_IF_FAIL(handle);
2063 /* It should be set after setting window */
2064 mm_attrs_multiple_get(attrs, NULL,
2065 "display_win_roi_x", &win_roi_x,
2066 "display_win_roi_y", &win_roi_y,
2067 "display_win_roi_width", &win_roi_width,
2068 "display_win_roi_height", &win_roi_height, NULL);
2070 /* After setting window handle, set display roi area */
2071 gst_video_overlay_set_display_roi_area(
2072 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2073 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2074 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2075 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2078 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2080 MMHandleType attrs = 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 /* common case if using overlay surface */
2091 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2092 MMPLAYER_RETURN_IF_FAIL(handle);
2094 /* default is using wl_surface_id */
2095 LOGD("set video param : wl_surface_id %d", handle);
2096 gst_video_overlay_set_wl_window_wl_surface_id(
2097 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2102 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2104 gboolean update_all_param = FALSE;
2108 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2109 LOGW("videosink is not ready yet");
2110 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2113 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2114 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2115 return MM_ERROR_PLAYER_INTERNAL;
2118 LOGD("param_name : %s", param_name);
2119 if (!g_strcmp0(param_name, "update_all_param"))
2120 update_all_param = TRUE;
2122 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2123 __mmplayer_video_param_set_display_overlay(player);
2124 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2125 __mmplayer_video_param_set_display_method(player);
2126 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2127 __mmplayer_video_param_set_display_visible(player);
2128 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2129 __mmplayer_video_param_set_display_rotation(player);
2130 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2131 __mmplayer_video_param_set_roi_area(player);
2132 if (update_all_param)
2133 __mmplayer_video_param_set_video_roi_area(player);
2137 return MM_ERROR_NONE;
2140 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2142 gboolean disable_overlay = FALSE;
2145 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2146 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2147 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2149 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2150 LOGW("Display control is not supported");
2151 return MM_ERROR_PLAYER_INTERNAL;
2154 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2156 if (disable == (bool)disable_overlay) {
2157 LOGE("It's the same with current setting: (%d)", disable);
2158 return MM_ERROR_NONE;
2162 LOGE("disable overlay");
2163 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2165 /* release overlay resource */
2166 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2167 LOGE("failed to release overlay resource");
2168 return MM_ERROR_PLAYER_INTERNAL;
2171 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2172 LOGE("failed to acquire video overlay resource");
2173 return MM_ERROR_PLAYER_INTERNAL;
2175 player->interrupted_by_resource = FALSE;
2177 LOGD("enable overlay");
2178 __mmplayer_video_param_set_display_overlay(player);
2179 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2183 return MM_ERROR_NONE;
2187 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2189 int ret = MM_ERROR_NONE;
2190 mmplayer_t *player = (mmplayer_t *)hplayer;
2193 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2195 if (MMPLAYER_USE_DECODEBIN(player)) {
2196 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2201 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2202 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2203 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2205 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2207 /* release decoder resource */
2208 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2209 LOGE("failed to release video decoder resources");
2210 return MM_ERROR_PLAYER_INTERNAL;
2212 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2214 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2218 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2225 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2227 GList *bucket = element_bucket;
2228 mmplayer_gst_element_t *element = NULL;
2229 mmplayer_gst_element_t *prv_element = NULL;
2230 GstElement *tee_element = NULL;
2231 gint successful_link_count = 0;
2235 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2237 prv_element = (mmplayer_gst_element_t *)bucket->data;
2238 bucket = bucket->next;
2240 for (; bucket; bucket = bucket->next) {
2241 element = (mmplayer_gst_element_t *)bucket->data;
2243 if (element && element->gst) {
2244 if (prv_element && prv_element->gst) {
2245 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2247 prv_element->gst = tee_element;
2249 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2250 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2251 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2255 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2256 LOGD("linking [%s] to [%s] success",
2257 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2258 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2259 successful_link_count++;
2260 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2261 LOGD("keep audio-tee element for next audio pipeline branch");
2262 tee_element = prv_element->gst;
2265 LOGD("linking [%s] to [%s] failed",
2266 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2267 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2273 prv_element = element;
2278 return successful_link_count;
2282 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2284 GList *bucket = element_bucket;
2285 mmplayer_gst_element_t *element = NULL;
2286 int successful_add_count = 0;
2290 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2291 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2293 for (; bucket; bucket = bucket->next) {
2294 element = (mmplayer_gst_element_t *)bucket->data;
2296 if (element && element->gst) {
2297 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2298 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2299 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2300 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2303 successful_add_count++;
2309 return successful_add_count;
2313 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2315 mmplayer_t *player = (mmplayer_t *)data;
2316 GstCaps *caps = NULL;
2317 GstStructure *str = NULL;
2319 gboolean caps_ret = TRUE;
2323 MMPLAYER_RETURN_IF_FAIL(pad);
2324 MMPLAYER_RETURN_IF_FAIL(unused);
2325 MMPLAYER_RETURN_IF_FAIL(data);
2327 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2331 LOGD("name = %s", name);
2333 if (strstr(name, "audio")) {
2334 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2336 if (player->audio_stream_changed_cb) {
2337 LOGE("call the audio stream changed cb");
2338 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2340 } else if (strstr(name, "video")) {
2341 if ((name = gst_structure_get_string(str, "format")))
2342 player->set_mode.video_zc = name[0] == 'S';
2344 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2345 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2347 LOGW("invalid caps info");
2352 gst_caps_unref(caps);
2360 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2365 MMPLAYER_RETURN_IF_FAIL(player);
2367 if (player->audio_stream_buff_list) {
2368 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2369 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2372 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2373 __mmplayer_audio_stream_send_data(player, tmp);
2375 MMPLAYER_FREEIF(tmp->pcm_data);
2376 MMPLAYER_FREEIF(tmp);
2379 g_list_free(player->audio_stream_buff_list);
2380 player->audio_stream_buff_list = NULL;
2387 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2389 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2392 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2394 audio_stream.bitrate = a_buffer->bitrate;
2395 audio_stream.channel = a_buffer->channel;
2396 audio_stream.channel_mask = a_buffer->channel_mask;
2397 audio_stream.data_size = a_buffer->data_size;
2398 audio_stream.data = a_buffer->pcm_data;
2399 audio_stream.pcm_format = a_buffer->pcm_format;
2401 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2403 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2409 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2411 mmplayer_t *player = (mmplayer_t *)data;
2412 const gchar *pcm_format = NULL;
2415 guint64 channel_mask = 0;
2416 void *a_data = NULL;
2418 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2419 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2423 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2425 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2426 a_data = mapinfo.data;
2427 a_size = mapinfo.size;
2429 GstCaps *caps = gst_pad_get_current_caps(pad);
2430 GstStructure *structure = gst_caps_get_structure(caps, 0);
2432 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2434 pcm_format = gst_structure_get_string(structure, "format");
2435 gst_structure_get_int(structure, "rate", &rate);
2436 gst_structure_get_int(structure, "channels", &channel);
2437 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2438 gst_caps_unref(GST_CAPS(caps));
2440 /* In case of the sync is false, use buffer list. *
2441 * The num of buffer list depends on the num of audio channels */
2442 if (player->audio_stream_buff_list) {
2443 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2444 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2446 if (channel_mask == tmp->channel_mask) {
2448 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2450 if (tmp->data_size + a_size < tmp->buff_size) {
2451 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2452 tmp->data_size += a_size;
2454 /* send data to client */
2455 __mmplayer_audio_stream_send_data(player, tmp);
2457 if (a_size > tmp->buff_size) {
2458 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2459 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2460 if (tmp->pcm_data == NULL) {
2461 LOGE("failed to realloc data.");
2464 tmp->buff_size = a_size;
2466 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2467 memcpy(tmp->pcm_data, a_data, a_size);
2468 tmp->data_size = a_size;
2473 LOGE("data is empty in list.");
2479 /* create new audio stream data for newly found audio channel */
2480 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2481 if (a_buffer == NULL) {
2482 LOGE("failed to alloc data.");
2485 a_buffer->bitrate = rate;
2486 a_buffer->channel = channel;
2487 a_buffer->channel_mask = channel_mask;
2488 a_buffer->data_size = a_size;
2489 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2491 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2492 /* If sync is FALSE, use buffer list to reduce the IPC. */
2493 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2494 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2495 if (a_buffer->pcm_data == NULL) {
2496 LOGE("failed to alloc data.");
2497 MMPLAYER_FREEIF(a_buffer);
2500 memcpy(a_buffer->pcm_data, a_data, a_size);
2502 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2504 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2506 /* If sync is TRUE, send data directly. */
2507 a_buffer->pcm_data = a_data;
2508 __mmplayer_audio_stream_send_data(player, a_buffer);
2509 MMPLAYER_FREEIF(a_buffer);
2513 gst_buffer_unmap(buffer, &mapinfo);
2518 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2520 mmplayer_t *player = (mmplayer_t *)data;
2521 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2522 GstPad *sinkpad = NULL;
2523 GstElement *queue = NULL, *sink = NULL;
2526 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2528 queue = gst_element_factory_make("queue", NULL);
2529 if (queue == NULL) {
2530 LOGD("fail make queue");
2534 sink = gst_element_factory_make("fakesink", NULL);
2536 LOGD("fail make fakesink");
2540 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2542 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2543 LOGW("failed to link queue & sink");
2547 sinkpad = gst_element_get_static_pad(queue, "sink");
2549 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2550 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2554 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2556 gst_object_unref(sinkpad);
2557 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2558 g_object_set(sink, "sync", TRUE, NULL);
2559 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2561 /* keep the first sink reference only */
2562 if (!audiobin[MMPLAYER_A_SINK].gst) {
2563 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2564 audiobin[MMPLAYER_A_SINK].gst = sink;
2568 _mmplayer_add_signal_connection(player,
2570 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2572 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2575 __mmplayer_add_sink(player, sink, FALSE);
2577 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2578 LOGE("failed to sync state");
2582 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2583 LOGE("failed to sync state");
2591 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2593 gst_object_unref(GST_OBJECT(queue));
2597 gst_object_unref(GST_OBJECT(sink));
2601 gst_object_unref(GST_OBJECT(sinkpad));
2609 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2611 mmplayer_t *player = (mmplayer_t *)data;
2614 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2616 player->no_more_pad = TRUE;
2617 _mmplayer_pipeline_complete(NULL, player);
2624 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2626 #define MAX_PROPS_LEN 128
2627 mmplayer_gst_element_t *audiobin = NULL;
2628 gint latency_mode = 0;
2629 gchar *stream_type = NULL;
2630 gchar *latency = NULL;
2632 gchar stream_props[MAX_PROPS_LEN] = {0,};
2633 GstStructure *props = NULL;
2636 * It should be set after player creation through attribute.
2637 * But, it can not be changed during playing.
2640 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2642 audiobin = player->pipeline->audiobin;
2644 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2645 if (player->sound.mute) {
2646 LOGD("mute enabled");
2647 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2650 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2651 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2654 snprintf(stream_props, sizeof(stream_props) - 1,
2655 "props,application.process.id.origin=%d", player->client_pid);
2657 snprintf(stream_props, sizeof(stream_props) - 1,
2658 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2659 stream_type, stream_id, player->client_pid);
2661 props = gst_structure_from_string(stream_props, NULL);
2662 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2663 LOGI("props result[%s].", stream_props);
2664 gst_structure_free(props);
2666 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2668 switch (latency_mode) {
2669 case AUDIO_LATENCY_MODE_LOW:
2670 latency = g_strdup("low");
2672 case AUDIO_LATENCY_MODE_MID:
2673 latency = g_strdup("mid");
2675 case AUDIO_LATENCY_MODE_HIGH:
2676 latency = g_strdup("high");
2679 latency = g_strdup("mid");
2683 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2685 LOGD("audiosink property - latency=%s", latency);
2687 MMPLAYER_FREEIF(latency);
2693 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2695 mmplayer_gst_element_t *audiobin = NULL;
2698 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2699 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2701 audiobin = player->pipeline->audiobin;
2703 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2704 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2705 LOGE("failed to create media stream info");
2706 return MM_ERROR_PLAYER_INTERNAL;
2709 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2711 if (player->video360_yaw_radians <= M_PI &&
2712 player->video360_yaw_radians >= -M_PI &&
2713 player->video360_pitch_radians <= M_PI_2 &&
2714 player->video360_pitch_radians >= -M_PI_2) {
2715 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2716 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2717 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2718 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2719 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2720 "source-orientation-y", player->video360_metadata.init_view_heading,
2721 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2725 return MM_ERROR_NONE;
2729 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2731 mmplayer_gst_element_t *audiobin = NULL;
2732 GstPad *sink_pad = NULL;
2733 GstCaps *acaps = NULL;
2735 int pitch_control = 0;
2736 double pitch_value = 1.0;
2739 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2740 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2742 audiobin = player->pipeline->audiobin;
2744 LOGD("make element for normal audio playback");
2746 /* audio bin structure for playback. {} means optional.
2747 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2749 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2750 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2753 /* for pitch control */
2754 mm_attrs_multiple_get(player->attrs, NULL,
2755 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2756 MM_PLAYER_PITCH_VALUE, &pitch_value,
2759 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2760 if (pitch_control && (player->videodec_linked == 0)) {
2761 GstElementFactory *factory;
2763 factory = gst_element_factory_find("pitch");
2765 gst_object_unref(factory);
2768 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2771 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2772 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2774 LOGW("there is no pitch element");
2779 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2781 /* replaygain volume */
2782 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2783 if (player->sound.rg_enable)
2784 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2786 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2789 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2791 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2792 /* currently, only openalsink uses volume element */
2793 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2794 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2796 if (player->sound.mute) {
2797 LOGD("mute enabled");
2798 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2802 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2804 /* audio effect element. if audio effect is enabled */
2805 if ((strcmp(player->ini.audioeffect_element, ""))
2807 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2808 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2810 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2812 if ((!player->bypass_audio_effect)
2813 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2814 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2815 if (!_mmplayer_audio_effect_custom_apply(player))
2816 LOGI("apply audio effect(custom) setting success");
2820 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2821 && (player->set_mode.rich_audio)) {
2822 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2826 /* create audio sink */
2827 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2828 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2829 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2831 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2832 if (player->is_360_feature_enabled &&
2833 player->is_content_spherical &&
2835 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2836 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2837 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2839 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2841 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2843 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2844 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2845 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2846 gst_caps_unref(acaps);
2848 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2850 player->is_openal_plugin_used = TRUE;
2852 if (player->is_360_feature_enabled && player->is_content_spherical)
2853 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2854 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2857 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2858 (player->videodec_linked && player->ini.use_system_clock)) {
2859 LOGD("system clock will be used.");
2860 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2863 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2864 __mmplayer_gst_set_pulsesink_property(player);
2865 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2866 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2871 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2872 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2874 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2875 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2876 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2877 gst_object_unref(GST_OBJECT(sink_pad));
2879 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2882 return MM_ERROR_NONE;
2884 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2886 return MM_ERROR_PLAYER_INTERNAL;
2890 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2892 mmplayer_gst_element_t *audiobin = NULL;
2893 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2895 gchar *dst_format = NULL;
2897 int dst_samplerate = 0;
2898 int dst_channels = 0;
2899 GstCaps *caps = NULL;
2900 char *caps_str = NULL;
2903 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2904 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2906 audiobin = player->pipeline->audiobin;
2908 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2910 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2912 [case 1] extract interleave audio pcm without playback
2913 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2914 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2916 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2918 [case 2] deinterleave for each channel without playback
2919 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2920 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2922 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2923 - fakesink (sync or not)
2926 [case 3] [case 1(sync only)] + playback
2927 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2929 * src - ... - tee - queue1 - playback path
2930 - queue2 - [case1 pipeline with sync]
2932 [case 4] [case 2(sync only)] + playback
2933 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2935 * src - ... - tee - queue1 - playback path
2936 - queue2 - [case2 pipeline with sync]
2940 /* 1. create tee and playback path
2941 'tee' should be added at first to copy the decoded stream
2943 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2944 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2945 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2947 /* tee - path 1 : for playback path */
2948 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2949 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2951 /* tee - path 2 : for extract path */
2952 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2953 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2956 /* if there is tee, 'tee - path 2' is linked here */
2958 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2961 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2963 /* 2. decide the extract pcm format */
2964 mm_attrs_multiple_get(player->attrs, NULL,
2965 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2966 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2967 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2970 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2971 dst_format, dst_len, dst_samplerate, dst_channels);
2973 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2974 mm_attrs_multiple_get(player->attrs, NULL,
2975 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2976 "content_audio_samplerate", &dst_samplerate,
2977 "content_audio_channels", &dst_channels,
2980 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2981 dst_format, dst_len, dst_samplerate, dst_channels);
2983 /* If there is no enough information, set it to platform default value. */
2984 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2985 LOGD("set platform default format");
2986 dst_format = DEFAULT_PCM_OUT_FORMAT;
2988 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2989 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2992 /* 3. create capsfilter */
2993 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2994 caps = gst_caps_new_simple("audio/x-raw",
2995 "format", G_TYPE_STRING, dst_format,
2996 "rate", G_TYPE_INT, dst_samplerate,
2997 "channels", G_TYPE_INT, dst_channels,
3000 caps_str = gst_caps_to_string(caps);
3001 LOGD("new caps : %s", caps_str);
3003 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3006 gst_caps_unref(caps);
3007 MMPLAYER_FREEIF(caps_str);
3009 /* 4-1. create deinterleave to extract pcm for each channel */
3010 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3011 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3012 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3014 /* audiosink will be added after getting signal for each channel */
3015 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3016 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3017 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3018 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3019 player->no_more_pad = FALSE;
3021 /* 4-2. create fakesink to extract interleaved pcm */
3022 LOGD("add audio fakesink for interleaved audio");
3023 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3024 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3025 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3026 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3028 _mmplayer_add_signal_connection(player,
3029 G_OBJECT(audiobin[extract_sink_id].gst),
3030 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3032 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3035 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3039 return MM_ERROR_NONE;
3041 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3043 return MM_ERROR_PLAYER_INTERNAL;
3047 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3049 int ret = MM_ERROR_NONE;
3050 mmplayer_gst_element_t *audiobin = NULL;
3051 GList *element_bucket = NULL;
3054 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3055 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3057 audiobin = player->pipeline->audiobin;
3059 if (player->build_audio_offload) { /* skip all the audio filters */
3060 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3062 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3063 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3064 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3066 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3070 /* FIXME: need to mention the supportable condition at API reference */
3071 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3072 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3074 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3076 if (ret != MM_ERROR_NONE)
3079 LOGD("success to make audio bin element");
3080 *bucket = element_bucket;
3083 return MM_ERROR_NONE;
3086 LOGE("failed to make audio bin element");
3087 g_list_free(element_bucket);
3091 return MM_ERROR_PLAYER_INTERNAL;
3095 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3097 mmplayer_gst_element_t *first_element = NULL;
3098 mmplayer_gst_element_t *audiobin = NULL;
3100 GstPad *ghostpad = NULL;
3101 GList *element_bucket = NULL;
3105 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3108 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3110 LOGE("failed to allocate memory for audiobin");
3111 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3115 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3116 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3117 if (!audiobin[MMPLAYER_A_BIN].gst) {
3118 LOGE("failed to create audiobin");
3123 player->pipeline->audiobin = audiobin;
3125 /* create audio filters and audiosink */
3126 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3129 /* adding created elements to bin */
3130 LOGD("adding created elements to bin");
3131 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3134 /* linking elements in the bucket by added order. */
3135 LOGD("Linking elements in the bucket by added order.");
3136 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3139 /* get first element's sinkpad for creating ghostpad */
3140 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3141 if (!first_element) {
3142 LOGE("failed to get first elem");
3146 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3148 LOGE("failed to get pad from first element of audiobin");
3152 ghostpad = gst_ghost_pad_new("sink", pad);
3154 LOGE("failed to create ghostpad");
3158 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3159 LOGE("failed to add ghostpad to audiobin");
3163 gst_object_unref(pad);
3165 g_list_free(element_bucket);
3168 return MM_ERROR_NONE;
3171 LOGD("ERROR : releasing audiobin");
3174 gst_object_unref(GST_OBJECT(pad));
3177 gst_object_unref(GST_OBJECT(ghostpad));
3180 g_list_free(element_bucket);
3182 /* release element which are not added to bin */
3183 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3184 /* NOTE : skip bin */
3185 if (audiobin[i].gst) {
3186 GstObject *parent = NULL;
3187 parent = gst_element_get_parent(audiobin[i].gst);
3190 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3191 audiobin[i].gst = NULL;
3193 gst_object_unref(GST_OBJECT(parent));
3197 /* release audiobin with it's children */
3198 if (audiobin[MMPLAYER_A_BIN].gst)
3199 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3201 MMPLAYER_FREEIF(audiobin);
3203 player->pipeline->audiobin = NULL;
3205 return MM_ERROR_PLAYER_INTERNAL;
3209 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3211 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3215 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3217 int ret = MM_ERROR_NONE;
3219 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3220 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3222 MMPLAYER_VIDEO_BO_LOCK(player);
3224 if (player->video_bo_list) {
3225 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3226 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3227 if (tmp && tmp->bo == bo) {
3229 LOGD("release bo %p", bo);
3230 tbm_bo_unref(tmp->bo);
3231 MMPLAYER_VIDEO_BO_UNLOCK(player);
3232 MMPLAYER_VIDEO_BO_SIGNAL(player);
3237 /* hw codec is running or the list was reset for DRC. */
3238 LOGW("there is no bo list.");
3240 MMPLAYER_VIDEO_BO_UNLOCK(player);
3242 LOGW("failed to find bo %p", bo);
3246 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3252 tbm_bo_unref(tmp->bo);
3257 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3260 MMPLAYER_RETURN_IF_FAIL(player);
3262 MMPLAYER_VIDEO_BO_LOCK(player);
3263 if (player->video_bo_list) {
3264 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3265 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3266 player->video_bo_list = NULL;
3268 player->video_bo_size = 0;
3269 MMPLAYER_VIDEO_BO_UNLOCK(player);
3276 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3279 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3280 gboolean ret = TRUE;
3282 /* check DRC, if it is, destroy the prev bo list to create again */
3283 if (player->video_bo_size != size) {
3284 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3285 __mmplayer_video_stream_destroy_bo_list(player);
3286 player->video_bo_size = size;
3289 MMPLAYER_VIDEO_BO_LOCK(player);
3291 if ((!player->video_bo_list) ||
3292 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3294 /* create bo list */
3296 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3298 if (player->video_bo_list) {
3299 /* if bo list did not created all, try it again. */
3300 idx = g_list_length(player->video_bo_list);
3301 LOGD("bo list exist(len: %d)", idx);
3304 for (; idx < player->ini.num_of_video_bo; idx++) {
3305 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3307 LOGE("Fail to alloc bo_info.");
3310 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3312 LOGE("Fail to tbm_bo_alloc.");
3313 MMPLAYER_FREEIF(bo_info);
3316 bo_info->used = FALSE;
3317 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3320 /* update video num buffers */
3321 LOGD("video_num_buffers : %d", idx);
3322 mm_player_set_attribute((MMHandleType)player, NULL,
3323 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3324 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3328 MMPLAYER_VIDEO_BO_UNLOCK(player);
3334 /* get bo from list*/
3335 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3336 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3337 if (tmp && (tmp->used == FALSE)) {
3338 LOGD("found bo %p to use", tmp->bo);
3340 MMPLAYER_VIDEO_BO_UNLOCK(player);
3341 return tbm_bo_ref(tmp->bo);
3345 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3346 MMPLAYER_VIDEO_BO_UNLOCK(player);
3350 if (player->ini.video_bo_timeout <= 0) {
3351 MMPLAYER_VIDEO_BO_WAIT(player);
3353 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3354 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3361 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3363 mmplayer_t *player = (mmplayer_t *)data;
3365 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3367 /* send prerolled pkt */
3368 player->video_stream_prerolled = false;
3370 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3372 /* not to send prerolled pkt again */
3373 player->video_stream_prerolled = true;
3377 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3379 mmplayer_t *player = (mmplayer_t *)data;
3380 mmplayer_video_decoded_data_info_t *stream = NULL;
3381 GstMemory *mem = NULL;
3384 MMPLAYER_RETURN_IF_FAIL(player);
3385 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3387 if (player->video_stream_prerolled) {
3388 player->video_stream_prerolled = false;
3389 LOGD("skip the prerolled pkt not to send it again");
3393 /* clear stream data structure */
3394 stream = __mmplayer_create_stream_from_pad(pad);
3396 LOGE("failed to alloc stream");
3400 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3402 /* set size and timestamp */
3403 mem = gst_buffer_peek_memory(buffer, 0);
3404 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3405 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3407 /* check zero-copy */
3408 if (player->set_mode.video_zc &&
3409 player->set_mode.video_export &&
3410 gst_is_tizen_memory(mem)) {
3411 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3412 stream->internal_buffer = gst_buffer_ref(buffer);
3413 } else { /* sw codec */
3414 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3417 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3421 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3422 LOGE("failed to send video decoded data.");
3429 LOGE("release video stream resource.");
3430 if (gst_is_tizen_memory(mem)) {
3432 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3434 tbm_bo_unref(stream->bo[i]);
3437 /* unref gst buffer */
3438 if (stream->internal_buffer)
3439 gst_buffer_unref(stream->internal_buffer);
3442 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3444 MMPLAYER_FREEIF(stream);
3449 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3451 mmplayer_gst_element_t *videobin = NULL;
3454 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3456 videobin = player->pipeline->videobin;
3458 /* Set spatial media metadata and/or user settings to the element.
3460 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3461 "projection-type", player->video360_metadata.projection_type, NULL);
3463 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3464 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3466 if (player->video360_metadata.full_pano_width_pixels &&
3467 player->video360_metadata.full_pano_height_pixels &&
3468 player->video360_metadata.cropped_area_image_width &&
3469 player->video360_metadata.cropped_area_image_height) {
3470 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3471 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3472 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3473 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3474 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3475 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3476 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3480 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3481 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3482 "horizontal-fov", player->video360_horizontal_fov,
3483 "vertical-fov", player->video360_vertical_fov, NULL);
3486 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3487 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3488 "zoom", 1.0f / player->video360_zoom, NULL);
3491 if (player->video360_yaw_radians <= M_PI &&
3492 player->video360_yaw_radians >= -M_PI &&
3493 player->video360_pitch_radians <= M_PI_2 &&
3494 player->video360_pitch_radians >= -M_PI_2) {
3495 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3496 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3497 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3498 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3499 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3500 "pose-yaw", player->video360_metadata.init_view_heading,
3501 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3504 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3505 "passthrough", !player->is_video360_enabled, NULL);
3512 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3514 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3515 GList *element_bucket = NULL;
3518 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3520 /* create video360 filter */
3521 if (player->is_360_feature_enabled && player->is_content_spherical) {
3522 LOGD("create video360 element");
3523 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3524 __mmplayer_gst_set_video360_property(player);
3528 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3529 LOGD("skip creating the videoconv and rotator");
3530 return MM_ERROR_NONE;
3533 /* in case of sw codec & overlay surface type, except 360 playback.
3534 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3535 LOGD("create video converter: %s", video_csc);
3536 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3539 *bucket = element_bucket;
3541 return MM_ERROR_NONE;
3543 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3544 g_list_free(element_bucket);
3548 return MM_ERROR_PLAYER_INTERNAL;
3552 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3554 gchar *factory_name = NULL;
3556 switch (surface_type) {
3557 case MM_DISPLAY_SURFACE_OVERLAY:
3558 if (strlen(player->ini.videosink_element_overlay) > 0)
3559 factory_name = player->ini.videosink_element_overlay;
3561 case MM_DISPLAY_SURFACE_REMOTE:
3562 case MM_DISPLAY_SURFACE_NULL:
3563 if (strlen(player->ini.videosink_element_fake) > 0)
3564 factory_name = player->ini.videosink_element_fake;
3567 LOGE("unidentified surface type");
3571 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3572 return factory_name;
3576 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3578 gchar *factory_name = NULL;
3579 mmplayer_gst_element_t *videobin = NULL;
3584 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3586 videobin = player->pipeline->videobin;
3587 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3589 attrs = MMPLAYER_GET_ATTRS(player);
3591 LOGE("cannot get content attribute");
3592 return MM_ERROR_PLAYER_INTERNAL;
3595 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3596 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3597 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3598 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3599 "use-tbm", use_tbm, NULL);
3602 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3603 return MM_ERROR_PLAYER_INTERNAL;
3605 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3608 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3609 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3612 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3614 LOGD("disable last-sample");
3615 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3618 if (player->set_mode.video_export) {
3620 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3621 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3622 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3624 _mmplayer_add_signal_connection(player,
3625 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3626 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3628 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3631 _mmplayer_add_signal_connection(player,
3632 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3633 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3635 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3639 if (videobin[MMPLAYER_V_SINK].gst) {
3640 GstPad *sink_pad = NULL;
3641 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3643 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3644 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3645 gst_object_unref(GST_OBJECT(sink_pad));
3647 LOGE("failed to get sink pad from videosink");
3651 return MM_ERROR_NONE;
3656 * - video overlay surface(arm/x86) : tizenwlsink
3659 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3662 GList *element_bucket = NULL;
3663 mmplayer_gst_element_t *first_element = NULL;
3664 mmplayer_gst_element_t *videobin = NULL;
3665 gchar *videosink_factory_name = NULL;
3668 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3671 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3673 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3675 player->pipeline->videobin = videobin;
3678 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3679 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3680 if (!videobin[MMPLAYER_V_BIN].gst) {
3681 LOGE("failed to create videobin");
3685 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3688 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3689 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3691 /* additional setting for sink plug-in */
3692 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3693 LOGE("failed to set video property");
3697 /* store it as it's sink element */
3698 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3700 /* adding created elements to bin */
3701 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3702 LOGE("failed to add elements");
3706 /* Linking elements in the bucket by added order */
3707 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3708 LOGE("failed to link elements");
3712 /* get first element's sinkpad for creating ghostpad */
3713 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3714 if (!first_element) {
3715 LOGE("failed to get first element from bucket");
3719 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3721 LOGE("failed to get pad from first element");
3725 /* create ghostpad */
3726 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3727 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3728 LOGE("failed to add ghostpad to videobin");
3731 gst_object_unref(pad);
3733 /* done. free allocated variables */
3734 g_list_free(element_bucket);
3738 return MM_ERROR_NONE;
3741 LOGE("ERROR : releasing videobin");
3742 g_list_free(element_bucket);
3745 gst_object_unref(GST_OBJECT(pad));
3747 /* release videobin with it's children */
3748 if (videobin[MMPLAYER_V_BIN].gst)
3749 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3751 MMPLAYER_FREEIF(videobin);
3752 player->pipeline->videobin = NULL;
3754 return MM_ERROR_PLAYER_INTERNAL;
3758 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3760 GList *element_bucket = NULL;
3761 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3763 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3764 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3765 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3766 "signal-handoffs", FALSE,
3769 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3770 _mmplayer_add_signal_connection(player,
3771 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3772 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3774 G_CALLBACK(__mmplayer_update_subtitle),
3777 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3778 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3780 if (!player->play_subtitle) {
3781 LOGD("add textbin sink as sink element of whole pipeline.");
3782 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3785 /* adding created elements to bin */
3786 LOGD("adding created elements to bin");
3787 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3788 LOGE("failed to add elements");
3789 g_list_free(element_bucket);
3793 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3794 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3795 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3797 /* linking elements in the bucket by added order. */
3798 LOGD("Linking elements in the bucket by added order.");
3799 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3800 LOGE("failed to link elements");
3801 g_list_free(element_bucket);
3805 /* done. free allocated variables */
3806 g_list_free(element_bucket);
3808 if (textbin[MMPLAYER_T_QUEUE].gst) {
3810 GstPad *ghostpad = NULL;
3812 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3814 LOGE("failed to get sink pad of text queue");
3818 ghostpad = gst_ghost_pad_new("text_sink", pad);
3819 gst_object_unref(pad);
3822 LOGE("failed to create ghostpad of textbin");
3826 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3827 LOGE("failed to add ghostpad to textbin");
3828 gst_object_unref(ghostpad);
3833 return MM_ERROR_NONE;
3837 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3838 LOGE("remove textbin sink from sink list");
3839 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3842 /* release element at __mmplayer_gst_create_text_sink_bin */
3843 return MM_ERROR_PLAYER_INTERNAL;
3847 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3849 mmplayer_gst_element_t *textbin = NULL;
3850 GList *element_bucket = NULL;
3851 int surface_type = 0;
3856 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3859 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3861 LOGE("failed to allocate memory for textbin");
3862 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3866 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3867 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3868 if (!textbin[MMPLAYER_T_BIN].gst) {
3869 LOGE("failed to create textbin");
3874 player->pipeline->textbin = textbin;
3877 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3878 LOGD("surface type for subtitle : %d", surface_type);
3879 switch (surface_type) {
3880 case MM_DISPLAY_SURFACE_OVERLAY:
3881 case MM_DISPLAY_SURFACE_NULL:
3882 case MM_DISPLAY_SURFACE_REMOTE:
3883 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3884 LOGE("failed to make plain text elements");
3895 return MM_ERROR_NONE;
3899 LOGD("ERROR : releasing textbin");
3901 g_list_free(element_bucket);
3903 /* release signal */
3904 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3906 /* release element which are not added to bin */
3907 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3908 /* NOTE : skip bin */
3909 if (textbin[i].gst) {
3910 GstObject *parent = NULL;
3911 parent = gst_element_get_parent(textbin[i].gst);
3914 gst_object_unref(GST_OBJECT(textbin[i].gst));
3915 textbin[i].gst = NULL;
3917 gst_object_unref(GST_OBJECT(parent));
3922 /* release textbin with it's children */
3923 if (textbin[MMPLAYER_T_BIN].gst)
3924 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3926 MMPLAYER_FREEIF(textbin);
3927 player->pipeline->textbin = NULL;
3930 return MM_ERROR_PLAYER_INTERNAL;
3934 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3936 mmplayer_gst_element_t *mainbin = NULL;
3937 mmplayer_gst_element_t *textbin = NULL;
3938 MMHandleType attrs = 0;
3939 GstElement *subsrc = NULL;
3940 GstElement *subparse = NULL;
3941 gchar *subtitle_uri = NULL;
3942 const gchar *charset = NULL;
3948 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3950 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3952 mainbin = player->pipeline->mainbin;
3954 attrs = MMPLAYER_GET_ATTRS(player);
3956 LOGE("cannot get content attribute");
3957 return MM_ERROR_PLAYER_INTERNAL;
3960 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3961 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3962 LOGE("subtitle uri is not proper filepath.");
3963 return MM_ERROR_PLAYER_INVALID_URI;
3966 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3967 LOGE("failed to get storage info of subtitle path");
3968 return MM_ERROR_PLAYER_INVALID_URI;
3971 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3973 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3974 player->subtitle_language_list = NULL;
3975 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3977 /* create the subtitle source */
3978 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3980 LOGE("failed to create filesrc element");
3983 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3985 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3986 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3988 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3989 LOGW("failed to add queue");
3990 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3991 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3992 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3997 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3999 LOGE("failed to create subparse element");
4003 charset = _mmplayer_get_charset(subtitle_uri);
4005 LOGD("detected charset is %s", charset);
4006 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4009 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4010 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4012 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4013 LOGW("failed to add subparse");
4014 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4015 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4016 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4020 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4021 LOGW("failed to link subsrc and subparse");
4025 player->play_subtitle = TRUE;
4026 player->adjust_subtitle_pos = 0;
4028 LOGD("play subtitle using subtitle file");
4030 if (player->pipeline->textbin == NULL) {
4031 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4032 LOGE("failed to create text sink bin. continuing without text");
4036 textbin = player->pipeline->textbin;
4038 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4039 LOGW("failed to add textbin");
4041 /* release signal */
4042 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4044 /* release textbin with it's children */
4045 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4046 MMPLAYER_FREEIF(player->pipeline->textbin);
4047 player->pipeline->textbin = textbin = NULL;
4051 LOGD("link text input selector and textbin ghost pad");
4053 player->textsink_linked = 1;
4054 player->external_text_idx = 0;
4055 LOGI("textsink is linked");
4057 textbin = player->pipeline->textbin;
4058 LOGD("text bin has been created. reuse it.");
4059 player->external_text_idx = 1;
4062 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4063 LOGW("failed to link subparse and textbin");
4067 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4069 LOGE("failed to get sink pad from textsink to probe data");
4073 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4074 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4076 gst_object_unref(pad);
4079 /* create dot. for debugging */
4080 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4083 return MM_ERROR_NONE;
4086 /* release text pipeline resource */
4087 player->textsink_linked = 0;
4089 /* release signal */
4090 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4092 if (player->pipeline->textbin) {
4093 LOGE("remove textbin");
4095 /* release textbin with it's children */
4096 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4097 MMPLAYER_FREEIF(player->pipeline->textbin);
4098 player->pipeline->textbin = NULL;
4102 /* release subtitle elem */
4103 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4104 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4106 return MM_ERROR_PLAYER_INTERNAL;
4110 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4112 mmplayer_t *player = (mmplayer_t *)data;
4113 MMMessageParamType msg = {0, };
4114 GstClockTime duration = 0;
4115 gpointer text = NULL;
4116 guint text_size = 0;
4117 gboolean ret = TRUE;
4118 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4122 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4123 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4125 if (player->is_subtitle_force_drop) {
4126 LOGW("subtitle is dropped forcedly.");
4130 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4131 text = mapinfo.data;
4132 text_size = mapinfo.size;
4134 if (player->set_mode.subtitle_off) {
4135 LOGD("subtitle is OFF.");
4139 if (!text || (text_size == 0)) {
4140 LOGD("There is no subtitle to be displayed.");
4144 msg.data = (void *)text;
4146 duration = GST_BUFFER_DURATION(buffer);
4148 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4149 if (player->duration > GST_BUFFER_PTS(buffer))
4150 duration = player->duration - GST_BUFFER_PTS(buffer);
4153 LOGI("subtitle duration is invalid, subtitle duration change "
4154 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4156 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4158 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4160 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4161 gst_buffer_unmap(buffer, &mapinfo);
4168 static GstPadProbeReturn
4169 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4171 mmplayer_t *player = (mmplayer_t *)u_data;
4172 GstClockTime cur_timestamp = 0;
4173 gint64 adjusted_timestamp = 0;
4174 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4176 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4178 if (player->set_mode.subtitle_off) {
4179 LOGD("subtitle is OFF.");
4183 if (player->adjust_subtitle_pos == 0) {
4184 LOGD("nothing to do");
4188 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4189 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4191 if (adjusted_timestamp < 0) {
4192 LOGD("adjusted_timestamp under zero");
4197 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4198 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4199 GST_TIME_ARGS(cur_timestamp),
4200 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4202 return GST_PAD_PROBE_OK;
4206 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4210 /* check player and subtitlebin are created */
4211 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4212 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4214 if (position == 0) {
4215 LOGD("nothing to do");
4217 return MM_ERROR_NONE;
4220 /* check current position */
4221 player->adjust_subtitle_pos = position;
4223 LOGD("save adjust_subtitle_pos in player");
4227 return MM_ERROR_NONE;
4231 * This function is to create audio or video pipeline for playing.
4233 * @param player [in] handle of player
4235 * @return This function returns zero on success.
4240 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4242 int ret = MM_ERROR_NONE;
4243 mmplayer_gst_element_t *mainbin = NULL;
4244 MMHandleType attrs = 0;
4247 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4249 /* get profile attribute */
4250 attrs = MMPLAYER_GET_ATTRS(player);
4252 LOGE("failed to get content attribute");
4256 /* create pipeline handles */
4257 if (player->pipeline) {
4258 LOGE("pipeline should be released before create new one");
4262 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4264 /* create mainbin */
4265 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4266 if (mainbin == NULL)
4269 /* create pipeline */
4270 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4271 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4272 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4273 LOGE("failed to create pipeline");
4278 player->pipeline->mainbin = mainbin;
4280 /* create the source and decoder elements */
4281 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4282 ret = _mmplayer_gst_build_es_pipeline(player);
4284 if (MMPLAYER_USE_DECODEBIN(player))
4285 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4287 ret = _mmplayer_gst_build_pipeline_with_src(player);
4290 if (ret != MM_ERROR_NONE) {
4291 LOGE("failed to create some elements");
4295 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4296 if (__mmplayer_check_subtitle(player)
4297 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4298 LOGE("failed to create text pipeline");
4301 ret = _mmplayer_gst_add_bus_watch(player);
4302 if (ret != MM_ERROR_NONE) {
4303 LOGE("failed to add bus watch");
4308 return MM_ERROR_NONE;
4311 _mmplayer_bus_watcher_remove(player);
4312 __mmplayer_gst_destroy_pipeline(player);
4313 return MM_ERROR_PLAYER_INTERNAL;
4317 __mmplayer_reset_gapless_state(mmplayer_t *player)
4320 MMPLAYER_RETURN_IF_FAIL(player
4322 && player->pipeline->audiobin
4323 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4325 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4332 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4335 int ret = MM_ERROR_NONE;
4339 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4341 /* cleanup stuffs */
4342 MMPLAYER_FREEIF(player->type);
4343 player->no_more_pad = FALSE;
4344 player->num_dynamic_pad = 0;
4346 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4347 player->subtitle_language_list = NULL;
4348 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4350 MMPLAYER_RECONFIGURE_LOCK(player);
4351 __mmplayer_reset_gapless_state(player);
4352 MMPLAYER_RECONFIGURE_UNLOCK(player);
4354 if (player->streamer) {
4355 _mm_player_streaming_initialize(player->streamer, FALSE);
4356 _mm_player_streaming_destroy(player->streamer);
4357 player->streamer = NULL;
4360 /* cleanup unlinked mime type */
4361 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4362 MMPLAYER_FREEIF(player->unlinked_video_mime);
4363 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4365 /* cleanup running stuffs */
4366 _mmplayer_cancel_eos_timer(player);
4368 /* cleanup gst stuffs */
4369 if (player->pipeline) {
4370 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4371 GstTagList *tag_list = player->pipeline->tag_list;
4373 /* first we need to disconnect all signal hander */
4374 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4377 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4378 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4379 gst_object_unref(bus);
4381 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4382 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4383 if (ret != MM_ERROR_NONE) {
4384 LOGE("fail to change state to NULL");
4385 return MM_ERROR_PLAYER_INTERNAL;
4388 LOGW("succeeded in changing state to NULL");
4390 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4393 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4394 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4396 MMPLAYER_FREEIF(player->pipeline->audiobin);
4397 MMPLAYER_FREEIF(player->pipeline->videobin);
4398 MMPLAYER_FREEIF(player->pipeline->textbin);
4399 MMPLAYER_FREEIF(mainbin);
4403 gst_tag_list_unref(tag_list);
4405 MMPLAYER_FREEIF(player->pipeline);
4407 MMPLAYER_FREEIF(player->album_art);
4409 if (player->type_caps) {
4410 gst_caps_unref(player->type_caps);
4411 player->type_caps = NULL;
4414 if (player->v_stream_caps) {
4415 gst_caps_unref(player->v_stream_caps);
4416 player->v_stream_caps = NULL;
4419 if (player->a_stream_caps) {
4420 gst_caps_unref(player->a_stream_caps);
4421 player->a_stream_caps = NULL;
4424 if (player->s_stream_caps) {
4425 gst_caps_unref(player->s_stream_caps);
4426 player->s_stream_caps = NULL;
4428 _mmplayer_track_destroy(player);
4430 if (player->sink_elements)
4431 g_list_free(player->sink_elements);
4432 player->sink_elements = NULL;
4434 if (player->bufmgr) {
4435 tbm_bufmgr_deinit(player->bufmgr);
4436 player->bufmgr = NULL;
4439 LOGW("finished destroy pipeline");
4447 __mmplayer_gst_realize(mmplayer_t *player)
4450 int ret = MM_ERROR_NONE;
4454 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4456 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4458 ret = __mmplayer_gst_create_pipeline(player);
4460 LOGE("failed to create pipeline");
4464 /* set pipeline state to READY */
4465 /* NOTE : state change to READY must be performed sync. */
4466 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4467 ret = _mmplayer_gst_set_state(player,
4468 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4470 if (ret != MM_ERROR_NONE) {
4471 /* return error if failed to set state */
4472 LOGE("failed to set READY state");
4476 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4478 /* create dot before error-return. for debugging */
4479 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4487 __mmplayer_gst_unrealize(mmplayer_t *player)
4489 int ret = MM_ERROR_NONE;
4493 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4495 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4496 MMPLAYER_PRINT_STATE(player);
4498 /* release miscellaneous information */
4499 __mmplayer_release_misc(player);
4501 /* destroy pipeline */
4502 ret = __mmplayer_gst_destroy_pipeline(player);
4503 if (ret != MM_ERROR_NONE) {
4504 LOGE("failed to destroy pipeline");
4508 /* release miscellaneous information.
4509 these info needs to be released after pipeline is destroyed. */
4510 __mmplayer_release_misc_post(player);
4512 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4520 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4525 LOGW("set_message_callback is called with invalid player handle");
4526 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4529 player->msg_cb = callback;
4530 player->msg_cb_param = user_param;
4532 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4536 return MM_ERROR_NONE;
4540 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4542 int ret = MM_ERROR_NONE;
4547 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4548 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4549 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4551 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4553 if (strstr(uri, "es_buff://")) {
4554 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4555 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4556 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4557 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4559 tmp = g_ascii_strdown(uri, strlen(uri));
4560 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4561 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4563 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4565 } else if (strstr(uri, "mms://")) {
4566 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4567 } else if ((path = strstr(uri, "mem://"))) {
4568 ret = __mmplayer_set_mem_uri(data, path, param);
4570 ret = __mmplayer_set_file_uri(data, uri);
4573 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4574 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4575 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4576 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4578 /* dump parse result */
4579 SECURE_LOGW("incoming uri : %s", uri);
4580 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4581 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4589 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4592 mmplayer_t *player = NULL;
4593 MMMessageParamType msg = {0, };
4595 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4600 LOGE("user_data is null");
4604 player = (mmplayer_t *)user_data;
4606 if (!player->pipeline || !player->attrs) {
4607 LOGW("not initialized");
4611 LOGD("cmd lock player, cmd state : %d", player->cmd);
4612 MMPLAYER_CMD_LOCK(player);
4613 LOGD("cmd locked player");
4615 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4616 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4617 LOGW("player already destroyed");
4618 MMPLAYER_CMD_UNLOCK(player);
4622 player->interrupted_by_resource = TRUE;
4624 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4626 /* get last play position */
4627 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4628 msg.union_type = MM_MSG_UNION_TIME;
4629 msg.time.elapsed = pos;
4630 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4632 LOGW("failed to get play position.");
4635 LOGD("video resource conflict so, resource will be freed by unrealizing");
4636 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4637 LOGE("failed to unrealize");
4639 MMPLAYER_CMD_UNLOCK(player);
4641 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4642 player->hw_resource[res_idx] = NULL;
4646 return TRUE; /* release all the resources */
4650 __mmplayer_initialize_video_roi(mmplayer_t *player)
4652 player->video_roi.scale_x = 0.0;
4653 player->video_roi.scale_y = 0.0;
4654 player->video_roi.scale_width = 1.0;
4655 player->video_roi.scale_height = 1.0;
4659 _mmplayer_create_player(MMHandleType handle)
4661 int ret = MM_ERROR_PLAYER_INTERNAL;
4662 bool enabled = false;
4664 mmplayer_t *player = MM_PLAYER_CAST(handle);
4668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4670 /* initialize player state */
4671 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4672 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4673 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4674 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4676 /* check current state */
4677 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4679 /* construct attributes */
4680 player->attrs = _mmplayer_construct_attribute(handle);
4682 if (!player->attrs) {
4683 LOGE("Failed to construct attributes");
4687 /* initialize gstreamer with configured parameter */
4688 if (!__mmplayer_init_gstreamer(player)) {
4689 LOGE("Initializing gstreamer failed");
4690 _mmplayer_deconstruct_attribute(handle);
4694 /* create lock. note that g_tread_init() has already called in gst_init() */
4695 g_mutex_init(&player->fsink_lock);
4697 /* create update tag lock */
4698 g_mutex_init(&player->update_tag_lock);
4700 /* create gapless play mutex */
4701 g_mutex_init(&player->gapless_play_thread_mutex);
4703 /* create gapless play cond */
4704 g_cond_init(&player->gapless_play_thread_cond);
4706 /* create gapless play thread */
4707 player->gapless_play_thread =
4708 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4709 if (!player->gapless_play_thread) {
4710 LOGE("failed to create gapless play thread");
4711 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4712 g_mutex_clear(&player->gapless_play_thread_mutex);
4713 g_cond_clear(&player->gapless_play_thread_cond);
4717 player->bus_msg_q = g_queue_new();
4718 if (!player->bus_msg_q) {
4719 LOGE("failed to create queue for bus_msg");
4720 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4724 ret = _mmplayer_initialize_video_capture(player);
4725 if (ret != MM_ERROR_NONE) {
4726 LOGW("video capture is not supported");
4727 /* do not handle as error for headless profile */
4730 /* initialize resource manager */
4731 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4732 __resource_release_cb, player, &player->resource_manager)
4733 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4734 LOGE("failed to create resource manager");
4735 ret = MM_ERROR_PLAYER_INTERNAL;
4739 /* create video bo lock and cond */
4740 g_mutex_init(&player->video_bo_mutex);
4741 g_cond_init(&player->video_bo_cond);
4743 /* create subtitle info lock and cond */
4744 g_mutex_init(&player->subtitle_info_mutex);
4745 g_cond_init(&player->subtitle_info_cond);
4747 player->streaming_type = STREAMING_SERVICE_NONE;
4749 /* give default value of audio effect setting */
4750 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4751 player->sound.rg_enable = false;
4752 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4754 player->play_subtitle = FALSE;
4755 player->has_closed_caption = FALSE;
4756 player->pending_resume = FALSE;
4757 if (player->ini.dump_element_keyword[0][0] == '\0')
4758 player->ini.set_dump_element_flag = FALSE;
4760 player->ini.set_dump_element_flag = TRUE;
4762 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4763 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4764 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4766 /* Set video360 settings to their defaults for just-created player.
4769 player->is_360_feature_enabled = FALSE;
4770 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4771 LOGI("spherical feature info: %d", enabled);
4773 player->is_360_feature_enabled = TRUE;
4775 LOGE("failed to get spherical feature info");
4778 player->is_content_spherical = FALSE;
4779 player->is_video360_enabled = TRUE;
4780 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4781 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4782 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4783 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4784 player->video360_zoom = 1.0f;
4785 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4786 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4788 __mmplayer_initialize_video_roi(player);
4790 /* set player state to null */
4791 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4792 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4796 return MM_ERROR_NONE;
4800 g_mutex_clear(&player->fsink_lock);
4801 /* free update tag lock */
4802 g_mutex_clear(&player->update_tag_lock);
4803 g_queue_free(player->bus_msg_q);
4804 player->bus_msg_q = NULL;
4805 /* free gapless play thread */
4806 if (player->gapless_play_thread) {
4807 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4808 player->gapless_play_thread_exit = TRUE;
4809 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4810 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4812 g_thread_join(player->gapless_play_thread);
4813 player->gapless_play_thread = NULL;
4815 g_mutex_clear(&player->gapless_play_thread_mutex);
4816 g_cond_clear(&player->gapless_play_thread_cond);
4819 /* release attributes */
4820 _mmplayer_deconstruct_attribute(handle);
4828 __mmplayer_init_gstreamer(mmplayer_t *player)
4830 static gboolean initialized = FALSE;
4831 static const int max_argc = 50;
4833 gchar **argv = NULL;
4834 gchar **argv2 = NULL;
4840 LOGD("gstreamer already initialized.");
4845 argc = malloc(sizeof(int));
4846 argv = malloc(sizeof(gchar *) * max_argc);
4847 argv2 = malloc(sizeof(gchar *) * max_argc);
4849 if (!argc || !argv || !argv2)
4852 memset(argv, 0, sizeof(gchar *) * max_argc);
4853 memset(argv2, 0, sizeof(gchar *) * max_argc);
4857 argv[0] = g_strdup("mmplayer");
4860 for (i = 0; i < 5; i++) {
4861 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4862 if (strlen(player->ini.gst_param[i]) > 0) {
4863 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4868 /* we would not do fork for scanning plugins */
4869 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4872 /* check disable registry scan */
4873 if (player->ini.skip_rescan) {
4874 argv[*argc] = g_strdup("--gst-disable-registry-update");
4878 /* check disable segtrap */
4879 if (player->ini.disable_segtrap) {
4880 argv[*argc] = g_strdup("--gst-disable-segtrap");
4884 LOGD("initializing gstreamer with following parameter");
4885 LOGD("argc : %d", *argc);
4888 for (i = 0; i < arg_count; i++) {
4890 LOGD("argv[%d] : %s", i, argv2[i]);
4893 /* initializing gstreamer */
4894 if (!gst_init_check(argc, &argv, &err)) {
4895 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4902 for (i = 0; i < arg_count; i++) {
4904 LOGD("release - argv[%d] : %s", i, argv2[i]);
4906 MMPLAYER_FREEIF(argv2[i]);
4909 MMPLAYER_FREEIF(argv);
4910 MMPLAYER_FREEIF(argv2);
4911 MMPLAYER_FREEIF(argc);
4921 for (i = 0; i < arg_count; i++) {
4922 LOGD("free[%d] : %s", i, argv2[i]);
4923 MMPLAYER_FREEIF(argv2[i]);
4926 MMPLAYER_FREEIF(argv);
4927 MMPLAYER_FREEIF(argv2);
4928 MMPLAYER_FREEIF(argc);
4934 __mmplayer_check_async_state_transition(mmplayer_t *player)
4936 GstState element_state = GST_STATE_VOID_PENDING;
4937 GstState element_pending_state = GST_STATE_VOID_PENDING;
4938 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4939 GstElement *element = NULL;
4940 gboolean async = FALSE;
4942 /* check player handle */
4943 MMPLAYER_RETURN_IF_FAIL(player &&
4945 player->pipeline->mainbin &&
4946 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4949 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4951 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4952 LOGD("don't need to check the pipeline state");
4956 MMPLAYER_PRINT_STATE(player);
4958 /* wait for state transition */
4959 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4960 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4962 if (ret == GST_STATE_CHANGE_FAILURE) {
4963 LOGE(" [%s] state : %s pending : %s",
4964 GST_ELEMENT_NAME(element),
4965 gst_element_state_get_name(element_state),
4966 gst_element_state_get_name(element_pending_state));
4968 /* dump state of all element */
4969 _mmplayer_dump_pipeline_state(player);
4974 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4979 _mmplayer_destroy(MMHandleType handle)
4981 mmplayer_t *player = MM_PLAYER_CAST(handle);
4985 /* check player handle */
4986 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4988 /* destroy can called at anytime */
4989 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4991 /* check async state transition */
4992 __mmplayer_check_async_state_transition(player);
4994 /* release gapless play thread */
4995 if (player->gapless_play_thread) {
4996 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4997 player->gapless_play_thread_exit = TRUE;
4998 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4999 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5001 LOGD("waiting for gapless play thread exit");
5002 g_thread_join(player->gapless_play_thread);
5003 g_mutex_clear(&player->gapless_play_thread_mutex);
5004 g_cond_clear(&player->gapless_play_thread_cond);
5005 LOGD("gapless play thread released");
5008 _mmplayer_release_video_capture(player);
5010 /* release miscellaneous information */
5011 __mmplayer_release_misc(player);
5013 /* release pipeline */
5014 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5015 LOGE("failed to destroy pipeline");
5016 return MM_ERROR_PLAYER_INTERNAL;
5019 __mmplayer_destroy_hw_resource(player);
5021 g_queue_free(player->bus_msg_q);
5023 /* release subtitle info lock and cond */
5024 g_mutex_clear(&player->subtitle_info_mutex);
5025 g_cond_clear(&player->subtitle_info_cond);
5027 __mmplayer_release_dump_list(player->dump_list);
5029 /* release miscellaneous information.
5030 these info needs to be released after pipeline is destroyed. */
5031 __mmplayer_release_misc_post(player);
5033 /* release attributes */
5034 _mmplayer_deconstruct_attribute(handle);
5036 if (player->uri_info.uri_list) {
5037 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5038 player->uri_info.uri_list = NULL;
5042 g_mutex_clear(&player->fsink_lock);
5045 g_mutex_clear(&player->update_tag_lock);
5047 /* release video bo lock and cond */
5048 g_mutex_clear(&player->video_bo_mutex);
5049 g_cond_clear(&player->video_bo_cond);
5053 return MM_ERROR_NONE;
5057 _mmplayer_realize(MMHandleType hplayer)
5059 mmplayer_t *player = (mmplayer_t *)hplayer;
5060 int ret = MM_ERROR_NONE;
5063 MMHandleType attrs = 0;
5067 /* check player handle */
5068 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5070 /* check current state */
5071 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5073 attrs = MMPLAYER_GET_ATTRS(player);
5075 LOGE("fail to get attributes.");
5076 return MM_ERROR_PLAYER_INTERNAL;
5078 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5079 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5081 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5082 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5084 if (ret != MM_ERROR_NONE) {
5085 LOGE("failed to parse profile");
5090 if (uri && (strstr(uri, "es_buff://"))) {
5091 if (strstr(uri, "es_buff://push_mode"))
5092 player->es_player_push_mode = TRUE;
5094 player->es_player_push_mode = FALSE;
5097 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5098 LOGW("mms protocol is not supported format.");
5099 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5102 if (MMPLAYER_IS_STREAMING(player))
5103 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5105 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5107 player->smooth_streaming = FALSE;
5108 player->videodec_linked = 0;
5109 player->audiodec_linked = 0;
5110 player->textsink_linked = 0;
5111 player->is_external_subtitle_present = FALSE;
5112 player->is_external_subtitle_added_now = FALSE;
5113 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5114 player->video360_metadata.is_spherical = -1;
5115 player->is_openal_plugin_used = FALSE;
5116 player->subtitle_language_list = NULL;
5117 player->is_subtitle_force_drop = FALSE;
5119 _mmplayer_track_initialize(player);
5120 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5122 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5123 gint prebuffer_ms = 0, rebuffer_ms = 0;
5125 player->streamer = _mm_player_streaming_create();
5126 _mm_player_streaming_initialize(player->streamer, TRUE);
5128 mm_attrs_multiple_get(player->attrs, NULL,
5129 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5130 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5132 if (prebuffer_ms > 0) {
5133 prebuffer_ms = MAX(prebuffer_ms, 1000);
5134 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5137 if (rebuffer_ms > 0) {
5138 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5139 rebuffer_ms = MAX(rebuffer_ms, 1000);
5140 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5143 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5144 player->streamer->buffering_req.rebuffer_time);
5147 /* realize pipeline */
5148 ret = __mmplayer_gst_realize(player);
5149 if (ret != MM_ERROR_NONE)
5150 LOGE("fail to realize the player.");
5152 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5160 _mmplayer_unrealize(MMHandleType hplayer)
5162 mmplayer_t *player = (mmplayer_t *)hplayer;
5163 int ret = MM_ERROR_NONE;
5164 int rm_ret = MM_ERROR_NONE;
5165 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5169 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5171 MMPLAYER_CMD_UNLOCK(player);
5172 _mmplayer_bus_watcher_remove(player);
5173 /* destroy the gst bus msg thread which is created during realize.
5174 this funct have to be called before getting cmd lock. */
5175 _mmplayer_bus_msg_thread_destroy(player);
5176 MMPLAYER_CMD_LOCK(player);
5178 /* check current state */
5179 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5181 /* check async state transition */
5182 __mmplayer_check_async_state_transition(player);
5184 /* unrealize pipeline */
5185 ret = __mmplayer_gst_unrealize(player);
5187 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5188 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5189 if (rm_ret != MM_ERROR_NONE)
5190 LOGE("failed to release [%d] resources", res_idx);
5193 player->interrupted_by_resource = FALSE;
5200 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5202 mmplayer_t *player = (mmplayer_t *)hplayer;
5204 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5206 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5210 _mmplayer_get_state(MMHandleType hplayer, int *state)
5212 mmplayer_t *player = (mmplayer_t *)hplayer;
5214 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5216 *state = MMPLAYER_CURRENT_STATE(player);
5218 return MM_ERROR_NONE;
5222 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5224 GstElement *vol_element = NULL;
5225 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5228 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5229 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5231 /* check pipeline handle */
5232 if (!player->pipeline || !player->pipeline->audiobin) {
5233 LOGD("'%s' will be applied when audiobin is created", prop_name);
5235 /* NOTE : stored value will be used in create_audiobin
5236 * returning MM_ERROR_NONE here makes application to able to
5237 * set audio volume or mute at anytime.
5239 return MM_ERROR_NONE;
5242 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5243 volume_elem_id = MMPLAYER_A_SINK;
5245 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5247 LOGE("failed to get vol element %d", volume_elem_id);
5248 return MM_ERROR_PLAYER_INTERNAL;
5251 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5253 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5254 LOGE("there is no '%s' property", prop_name);
5255 return MM_ERROR_PLAYER_INTERNAL;
5258 if (!strcmp(prop_name, "volume")) {
5259 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5260 } else if (!strcmp(prop_name, "mute")) {
5261 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5263 LOGE("invalid property %s", prop_name);
5264 return MM_ERROR_PLAYER_INTERNAL;
5267 return MM_ERROR_NONE;
5271 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5273 int ret = MM_ERROR_NONE;
5274 mmplayer_t *player = (mmplayer_t *)hplayer;
5277 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5279 LOGD("volume = %f", volume);
5281 /* invalid factor range or not */
5282 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5283 LOGE("Invalid volume value");
5284 return MM_ERROR_INVALID_ARGUMENT;
5287 player->sound.volume = volume;
5289 ret = __mmplayer_gst_set_volume_property(player, "volume");
5296 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5298 mmplayer_t *player = (mmplayer_t *)hplayer;
5302 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5303 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5305 *volume = player->sound.volume;
5307 LOGD("current vol = %f", *volume);
5310 return MM_ERROR_NONE;
5314 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5316 int ret = MM_ERROR_NONE;
5317 mmplayer_t *player = (mmplayer_t *)hplayer;
5320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5322 LOGD("mute = %d", mute);
5324 player->sound.mute = mute;
5326 ret = __mmplayer_gst_set_volume_property(player, "mute");
5333 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5335 mmplayer_t *player = (mmplayer_t *)hplayer;
5339 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5340 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5342 *mute = player->sound.mute;
5344 LOGD("current mute = %d", *mute);
5348 return MM_ERROR_NONE;
5352 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5354 mmplayer_t *player = (mmplayer_t *)hplayer;
5358 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5360 player->audio_stream_changed_cb = callback;
5361 player->audio_stream_changed_cb_user_param = user_param;
5362 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5366 return MM_ERROR_NONE;
5370 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5372 mmplayer_t *player = (mmplayer_t *)hplayer;
5376 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5378 player->audio_decoded_cb = callback;
5379 player->audio_decoded_cb_user_param = user_param;
5380 player->audio_extract_opt = opt;
5381 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5385 return MM_ERROR_NONE;
5389 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5391 mmplayer_t *player = (mmplayer_t *)hplayer;
5395 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5397 if (callback && !player->bufmgr)
5398 player->bufmgr = tbm_bufmgr_init(-1);
5400 player->set_mode.video_export = (callback) ? true : false;
5401 player->video_decoded_cb = callback;
5402 player->video_decoded_cb_user_param = user_param;
5404 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5408 return MM_ERROR_NONE;
5412 _mmplayer_start(MMHandleType hplayer)
5414 mmplayer_t *player = (mmplayer_t *)hplayer;
5415 gint ret = MM_ERROR_NONE;
5419 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5421 /* check current state */
5422 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5424 /* start pipeline */
5425 ret = _mmplayer_gst_start(player);
5426 if (ret != MM_ERROR_NONE)
5427 LOGE("failed to start player.");
5429 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5430 LOGD("force playing start even during buffering");
5431 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5439 /* NOTE: post "not supported codec message" to application
5440 * when one codec is not found during AUTOPLUGGING in MSL.
5441 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5442 * And, if any codec is not found, don't send message here.
5443 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5446 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5448 MMMessageParamType msg_param;
5449 memset(&msg_param, 0, sizeof(MMMessageParamType));
5450 gboolean post_msg_direct = FALSE;
5454 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5456 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5457 player->not_supported_codec, player->can_support_codec);
5459 if (player->not_found_demuxer) {
5460 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5461 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5463 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5464 MMPLAYER_FREEIF(msg_param.data);
5466 return MM_ERROR_NONE;
5469 if (player->not_supported_codec) {
5470 if (player->can_support_codec) {
5471 // There is one codec to play
5472 post_msg_direct = TRUE;
5474 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5475 post_msg_direct = TRUE;
5478 if (post_msg_direct) {
5479 MMMessageParamType msg_param;
5480 memset(&msg_param, 0, sizeof(MMMessageParamType));
5482 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5483 LOGW("not found AUDIO codec, posting error code to application.");
5485 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5486 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5487 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5488 LOGW("not found VIDEO codec, posting error code to application.");
5490 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5491 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5494 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5496 MMPLAYER_FREEIF(msg_param.data);
5498 return MM_ERROR_NONE;
5500 // no any supported codec case
5501 LOGW("not found any codec, posting error code to application.");
5503 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5504 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5505 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5507 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5508 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5511 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5513 MMPLAYER_FREEIF(msg_param.data);
5519 return MM_ERROR_NONE;
5522 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5524 GstState element_state = GST_STATE_VOID_PENDING;
5525 GstState element_pending_state = GST_STATE_VOID_PENDING;
5526 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5527 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5529 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5531 MMPLAYER_RECONFIGURE_LOCK(player);
5532 if (!player->gapless.reconfigure) {
5533 MMPLAYER_RECONFIGURE_UNLOCK(player);
5537 LOGI("reconfigure is under process");
5538 MMPLAYER_RECONFIGURE_WAIT(player);
5539 MMPLAYER_RECONFIGURE_UNLOCK(player);
5540 LOGI("reconfigure is completed.");
5542 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5543 &element_state, &element_pending_state, timeout * GST_SECOND);
5544 if (result == GST_STATE_CHANGE_FAILURE)
5545 LOGW("failed to get pipeline state in %d sec", timeout);
5550 /* NOTE : it should be able to call 'stop' anytime*/
5552 _mmplayer_stop(MMHandleType hplayer)
5554 mmplayer_t *player = (mmplayer_t *)hplayer;
5555 int ret = MM_ERROR_NONE;
5559 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5561 /* check current state */
5562 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5564 /* need to wait till the rebuilding pipeline is completed */
5565 __mmplayer_check_pipeline_reconfigure_state(player);
5566 MMPLAYER_RECONFIGURE_LOCK(player);
5567 __mmplayer_reset_gapless_state(player);
5568 MMPLAYER_RECONFIGURE_UNLOCK(player);
5570 /* NOTE : application should not wait for EOS after calling STOP */
5571 _mmplayer_cancel_eos_timer(player);
5574 player->seek_state = MMPLAYER_SEEK_NONE;
5577 ret = _mmplayer_gst_stop(player);
5579 if (ret != MM_ERROR_NONE)
5580 LOGE("failed to stop player.");
5588 _mmplayer_pause(MMHandleType hplayer)
5590 mmplayer_t *player = (mmplayer_t *)hplayer;
5591 gint64 pos_nsec = 0;
5592 gboolean async = FALSE;
5593 gint ret = MM_ERROR_NONE;
5597 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5599 /* check current state */
5600 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5602 /* check pipeline reconfigure state */
5603 __mmplayer_check_pipeline_reconfigure_state(player);
5605 switch (MMPLAYER_CURRENT_STATE(player)) {
5606 case MM_PLAYER_STATE_READY:
5608 /* check prepare async or not.
5609 * In the case of streaming playback, it's recommended to avoid blocking wait.
5611 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5612 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5614 /* Changing back sync of rtspsrc to async */
5615 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5616 LOGD("async prepare working mode for rtsp");
5622 case MM_PLAYER_STATE_PLAYING:
5624 /* NOTE : store current point to overcome some bad operation
5625 *(returning zero when getting current position in paused state) of some
5628 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5629 LOGW("getting current position failed in paused");
5631 player->last_position = pos_nsec;
5633 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5634 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5635 This causes problem is position calculation during normal pause resume scenarios also.
5636 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5637 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5638 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5639 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5645 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5646 LOGD("doing async pause in case of ms buff src");
5650 /* pause pipeline */
5651 ret = _mmplayer_gst_pause(player, async);
5652 if (ret != MM_ERROR_NONE) {
5653 LOGE("failed to pause player. ret : 0x%x", ret);
5654 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5658 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5659 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5660 LOGE("failed to update display_rotation");
5664 return MM_ERROR_NONE;
5667 /* in case of streaming, pause could take long time.*/
5669 _mmplayer_abort_pause(MMHandleType hplayer)
5671 mmplayer_t *player = (mmplayer_t *)hplayer;
5672 int ret = MM_ERROR_NONE;
5676 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5678 player->pipeline->mainbin,
5679 MM_ERROR_PLAYER_NOT_INITIALIZED);
5681 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5682 LOGD("set the videobin state to READY");
5683 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5684 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5688 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5689 LOGD("set the audiobin state to READY");
5690 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5691 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5695 LOGD("set the pipeline state to READY");
5696 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5697 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5699 if (ret != MM_ERROR_NONE) {
5700 LOGE("fail to change state to READY");
5701 return MM_ERROR_PLAYER_INTERNAL;
5704 LOGD("succeeded in changing state to READY");
5709 _mmplayer_resume(MMHandleType hplayer)
5711 mmplayer_t *player = (mmplayer_t *)hplayer;
5712 int ret = MM_ERROR_NONE;
5713 gboolean async = FALSE;
5717 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5719 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5720 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5721 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5725 /* Changing back sync mode rtspsrc to async */
5726 LOGD("async resume for rtsp case");
5730 /* check current state */
5731 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5733 ret = _mmplayer_gst_resume(player, async);
5734 if (ret != MM_ERROR_NONE)
5735 LOGE("failed to resume player.");
5737 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5738 LOGD("force resume even during buffering");
5739 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5748 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5750 mmplayer_t *player = (mmplayer_t *)hplayer;
5751 gint64 pos_nsec = 0;
5752 int ret = MM_ERROR_NONE;
5754 signed long long start = 0, stop = 0;
5755 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5758 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5759 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5761 /* The sound of video is not supported under 0.0 and over 2.0. */
5762 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5763 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5766 _mmplayer_set_mute(hplayer, mute);
5768 if (player->playback_rate == rate)
5769 return MM_ERROR_NONE;
5771 /* If the position is reached at start potion during fast backward, EOS is posted.
5772 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5774 player->playback_rate = rate;
5776 current_state = MMPLAYER_CURRENT_STATE(player);
5778 if (current_state != MM_PLAYER_STATE_PAUSED)
5779 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5781 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5783 if ((current_state == MM_PLAYER_STATE_PAUSED)
5784 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5785 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5786 pos_nsec = player->last_position;
5791 stop = GST_CLOCK_TIME_NONE;
5793 start = GST_CLOCK_TIME_NONE;
5797 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5798 player->playback_rate,
5800 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5801 GST_SEEK_TYPE_SET, start,
5802 GST_SEEK_TYPE_SET, stop)) {
5803 LOGE("failed to set speed playback");
5804 return MM_ERROR_PLAYER_SEEK;
5807 LOGD("succeeded to set speed playback as %0.1f", rate);
5811 return MM_ERROR_NONE;;
5815 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5817 mmplayer_t *player = (mmplayer_t *)hplayer;
5818 int ret = MM_ERROR_NONE;
5822 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5824 /* check pipeline reconfigure state */
5825 __mmplayer_check_pipeline_reconfigure_state(player);
5827 ret = _mmplayer_gst_set_position(player, position, FALSE);
5835 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5837 mmplayer_t *player = (mmplayer_t *)hplayer;
5838 int ret = MM_ERROR_NONE;
5840 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5841 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5843 if (g_strrstr(player->type, "video/mpegts"))
5844 __mmplayer_update_duration_value(player);
5846 *duration = player->duration;
5851 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5853 mmplayer_t *player = (mmplayer_t *)hplayer;
5854 int ret = MM_ERROR_NONE;
5856 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5858 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5864 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5866 mmplayer_t *player = (mmplayer_t *)hplayer;
5867 int ret = MM_ERROR_NONE;
5871 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5873 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5881 __mmplayer_is_midi_type(gchar *str_caps)
5883 if ((g_strrstr(str_caps, "audio/midi")) ||
5884 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5885 (g_strrstr(str_caps, "application/x-smaf")) ||
5886 (g_strrstr(str_caps, "audio/x-imelody")) ||
5887 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5888 (g_strrstr(str_caps, "audio/xmf")) ||
5889 (g_strrstr(str_caps, "audio/mxmf"))) {
5898 __mmplayer_is_only_mp3_type(gchar *str_caps)
5900 if (g_strrstr(str_caps, "application/x-id3") ||
5901 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5907 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5909 GstStructure *caps_structure = NULL;
5910 gint samplerate = 0;
5914 MMPLAYER_RETURN_IF_FAIL(player && caps);
5916 caps_structure = gst_caps_get_structure(caps, 0);
5918 /* set stream information */
5919 gst_structure_get_int(caps_structure, "rate", &samplerate);
5920 gst_structure_get_int(caps_structure, "channels", &channels);
5922 mm_player_set_attribute((MMHandleType)player, NULL,
5923 "content_audio_samplerate", samplerate,
5924 "content_audio_channels", channels, NULL);
5926 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5930 __mmplayer_update_content_type_info(mmplayer_t *player)
5933 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5935 if (__mmplayer_is_midi_type(player->type)) {
5936 player->bypass_audio_effect = TRUE;
5940 if (!player->streamer) {
5941 LOGD("no need to check streaming type");
5945 if (g_strrstr(player->type, "application/x-hls")) {
5946 /* If it can't know exact type when it parses uri because of redirection case,
5947 * it will be fixed by typefinder or when doing autoplugging.
5949 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5950 player->streamer->is_adaptive_streaming = TRUE;
5951 } else if (g_strrstr(player->type, "application/dash+xml")) {
5952 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5953 player->streamer->is_adaptive_streaming = TRUE;
5956 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5957 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5958 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5960 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5961 if (player->streamer->is_adaptive_streaming)
5962 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5964 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5968 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5973 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5974 GstCaps *caps, gpointer data)
5976 mmplayer_t *player = (mmplayer_t *)data;
5980 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5982 /* store type string */
5983 if (player->type_caps) {
5984 gst_caps_unref(player->type_caps);
5985 player->type_caps = NULL;
5988 player->type_caps = gst_caps_copy(caps);
5989 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5991 MMPLAYER_FREEIF(player->type);
5992 player->type = gst_caps_to_string(caps);
5994 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5995 player, player->type, probability, gst_caps_get_size(caps));
5997 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5998 (g_strrstr(player->type, "audio/x-raw-int"))) {
5999 LOGE("not support media format");
6001 if (player->msg_posted == FALSE) {
6002 MMMessageParamType msg_param;
6003 memset(&msg_param, 0, sizeof(MMMessageParamType));
6005 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6006 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6008 /* don't post more if one was sent already */
6009 player->msg_posted = TRUE;
6014 __mmplayer_update_content_type_info(player);
6016 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6019 pad = gst_element_get_static_pad(tf, "src");
6021 LOGE("fail to get typefind src pad.");
6025 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6026 gboolean async = FALSE;
6027 LOGE("failed to autoplug %s", player->type);
6029 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6031 if (async && player->msg_posted == FALSE)
6032 __mmplayer_handle_missed_plugin(player);
6034 gst_object_unref(GST_OBJECT(pad));
6041 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6043 GstElement *decodebin = NULL;
6047 /* create decodebin */
6048 decodebin = gst_element_factory_make("decodebin", NULL);
6051 LOGE("fail to create decodebin");
6055 /* raw pad handling signal */
6056 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6057 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6059 /* no-more-pad pad handling signal */
6060 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6061 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6063 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6064 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6066 /* This signal is emitted when a pad for which there is no further possible
6067 decoding is added to the decodebin.*/
6068 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6069 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6071 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6072 before looking for any elements that can handle that stream.*/
6073 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6074 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6076 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6077 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6078 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6080 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6081 before looking for any elements that can handle that stream.*/
6082 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6083 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6085 /* This signal is emitted once decodebin has finished decoding all the data.*/
6086 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6087 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6089 /* This signal is emitted when a element is added to the bin.*/
6090 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6091 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6098 __mmplayer_gst_make_queue2(mmplayer_t *player)
6100 GstElement *queue2 = NULL;
6101 gint64 dur_bytes = 0L;
6102 mmplayer_gst_element_t *mainbin = NULL;
6103 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6106 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6108 mainbin = player->pipeline->mainbin;
6110 queue2 = gst_element_factory_make("queue2", "queue2");
6112 LOGE("failed to create buffering queue element");
6116 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6117 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6119 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6121 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6122 * skip the pull mode(file or ring buffering) setting. */
6123 if (dur_bytes > 0) {
6124 if (!g_strrstr(player->type, "video/mpegts")) {
6125 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6126 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6132 _mm_player_streaming_set_queue2(player->streamer,
6136 (guint64)dur_bytes); /* no meaning at the moment */
6142 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6144 mmplayer_gst_element_t *mainbin = NULL;
6145 GstElement *decodebin = NULL;
6146 GstElement *queue2 = NULL;
6147 GstPad *sinkpad = NULL;
6148 GstPad *qsrcpad = NULL;
6151 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6153 mainbin = player->pipeline->mainbin;
6155 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6157 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6158 LOGW("need to check: muxed buffer is not null");
6161 queue2 = __mmplayer_gst_make_queue2(player);
6163 LOGE("failed to make queue2");
6167 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6168 LOGE("failed to add buffering queue");
6172 sinkpad = gst_element_get_static_pad(queue2, "sink");
6173 qsrcpad = gst_element_get_static_pad(queue2, "src");
6175 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6176 LOGE("failed to link [%s:%s]-[%s:%s]",
6177 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6181 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6182 LOGE("failed to sync queue2 state with parent");
6186 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6187 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6191 gst_object_unref(GST_OBJECT(sinkpad));
6195 /* create decodebin */
6196 decodebin = _mmplayer_gst_make_decodebin(player);
6198 LOGE("failed to make decodebin");
6202 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6203 LOGE("failed to add decodebin");
6207 /* to force caps on the decodebin element and avoid reparsing stuff by
6208 * typefind. It also avoids a deadlock in the way typefind activates pads in
6209 * the state change */
6210 g_object_set(decodebin, "sink-caps", caps, NULL);
6212 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6214 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6215 LOGE("failed to link [%s:%s]-[%s:%s]",
6216 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6220 gst_object_unref(GST_OBJECT(sinkpad));
6222 gst_object_unref(GST_OBJECT(qsrcpad));
6225 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6226 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6228 /* set decodebin property about buffer in streaming playback. *
6229 * in case of HLS/DASH, it does not need to have big buffer *
6230 * because it is kind of adaptive streaming. */
6231 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6232 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6233 gint high_percent = 0;
6235 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6236 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6238 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6240 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6242 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6243 "high-percent", high_percent,
6244 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6245 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6246 "max-size-buffers", 0, NULL); // disable or automatic
6249 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6250 LOGE("failed to sync decodebin state with parent");
6261 gst_object_unref(GST_OBJECT(sinkpad));
6264 gst_object_unref(GST_OBJECT(qsrcpad));
6267 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6268 * You need to explicitly set elements to the NULL state before
6269 * dropping the final reference, to allow them to clean up.
6271 gst_element_set_state(queue2, GST_STATE_NULL);
6273 /* And, it still has a parent "player".
6274 * You need to let the parent manage the object instead of unreffing the object directly.
6276 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6277 gst_object_unref(queue2);
6282 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6283 * You need to explicitly set elements to the NULL state before
6284 * dropping the final reference, to allow them to clean up.
6286 gst_element_set_state(decodebin, GST_STATE_NULL);
6288 /* And, it still has a parent "player".
6289 * You need to let the parent manage the object instead of unreffing the object directly.
6292 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6293 gst_object_unref(decodebin);
6301 _mmplayer_update_not_supported_codec_info(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6305 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6306 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6308 LOGD("class : %s, mime : %s", factory_class, mime);
6310 /* add missing plugin */
6311 /* NOTE : msl should check missing plugin for image mime type.
6312 * Some motion jpeg clips can have playable audio track.
6313 * So, msl have to play audio after displaying popup written video format not supported.
6315 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6316 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6317 LOGD("not found demuxer");
6318 player->not_found_demuxer = TRUE;
6319 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6325 if (!g_strrstr(factory_class, "Demuxer")) {
6326 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6327 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6328 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6330 /* check that clip have multi tracks or not */
6331 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6332 LOGD("video plugin is already linked");
6334 LOGW("add VIDEO to missing plugin");
6335 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6336 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6338 } else if (g_str_has_prefix(mime, "audio")) {
6339 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6340 LOGD("audio plugin is already linked");
6342 LOGW("add AUDIO to missing plugin");
6343 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6344 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6352 return MM_ERROR_NONE;
6356 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6358 mmplayer_t *player = (mmplayer_t *)data;
6362 MMPLAYER_RETURN_IF_FAIL(player);
6364 /* remove fakesink. */
6365 if (!_mmplayer_gst_remove_fakesink(player,
6366 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6367 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6368 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6369 * source element are not same. To overcome this situation, this function will called
6370 * several places and several times. Therefore, this is not an error case.
6375 LOGD("[handle: %p] pipeline has completely constructed", player);
6377 if ((player->msg_posted == FALSE) &&
6378 (player->cmd >= MMPLAYER_COMMAND_START))
6379 __mmplayer_handle_missed_plugin(player);
6381 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6385 __mmplayer_check_profile(void)
6388 static int profile_tv = -1;
6390 if (__builtin_expect(profile_tv != -1, 1))
6393 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6394 switch (*profileName) {
6409 __mmplayer_get_next_uri(mmplayer_t *player)
6411 mmplayer_parse_profile_t profile;
6413 guint num_of_list = 0;
6416 num_of_list = g_list_length(player->uri_info.uri_list);
6417 uri_idx = player->uri_info.uri_idx;
6419 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6420 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6421 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6423 LOGW("next uri does not exist");
6427 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6428 LOGE("failed to parse profile");
6432 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6433 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6434 LOGW("uri type is not supported(%d)", profile.uri_type);
6438 LOGD("success to find next uri %d", uri_idx);
6442 if (!uri || uri_idx == num_of_list) {
6443 LOGE("failed to find next uri");
6447 player->uri_info.uri_idx = uri_idx;
6448 if (mm_player_set_attribute((MMHandleType)player, NULL,
6449 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6450 LOGE("failed to set attribute");
6454 SECURE_LOGD("next playback uri: %s", uri);
6459 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6461 #define REPEAT_COUNT_INFINITE -1
6462 #define REPEAT_COUNT_MIN 2
6463 #define ORIGINAL_URI_ONLY 1
6465 MMHandleType attrs = 0;
6469 guint num_of_uri = 0;
6470 int profile_tv = -1;
6474 LOGD("checking for gapless play option");
6476 if (player->build_audio_offload) {
6477 LOGE("offload path is not supportable.");
6481 if (player->pipeline->textbin) {
6482 LOGE("subtitle path is enabled. gapless play is not supported.");
6486 attrs = MMPLAYER_GET_ATTRS(player);
6488 LOGE("fail to get attributes.");
6492 mm_attrs_multiple_get(player->attrs, NULL,
6493 "content_video_found", &video,
6494 "profile_play_count", &count,
6495 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6497 /* gapless playback is not supported in case of video at TV profile. */
6498 profile_tv = __mmplayer_check_profile();
6499 if (profile_tv && video) {
6500 LOGW("not support video gapless playback");
6504 /* check repeat count in case of audio */
6506 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6507 LOGW("gapless is disabled");
6511 num_of_uri = g_list_length(player->uri_info.uri_list);
6513 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6515 if (num_of_uri == ORIGINAL_URI_ONLY) {
6516 /* audio looping path */
6517 if (count >= REPEAT_COUNT_MIN) {
6518 /* decrease play count */
6519 /* we succeeded to rewind. update play count and then wait for next EOS */
6521 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6522 } else if (count != REPEAT_COUNT_INFINITE) {
6523 LOGD("there is no next uri and no repeat");
6526 LOGD("looping cnt %d", count);
6528 /* gapless playback path */
6529 if (!__mmplayer_get_next_uri(player)) {
6530 LOGE("failed to get next uri");
6537 LOGE("unable to play gapless path. EOS will be posted soon");
6542 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6544 GstPad *sinkpad = g_value_get_object (item);
6545 GstElement *element = GST_ELEMENT(user_data);
6546 if (!sinkpad || !element) {
6547 LOGE("invalid parameter");
6551 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6552 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6556 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6558 mmplayer_gst_element_t *sinkbin = NULL;
6559 main_element_id_e concatId = MMPLAYER_M_NUM;
6560 main_element_id_e sinkId = MMPLAYER_M_NUM;
6561 gboolean send_notice = FALSE;
6562 GstElement *element;
6566 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6568 LOGD("type %d", type);
6571 case MM_PLAYER_TRACK_TYPE_AUDIO:
6572 concatId = MMPLAYER_M_A_CONCAT;
6573 sinkId = MMPLAYER_A_BIN;
6574 sinkbin = player->pipeline->audiobin;
6576 case MM_PLAYER_TRACK_TYPE_VIDEO:
6577 concatId = MMPLAYER_M_V_CONCAT;
6578 sinkId = MMPLAYER_V_BIN;
6579 sinkbin = player->pipeline->videobin;
6582 case MM_PLAYER_TRACK_TYPE_TEXT:
6583 concatId = MMPLAYER_M_T_CONCAT;
6584 sinkId = MMPLAYER_T_BIN;
6585 sinkbin = player->pipeline->textbin;
6588 LOGE("requested type is not supportable");
6593 element = player->pipeline->mainbin[concatId].gst;
6597 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6598 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6599 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6600 if (srcpad && sinkpad) {
6601 /* after getting drained signal there is no data flows, so no need to do pad_block */
6602 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6603 gst_pad_unlink(srcpad, sinkpad);
6605 /* send custom event to sink pad to handle it at video sink */
6607 LOGD("send custom event to sinkpad");
6608 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6609 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6610 gst_pad_send_event(sinkpad, event);
6613 gst_object_unref(srcpad);
6614 gst_object_unref(sinkpad);
6617 LOGD("release concat request pad");
6618 /* release and unref requests pad from the selector */
6619 iter = gst_element_iterate_sink_pads(element);
6620 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6621 gst_iterator_resync(iter);
6622 gst_iterator_free(iter);
6628 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6630 mmplayer_track_t *selector = &player->track[type];
6631 mmplayer_gst_element_t *sinkbin = NULL;
6632 main_element_id_e selectorId = MMPLAYER_M_NUM;
6633 main_element_id_e sinkId = MMPLAYER_M_NUM;
6634 GstPad *srcpad = NULL;
6635 GstPad *sinkpad = NULL;
6636 gboolean send_notice = FALSE;
6639 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6641 LOGD("type %d", type);
6644 case MM_PLAYER_TRACK_TYPE_AUDIO:
6645 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6646 sinkId = MMPLAYER_A_BIN;
6647 sinkbin = player->pipeline->audiobin;
6649 case MM_PLAYER_TRACK_TYPE_VIDEO:
6650 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6651 sinkId = MMPLAYER_V_BIN;
6652 sinkbin = player->pipeline->videobin;
6655 case MM_PLAYER_TRACK_TYPE_TEXT:
6656 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6657 sinkId = MMPLAYER_T_BIN;
6658 sinkbin = player->pipeline->textbin;
6661 LOGE("requested type is not supportable");
6666 if (player->pipeline->mainbin[selectorId].gst) {
6669 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6671 if (selector->event_probe_id != 0)
6672 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6673 selector->event_probe_id = 0;
6675 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6676 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);
6692 gst_object_unref(sinkpad);
6695 gst_object_unref(srcpad);
6698 LOGD("selector release");
6700 /* release and unref requests pad from the selector */
6701 for (n = 0; n < selector->streams->len; n++) {
6702 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6703 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6706 g_ptr_array_set_size(selector->streams, 0);
6708 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6709 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6711 player->pipeline->mainbin[selectorId].gst = NULL;
6719 __mmplayer_deactivate_old_path(mmplayer_t *player)
6722 MMPLAYER_RETURN_IF_FAIL(player);
6724 if (MMPLAYER_USE_DECODEBIN(player)) {
6725 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6726 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6727 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6728 LOGE("deactivate selector error");
6732 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6733 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6734 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6735 LOGE("deactivate concat error");
6740 _mmplayer_track_destroy(player);
6741 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6743 if (player->streamer) {
6744 _mm_player_streaming_initialize(player->streamer, FALSE);
6745 _mm_player_streaming_destroy(player->streamer);
6746 player->streamer = NULL;
6749 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6755 if (!player->msg_posted) {
6756 MMMessageParamType msg = {0,};
6759 msg.code = MM_ERROR_PLAYER_INTERNAL;
6760 LOGE("gapless_uri_play> deactivate error");
6762 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6763 player->msg_posted = TRUE;
6769 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6771 int result = MM_ERROR_NONE;
6772 mmplayer_t *player = (mmplayer_t *)hplayer;
6775 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6776 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6778 if (mm_player_set_attribute(hplayer, NULL,
6779 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6780 LOGE("failed to set attribute");
6781 result = MM_ERROR_PLAYER_INTERNAL;
6783 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6784 LOGE("failed to add the original uri in the uri list.");
6792 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6794 mmplayer_t *player = (mmplayer_t *)hplayer;
6795 guint num_of_list = 0;
6799 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6800 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6802 if (player->pipeline && player->pipeline->textbin) {
6803 LOGE("subtitle path is enabled.");
6804 return MM_ERROR_PLAYER_INVALID_STATE;
6807 num_of_list = g_list_length(player->uri_info.uri_list);
6809 if (is_first_path) {
6810 if (num_of_list == 0) {
6811 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6812 SECURE_LOGD("add original path : %s", uri);
6814 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6815 player->uri_info.uri_list = g_list_prepend(
6816 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6817 SECURE_LOGD("change original path : %s", uri);
6820 MMHandleType attrs = 0;
6821 attrs = MMPLAYER_GET_ATTRS(player);
6823 if (num_of_list == 0) {
6824 char *original_uri = NULL;
6827 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6829 if (!original_uri) {
6830 LOGE("there is no original uri.");
6831 return MM_ERROR_PLAYER_INVALID_STATE;
6834 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6835 player->uri_info.uri_idx = 0;
6837 SECURE_LOGD("add original path at first : %s", original_uri);
6841 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6842 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6846 return MM_ERROR_NONE;
6850 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6852 mmplayer_t *player = (mmplayer_t *)hplayer;
6853 char *next_uri = NULL;
6854 guint num_of_list = 0;
6857 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6859 num_of_list = g_list_length(player->uri_info.uri_list);
6861 if (num_of_list > 0) {
6862 gint uri_idx = player->uri_info.uri_idx;
6864 if (uri_idx < num_of_list - 1)
6869 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6870 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6872 *uri = g_strdup(next_uri);
6876 return MM_ERROR_NONE;
6880 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6881 GstCaps *caps, gpointer data)
6883 mmplayer_t *player = (mmplayer_t *)data;
6884 const gchar *klass = NULL;
6885 const gchar *mime = NULL;
6886 gchar *caps_str = NULL;
6888 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6889 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6890 caps_str = gst_caps_to_string(caps);
6892 LOGW("unknown type of caps : %s from %s",
6893 caps_str, GST_ELEMENT_NAME(elem));
6895 MMPLAYER_FREEIF(caps_str);
6897 /* There is no available codec. */
6898 _mmplayer_update_not_supported_codec_info(player, klass, mime);
6902 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6903 GstCaps *caps, gpointer data)
6905 mmplayer_t *player = (mmplayer_t *)data;
6906 const char *mime = NULL;
6907 gboolean ret = TRUE;
6909 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6910 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6912 if (g_str_has_prefix(mime, "audio")) {
6913 GstStructure *caps_structure = NULL;
6914 gint samplerate = 0;
6916 gchar *caps_str = NULL;
6918 caps_structure = gst_caps_get_structure(caps, 0);
6919 gst_structure_get_int(caps_structure, "rate", &samplerate);
6920 gst_structure_get_int(caps_structure, "channels", &channels);
6922 if ((channels > 0 && samplerate == 0)) {
6923 LOGD("exclude audio...");
6927 caps_str = gst_caps_to_string(caps);
6928 /* set it directly because not sent by TAG */
6929 if (g_strrstr(caps_str, "mobile-xmf"))
6930 mm_player_set_attribute((MMHandleType)player, NULL,
6931 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6933 MMPLAYER_FREEIF(caps_str);
6934 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6935 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
6936 LOGD("video is already linked, allow the stream switch");
6939 LOGD("video is already linked");
6943 LOGD("found new stream");
6950 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6952 gboolean ret = FALSE;
6953 GDBusConnection *conn = NULL;
6955 GVariant *result = NULL;
6956 const gchar *dbus_device_type = NULL;
6957 const gchar *dbus_ret = NULL;
6960 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6962 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6967 result = g_dbus_connection_call_sync(conn,
6968 "org.pulseaudio.Server",
6969 "/org/pulseaudio/StreamManager",
6970 "org.pulseaudio.StreamManager",
6971 "GetCurrentMediaRoutingPath",
6972 g_variant_new("(s)", "out"),
6973 G_VARIANT_TYPE("(ss)"),
6974 G_DBUS_CALL_FLAGS_NONE,
6978 if (!result || err) {
6979 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6984 /* device type is listed in stream-map.json at mmfw-sysconf */
6985 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6987 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6988 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6991 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6992 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6993 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6994 LOGD("audio offload is supportable");
7000 LOGD("audio offload is not supportable");
7003 g_variant_unref(result);
7005 g_object_unref(conn);
7010 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7012 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7013 gint64 position = 0;
7015 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7016 player->pipeline && player->pipeline->mainbin);
7018 MMPLAYER_CMD_LOCK(player);
7019 current_state = MMPLAYER_CURRENT_STATE(player);
7021 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7022 LOGW("getting current position failed in paused");
7024 _mmplayer_unrealize((MMHandleType)player);
7025 _mmplayer_realize((MMHandleType)player);
7027 _mmplayer_set_position((MMHandleType)player, position);
7029 /* async not to be blocked in streaming case */
7030 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7032 _mmplayer_pause((MMHandleType)player);
7034 if (current_state == MM_PLAYER_STATE_PLAYING)
7035 _mmplayer_start((MMHandleType)player);
7036 MMPLAYER_CMD_UNLOCK(player);
7038 LOGD("rebuilding audio pipeline is completed.");
7041 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7043 mmplayer_t *player = (mmplayer_t *)user_data;
7044 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7045 gboolean is_supportable = FALSE;
7047 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7048 LOGW("failed to get device type");
7050 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7052 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7053 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7054 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7055 LOGD("ignore this dev connected info");
7059 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7060 if (player->build_audio_offload == is_supportable) {
7061 LOGD("keep current pipeline without re-building");
7065 /* rebuild pipeline */
7066 LOGD("re-build pipeline - offload: %d", is_supportable);
7067 player->build_audio_offload = FALSE;
7068 __mmplayer_rebuild_audio_pipeline(player);
7074 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7076 unsigned int id = 0;
7078 if (player->audio_device_cb_id != 0) {
7079 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7083 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7084 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7085 LOGD("added device connected cb (%u)", id);
7086 player->audio_device_cb_id = id;
7088 LOGW("failed to add device connected cb");
7095 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7097 mmplayer_t *player = (mmplayer_t *)hplayer;
7100 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7101 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7103 *activated = player->build_audio_offload;
7105 LOGD("offload activated : %d", (int)*activated);
7108 return MM_ERROR_NONE;
7112 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7115 this function need to be updated according to the supported media format
7116 @see player->ini.audio_offload_media_format */
7118 if (__mmplayer_is_only_mp3_type(player->type)) {
7119 LOGD("offload supportable media format type");
7127 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7129 gboolean ret = FALSE;
7130 GstElementFactory *factory = NULL;
7133 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7135 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7136 if (!__mmplayer_is_offload_supported_type(player))
7139 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7140 LOGD("there is no audio offload sink");
7144 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7145 LOGW("there is no audio device type to support offload");
7149 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7151 LOGW("there is no installed audio offload sink element");
7154 gst_object_unref(factory);
7156 if (_mmplayer_acquire_hw_resource(player,
7157 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7158 LOGE("failed to acquire audio offload decoder resource");
7162 if (!__mmplayer_add_audio_device_connected_cb(player))
7165 if (!__mmplayer_is_audio_offload_device_type(player))
7168 LOGD("audio offload can be built");
7173 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7179 static GstAutoplugSelectResult
7180 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7182 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7183 int audio_offload = 0;
7185 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7186 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7188 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7189 LOGD("expose audio path to build offload output path");
7190 player->build_audio_offload = TRUE;
7191 /* update codec info */
7192 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7193 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7194 player->audiodec_linked = 1;
7196 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7200 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7201 And need to consider the multi-track audio content.
7202 There is no HW audio decoder in public. */
7204 /* set stream information */
7205 if (!player->audiodec_linked)
7206 _mmplayer_set_audio_attrs(player, caps);
7208 /* update codec info */
7209 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7210 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7211 player->audiodec_linked = 1;
7213 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7215 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7216 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7218 /* mark video decoder for acquire */
7219 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7220 LOGW("video decoder resource is already acquired, skip it.");
7221 ret = GST_AUTOPLUG_SELECT_SKIP;
7225 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7226 LOGE("failed to acquire video decoder resource");
7227 ret = GST_AUTOPLUG_SELECT_SKIP;
7230 player->interrupted_by_resource = FALSE;
7233 /* update codec info */
7234 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7235 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7236 player->videodec_linked = 1;
7244 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7245 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7247 #define DEFAULT_IDX 0xFFFF
7248 #define MIN_FACTORY_NUM 2
7249 mmplayer_t *player = (mmplayer_t *)data;
7250 GValueArray *new_factories = NULL;
7251 GValue val = { 0, };
7252 GstElementFactory *factory = NULL;
7253 const gchar *klass = NULL;
7254 gchar *factory_name = NULL;
7255 guint hw_dec_idx = DEFAULT_IDX;
7256 guint first_sw_dec_idx = DEFAULT_IDX;
7257 guint last_sw_dec_idx = DEFAULT_IDX;
7258 guint new_pos = DEFAULT_IDX;
7259 guint rm_pos = DEFAULT_IDX;
7260 int audio_codec_type;
7261 int video_codec_type;
7262 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7264 if (factories->n_values < MIN_FACTORY_NUM)
7267 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7268 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7271 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7273 for (int i = 0 ; i < factories->n_values ; i++) {
7274 gchar *hw_dec_info = NULL;
7275 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7277 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7279 LOGW("failed to get factory object");
7282 klass = gst_element_factory_get_klass(factory);
7283 factory_name = GST_OBJECT_NAME(factory);
7286 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7288 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7289 if (!player->need_audio_dec_sorting) {
7290 LOGD("sorting is not required");
7293 codec_type = audio_codec_type;
7294 hw_dec_info = player->ini.audiocodec_element_hw;
7295 sw_dec_info = player->ini.audiocodec_element_sw;
7296 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7297 if (!player->need_video_dec_sorting) {
7298 LOGD("sorting is not required");
7301 codec_type = video_codec_type;
7302 hw_dec_info = player->ini.videocodec_element_hw;
7303 sw_dec_info = player->ini.videocodec_element_sw;
7308 if (g_strrstr(factory_name, hw_dec_info)) {
7311 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7312 if (strstr(factory_name, sw_dec_info[j])) {
7313 last_sw_dec_idx = i;
7314 if (first_sw_dec_idx == DEFAULT_IDX) {
7315 first_sw_dec_idx = i;
7320 if (first_sw_dec_idx == DEFAULT_IDX)
7321 LOGW("unknown codec %s", factory_name);
7325 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7328 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7329 if (hw_dec_idx < first_sw_dec_idx)
7331 new_pos = first_sw_dec_idx;
7332 rm_pos = hw_dec_idx + 1;
7333 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7334 if (last_sw_dec_idx < hw_dec_idx)
7336 new_pos = last_sw_dec_idx + 1;
7337 rm_pos = hw_dec_idx;
7342 /* change position - insert H/W decoder according to the new position */
7343 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7345 LOGW("failed to get factory object");
7348 new_factories = g_value_array_copy(factories);
7349 g_value_init (&val, G_TYPE_OBJECT);
7350 g_value_set_object (&val, factory);
7351 g_value_array_insert(new_factories, new_pos, &val);
7352 g_value_unset (&val);
7353 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7355 for (int i = 0 ; i < new_factories->n_values ; i++) {
7356 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7358 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7359 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7361 LOGE("[Re-arranged] failed to get factory object");
7364 return new_factories;
7368 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7369 GstCaps *caps, GstElementFactory *factory, gpointer data)
7371 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7372 mmplayer_t *player = (mmplayer_t *)data;
7374 gchar *factory_name = NULL;
7375 gchar *caps_str = NULL;
7376 const gchar *klass = NULL;
7379 factory_name = GST_OBJECT_NAME(factory);
7380 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7381 caps_str = gst_caps_to_string(caps);
7383 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7385 /* store type string */
7386 if (player->type == NULL) {
7387 player->type = gst_caps_to_string(caps);
7388 __mmplayer_update_content_type_info(player);
7391 /* filtering exclude keyword */
7392 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7393 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7394 LOGW("skipping [%s] by exclude keyword [%s]",
7395 factory_name, player->ini.exclude_element_keyword[idx]);
7397 result = GST_AUTOPLUG_SELECT_SKIP;
7402 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7403 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7404 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7405 factory_name, player->ini.unsupported_codec_keyword[idx]);
7406 result = GST_AUTOPLUG_SELECT_SKIP;
7411 /* exclude webm format */
7412 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7413 * because webm format is not supportable.
7414 * If webm is disabled in "autoplug-continue", there is no state change
7415 * failure or error because the decodebin will expose the pad directly.
7416 * It make MSL invoke _prepare_async_callback.
7417 * So, we need to disable webm format in "autoplug-select" */
7418 if (caps_str && strstr(caps_str, "webm")) {
7419 LOGW("webm is not supported");
7420 result = GST_AUTOPLUG_SELECT_SKIP;
7424 /* check factory class for filtering */
7425 /* NOTE : msl don't need to use image plugins.
7426 * So, those plugins should be skipped for error handling.
7428 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7429 LOGD("skipping [%s] by not required", factory_name);
7430 result = GST_AUTOPLUG_SELECT_SKIP;
7434 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7435 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7436 // TO CHECK : subtitle if needed, add subparse exception.
7437 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7438 result = GST_AUTOPLUG_SELECT_SKIP;
7442 if (g_strrstr(factory_name, "mpegpsdemux")) {
7443 LOGD("skipping PS container - not support");
7444 result = GST_AUTOPLUG_SELECT_SKIP;
7448 if (g_strrstr(factory_name, "mssdemux"))
7449 player->smooth_streaming = TRUE;
7451 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7452 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7455 GstStructure *str = NULL;
7456 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7458 /* don't make video because of not required */
7459 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7460 (!player->set_mode.video_export)) {
7461 LOGD("no need video decoding, expose pad");
7462 result = GST_AUTOPLUG_SELECT_EXPOSE;
7466 /* get w/h for omx state-tune */
7467 /* FIXME: deprecated? */
7468 str = gst_caps_get_structure(caps, 0);
7469 gst_structure_get_int(str, "width", &width);
7472 if (player->v_stream_caps) {
7473 gst_caps_unref(player->v_stream_caps);
7474 player->v_stream_caps = NULL;
7477 player->v_stream_caps = gst_caps_copy(caps);
7478 LOGD("take caps for video state tune");
7479 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7483 if (g_strrstr(klass, "Codec/Decoder")) {
7484 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7485 if (result != GST_AUTOPLUG_SELECT_TRY) {
7486 LOGW("skip add decoder");
7492 MMPLAYER_FREEIF(caps_str);
7498 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7501 int ret = MM_ERROR_NONE;
7502 mmplayer_t *player = (mmplayer_t *)data;
7503 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7504 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7505 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7508 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7510 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7512 if (MMPLAYER_USE_DECODEBIN(player))
7515 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7518 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7520 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7521 LOGE("failed to remove videobin");
7524 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7525 LOGE("failed to remove video concat");
7528 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL, FALSE, timeout);
7529 if (ret != MM_ERROR_NONE) {
7530 LOGE("fail to change state to NULL");
7534 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst, GST_STATE_NULL, FALSE, timeout);
7535 if (ret != MM_ERROR_NONE) {
7536 LOGE("fail to change state to NULL");
7540 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7541 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7542 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7544 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7545 MMPLAYER_FREEIF(player->pipeline->videobin);
7547 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7548 if (ret != MM_ERROR_NONE)
7549 LOGE("failed to release overlay resources");
7551 player->videodec_linked = 0;
7553 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7558 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7560 mmplayer_t *player = (mmplayer_t *)data;
7563 MMPLAYER_RETURN_IF_FAIL(player);
7565 LOGD("got about to finish signal");
7567 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7568 LOGW("Fail to get cmd lock");
7572 if (!__mmplayer_verify_gapless_play_path(player)) {
7573 LOGD("decoding is finished.");
7574 MMPLAYER_CMD_UNLOCK(player);
7578 _mmplayer_set_reconfigure_state(player, TRUE);
7579 MMPLAYER_CMD_UNLOCK(player);
7581 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7582 __mmplayer_deactivate_old_path(player);
7588 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7590 mmplayer_t *player = (mmplayer_t *)data;
7591 GstIterator *iter = NULL;
7592 GValue item = { 0, };
7594 gboolean done = FALSE;
7595 gboolean is_all_drained = TRUE;
7598 MMPLAYER_RETURN_IF_FAIL(player);
7600 LOGD("got drained signal");
7602 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7603 LOGW("Fail to get cmd lock");
7607 if (!__mmplayer_verify_gapless_play_path(player)) {
7608 LOGD("decoding is finished.");
7609 MMPLAYER_CMD_UNLOCK(player);
7613 _mmplayer_set_reconfigure_state(player, TRUE);
7614 MMPLAYER_CMD_UNLOCK(player);
7616 /* check decodebin src pads whether they received EOS or not */
7617 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7620 switch (gst_iterator_next(iter, &item)) {
7621 case GST_ITERATOR_OK:
7622 pad = g_value_get_object(&item);
7623 if (pad && !GST_PAD_IS_EOS(pad)) {
7624 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7625 is_all_drained = FALSE;
7628 g_value_reset(&item);
7630 case GST_ITERATOR_RESYNC:
7631 gst_iterator_resync(iter);
7633 case GST_ITERATOR_ERROR:
7634 case GST_ITERATOR_DONE:
7639 g_value_unset(&item);
7640 gst_iterator_free(iter);
7642 if (!is_all_drained) {
7643 LOGD("Wait util the all pads get EOS.");
7648 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7649 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7651 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7652 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7653 __mmplayer_deactivate_old_path(player);
7659 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7661 mmplayer_t *player = (mmplayer_t *)data;
7662 const gchar *klass = NULL;
7663 gchar *factory_name = NULL;
7665 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7666 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7668 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7670 if (__mmplayer_add_dump_buffer_probe(player, element))
7671 LOGD("add buffer probe");
7673 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7674 gchar *selected = NULL;
7675 selected = g_strdup(GST_ELEMENT_NAME(element));
7676 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7678 /* update codec info */
7679 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7680 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7681 player->audiodec_linked = 1;
7682 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7683 /* update codec info */
7684 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7685 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7686 player->videodec_linked = 1;
7689 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7690 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7691 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7693 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7694 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7696 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7697 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7698 "max-video-width", player->adaptive_info.limit.width,
7699 "max-video-height", player->adaptive_info.limit.height, NULL);
7701 } else if (g_strrstr(klass, "Demuxer")) {
7703 LOGD("plugged element is demuxer. take it");
7705 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7706 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7707 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7708 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7709 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7712 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7713 int surface_type = 0;
7715 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7718 // to support trust-zone only
7719 if (g_strrstr(factory_name, "asfdemux")) {
7720 LOGD("set file-location %s", player->profile.uri);
7721 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7722 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7723 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7724 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7725 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7726 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7727 (__mmplayer_is_only_mp3_type(player->type))) {
7728 LOGD("[mpegaudioparse] set streaming pull mode.");
7729 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7731 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7732 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7733 } else if (g_strrstr(factory_name, "omxdec_h264")) {
7734 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7735 if (video_parse && (g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7736 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7737 LOGD("Send SPS and PPS Insertion every IDR frame");
7741 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7742 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7743 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7745 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7746 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7748 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7749 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7750 (MMPLAYER_IS_DASH_STREAMING(player))) {
7751 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7752 _mm_player_streaming_set_multiqueue(player->streamer, element);
7753 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7762 __mmplayer_release_misc(mmplayer_t *player)
7765 bool cur_mode = player->set_mode.rich_audio;
7768 MMPLAYER_RETURN_IF_FAIL(player);
7770 player->sent_bos = FALSE;
7771 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7773 player->seek_state = MMPLAYER_SEEK_NONE;
7775 player->total_bitrate = 0;
7776 player->total_maximum_bitrate = 0;
7778 player->not_found_demuxer = 0;
7780 player->last_position = 0;
7781 player->duration = 0;
7782 player->http_content_size = 0;
7783 player->not_supported_codec = MISSING_PLUGIN_NONE;
7784 player->can_support_codec = FOUND_PLUGIN_NONE;
7785 player->pending_seek.is_pending = false;
7786 player->pending_seek.pos = 0;
7787 player->msg_posted = FALSE;
7788 player->has_many_types = FALSE;
7789 player->is_subtitle_force_drop = FALSE;
7790 player->play_subtitle = FALSE;
7791 player->adjust_subtitle_pos = 0;
7792 player->has_closed_caption = FALSE;
7793 player->set_mode.video_export = false;
7794 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7795 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7797 player->set_mode.rich_audio = cur_mode;
7799 if (player->audio_device_cb_id > 0 &&
7800 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7801 LOGW("failed to remove audio device_connected_callback");
7802 player->audio_device_cb_id = 0;
7804 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7805 player->bitrate[i] = 0;
7806 player->maximum_bitrate[i] = 0;
7809 /* free memory related to audio effect */
7810 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7812 if (player->adaptive_info.var_list) {
7813 g_list_free_full(player->adaptive_info.var_list, g_free);
7814 player->adaptive_info.var_list = NULL;
7817 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7818 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7819 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7821 /* Reset video360 settings to their defaults in case if the pipeline is to be
7824 player->video360_metadata.is_spherical = -1;
7825 player->is_openal_plugin_used = FALSE;
7827 player->is_content_spherical = FALSE;
7828 player->is_video360_enabled = TRUE;
7829 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7830 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7831 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7832 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7833 player->video360_zoom = 1.0f;
7834 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7835 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7837 player->sound.rg_enable = false;
7839 __mmplayer_initialize_video_roi(player);
7844 __mmplayer_release_misc_post(mmplayer_t *player)
7846 gchar *original_uri = NULL;
7849 /* player->pipeline is already released before. */
7850 MMPLAYER_RETURN_IF_FAIL(player);
7852 player->video_decoded_cb = NULL;
7853 player->video_decoded_cb_user_param = NULL;
7854 player->video_stream_prerolled = false;
7856 player->audio_decoded_cb = NULL;
7857 player->audio_decoded_cb_user_param = NULL;
7858 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7860 player->audio_stream_changed_cb = NULL;
7861 player->audio_stream_changed_cb_user_param = NULL;
7863 mm_player_set_attribute((MMHandleType)player, NULL,
7864 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7866 /* clean found audio decoders */
7867 if (player->audio_decoders) {
7868 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7869 player->audio_decoders = NULL;
7872 /* clean the uri list except original uri */
7873 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7875 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7876 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7877 g_list_free_full(tmp, (GDestroyNotify)g_free);
7880 LOGW("failed to get original uri info");
7882 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7883 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7884 MMPLAYER_FREEIF(original_uri);
7887 /* clear the audio stream buffer list */
7888 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7890 /* clear the video stream bo list */
7891 __mmplayer_video_stream_destroy_bo_list(player);
7892 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7894 if (player->profile.input_mem.buf) {
7895 free(player->profile.input_mem.buf);
7896 player->profile.input_mem.buf = NULL;
7898 player->profile.input_mem.len = 0;
7899 player->profile.input_mem.offset = 0;
7901 player->uri_info.uri_idx = 0;
7906 __mmplayer_check_subtitle(mmplayer_t *player)
7908 MMHandleType attrs = 0;
7909 char *subtitle_uri = NULL;
7913 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7915 /* get subtitle attribute */
7916 attrs = MMPLAYER_GET_ATTRS(player);
7920 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7921 if (!subtitle_uri || !strlen(subtitle_uri))
7924 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7925 player->is_external_subtitle_present = TRUE;
7933 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7935 MMPLAYER_RETURN_IF_FAIL(player);
7937 if (player->eos_timer) {
7938 LOGD("cancel eos timer");
7939 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7940 player->eos_timer = 0;
7947 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7951 MMPLAYER_RETURN_IF_FAIL(player);
7952 MMPLAYER_RETURN_IF_FAIL(sink);
7955 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7957 player->sink_elements = g_list_append(player->sink_elements, sink);
7963 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7967 MMPLAYER_RETURN_IF_FAIL(player);
7968 MMPLAYER_RETURN_IF_FAIL(sink);
7970 player->sink_elements = g_list_remove(player->sink_elements, sink);
7976 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7977 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7979 mmplayer_signal_item_t *item = NULL;
7982 MMPLAYER_RETURN_IF_FAIL(player);
7984 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7985 LOGE("invalid signal type [%d]", type);
7989 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7991 LOGE("cannot connect signal [%s]", signal);
7996 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7997 player->signals[type] = g_list_append(player->signals[type], item);
8003 /* NOTE : be careful with calling this api. please refer to below glib comment
8004 * glib comment : Note that there is a bug in GObject that makes this function much
8005 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8006 * will no longer be called, but, the signal handler is not currently disconnected.
8007 * If the instance is itself being freed at the same time than this doesn't matter,
8008 * since the signal will automatically be removed, but if instance persists,
8009 * then the signal handler will leak. You should not remove the signal yourself
8010 * because in a future versions of GObject, the handler will automatically be
8013 * It's possible to work around this problem in a way that will continue to work
8014 * with future versions of GObject by checking that the signal handler is still
8015 * connected before disconnected it:
8017 * if (g_signal_handler_is_connected(instance, id))
8018 * g_signal_handler_disconnect(instance, id);
8021 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8023 GList *sig_list = NULL;
8024 mmplayer_signal_item_t *item = NULL;
8028 MMPLAYER_RETURN_IF_FAIL(player);
8030 LOGD("release signals type : %d", type);
8032 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8033 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8034 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8035 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8036 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8037 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8041 sig_list = player->signals[type];
8043 for (; sig_list; sig_list = sig_list->next) {
8044 item = sig_list->data;
8046 if (item && item->obj) {
8047 if (g_signal_handler_is_connected(item->obj, item->sig))
8048 g_signal_handler_disconnect(item->obj, item->sig);
8051 MMPLAYER_FREEIF(item);
8054 g_list_free(player->signals[type]);
8055 player->signals[type] = NULL;
8063 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8065 mmplayer_t *player = 0;
8066 int prev_display_surface_type = 0;
8070 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8072 player = MM_PLAYER_CAST(handle);
8074 /* check video sinkbin is created */
8075 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8076 LOGW("Videosink is already created");
8077 return MM_ERROR_NONE;
8080 LOGD("videosink element is not yet ready");
8082 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8083 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8085 return MM_ERROR_INVALID_ARGUMENT;
8088 /* load previous attributes */
8089 if (player->attrs) {
8090 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8091 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8092 if (prev_display_surface_type == surface_type) {
8093 LOGD("incoming display surface type is same as previous one, do nothing..");
8095 return MM_ERROR_NONE;
8098 LOGE("failed to load attributes");
8100 return MM_ERROR_PLAYER_INTERNAL;
8103 /* videobin is not created yet, so we just set attributes related to display surface */
8104 LOGD("store display attribute for given surface type(%d)", surface_type);
8105 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8106 "display_overlay", wl_surface_id, NULL);
8109 return MM_ERROR_NONE;
8112 /* Note : if silent is true, then subtitle would not be displayed. :*/
8114 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8116 mmplayer_t *player = (mmplayer_t *)hplayer;
8120 /* check player handle */
8121 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8123 player->set_mode.subtitle_off = silent;
8125 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8129 return MM_ERROR_NONE;
8133 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8135 mmplayer_gst_element_t *mainbin = NULL;
8136 mmplayer_gst_element_t *textbin = NULL;
8137 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8138 GstState current_state = GST_STATE_VOID_PENDING;
8139 GstState element_state = GST_STATE_VOID_PENDING;
8140 GstState element_pending_state = GST_STATE_VOID_PENDING;
8142 GstEvent *event = NULL;
8143 int result = MM_ERROR_NONE;
8145 GstClock *curr_clock = NULL;
8146 GstClockTime base_time, start_time, curr_time;
8151 /* check player handle */
8152 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8154 player->pipeline->mainbin &&
8155 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8157 mainbin = player->pipeline->mainbin;
8158 textbin = player->pipeline->textbin;
8160 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8162 // sync clock with current pipeline
8163 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8164 curr_time = gst_clock_get_time(curr_clock);
8166 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8167 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8169 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8170 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8172 if (current_state > GST_STATE_READY) {
8173 // sync state with current pipeline
8174 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8175 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8176 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8178 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8179 if (GST_STATE_CHANGE_FAILURE == ret) {
8180 LOGE("fail to state change.");
8181 result = MM_ERROR_PLAYER_INTERNAL;
8185 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8186 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8189 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8190 gst_object_unref(curr_clock);
8193 // seek to current position
8194 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8195 result = MM_ERROR_PLAYER_INVALID_STATE;
8196 LOGE("gst_element_query_position failed, invalid state");
8200 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8201 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);
8203 _mmplayer_gst_send_event_to_sink(player, event);
8205 result = MM_ERROR_PLAYER_INTERNAL;
8206 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8210 /* sync state with current pipeline */
8211 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8212 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8213 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8215 return MM_ERROR_NONE;
8218 /* release text pipeline resource */
8219 player->textsink_linked = 0;
8221 /* release signal */
8222 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8224 /* release textbin with it's children */
8225 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8226 MMPLAYER_FREEIF(player->pipeline->textbin);
8227 player->pipeline->textbin = NULL;
8229 /* release subtitle elem */
8230 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8231 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8237 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8239 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8240 GstState current_state = GST_STATE_VOID_PENDING;
8242 MMHandleType attrs = 0;
8243 mmplayer_gst_element_t *mainbin = NULL;
8244 mmplayer_gst_element_t *textbin = NULL;
8246 gchar *subtitle_uri = NULL;
8247 int result = MM_ERROR_NONE;
8248 const gchar *charset = NULL;
8252 /* check player handle */
8253 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8255 player->pipeline->mainbin &&
8256 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8257 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8259 mainbin = player->pipeline->mainbin;
8260 textbin = player->pipeline->textbin;
8262 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8263 if (current_state < GST_STATE_READY) {
8264 result = MM_ERROR_PLAYER_INVALID_STATE;
8265 LOGE("Pipeline is not in proper state");
8269 attrs = MMPLAYER_GET_ATTRS(player);
8271 LOGE("cannot get content attribute");
8272 result = MM_ERROR_PLAYER_INTERNAL;
8276 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8277 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8278 LOGE("subtitle uri is not proper filepath");
8279 result = MM_ERROR_PLAYER_INVALID_URI;
8283 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8284 LOGE("failed to get storage info of subtitle path");
8285 result = MM_ERROR_PLAYER_INVALID_URI;
8289 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8290 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8292 if (!strcmp(filepath, subtitle_uri)) {
8293 LOGD("subtitle path is not changed");
8296 if (mm_player_set_attribute((MMHandleType)player, NULL,
8297 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8298 LOGE("failed to set attribute");
8303 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8304 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8305 player->subtitle_language_list = NULL;
8306 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8308 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8309 if (ret != GST_STATE_CHANGE_SUCCESS) {
8310 LOGE("failed to change state of textbin to READY");
8311 result = MM_ERROR_PLAYER_INTERNAL;
8315 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8316 if (ret != GST_STATE_CHANGE_SUCCESS) {
8317 LOGE("failed to change state of subparse to READY");
8318 result = MM_ERROR_PLAYER_INTERNAL;
8322 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8323 if (ret != GST_STATE_CHANGE_SUCCESS) {
8324 LOGE("failed to change state of filesrc to READY");
8325 result = MM_ERROR_PLAYER_INTERNAL;
8329 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8331 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8333 charset = _mmplayer_get_charset(filepath);
8335 LOGD("detected charset is %s", charset);
8336 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8339 result = _mmplayer_sync_subtitle_pipeline(player);
8346 /* API to switch between external subtitles */
8348 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8350 int result = MM_ERROR_NONE;
8351 mmplayer_t *player = (mmplayer_t *)hplayer;
8356 /* check player handle */
8357 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8359 /* filepath can be null in idle state */
8361 /* check file path */
8362 if ((path = strstr(filepath, "file://")))
8363 result = _mmplayer_exist_file_path(path + 7);
8365 result = _mmplayer_exist_file_path(filepath);
8367 if (result != MM_ERROR_NONE) {
8368 LOGE("invalid subtitle path 0x%X", result);
8369 return result; /* file not found or permission denied */
8373 if (!player->pipeline) {
8375 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8376 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8377 LOGE("failed to set attribute");
8378 return MM_ERROR_PLAYER_INTERNAL;
8381 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8382 /* check filepath */
8383 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8385 if (!__mmplayer_check_subtitle(player)) {
8386 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8387 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8388 LOGE("failed to set attribute");
8389 return MM_ERROR_PLAYER_INTERNAL;
8392 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8393 LOGE("fail to create text pipeline");
8394 return MM_ERROR_PLAYER_INTERNAL;
8397 result = _mmplayer_sync_subtitle_pipeline(player);
8399 result = __mmplayer_change_external_subtitle_language(player, filepath);
8402 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8403 player->is_external_subtitle_added_now = TRUE;
8405 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8406 if (!player->subtitle_language_list) {
8407 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8408 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8409 LOGW("subtitle language list is not updated yet");
8411 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8419 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8421 guint active_idx = 0;
8422 GstStream *stream = NULL;
8423 GList *streams = NULL;
8424 GstCaps *caps = NULL;
8427 LOGD("Switching Streams... type: %d, index: %d", type, index);
8429 player->track[type].active_track_index = index;
8431 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8432 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8433 LOGD("track type:%d, total: %d, active: %d", i,
8434 player->track[i].total_track_num, player->track[i].active_track_index);
8435 if (player->track[i].total_track_num > 0 &&
8436 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8437 active_idx = player->track[i].active_track_index;
8438 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8439 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8440 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8442 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8443 caps = gst_stream_get_caps(stream);
8445 _mmplayer_set_audio_attrs(player, caps);
8446 gst_caps_unref(caps);
8453 LOGD("send select stream event");
8454 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8455 gst_event_new_select_streams(streams));
8456 g_list_free(streams);
8460 return MM_ERROR_NONE;
8464 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8466 int result = MM_ERROR_NONE;
8467 gchar *change_pad_name = NULL;
8468 GstPad *sinkpad = NULL;
8469 mmplayer_gst_element_t *mainbin = NULL;
8470 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8471 GstCaps *caps = NULL;
8472 gint total_track_num = 0;
8476 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8477 MM_ERROR_PLAYER_NOT_INITIALIZED);
8479 LOGD("Change Track(%d) to %d", type, index);
8481 mainbin = player->pipeline->mainbin;
8483 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8484 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8485 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8486 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8488 /* Changing Video Track is not supported. */
8489 LOGE("Track Type Error");
8493 if (mainbin[elem_idx].gst == NULL) {
8494 result = MM_ERROR_PLAYER_NO_OP;
8495 LOGD("Req track doesn't exist");
8499 total_track_num = player->track[type].total_track_num;
8500 if (total_track_num <= 0) {
8501 result = MM_ERROR_PLAYER_NO_OP;
8502 LOGD("Language list is not available");
8506 if ((index < 0) || (index >= total_track_num)) {
8507 result = MM_ERROR_INVALID_ARGUMENT;
8508 LOGD("Not a proper index : %d", index);
8512 /*To get the new pad from the selector*/
8513 change_pad_name = g_strdup_printf("sink_%u", index);
8514 if (change_pad_name == NULL) {
8515 result = MM_ERROR_PLAYER_INTERNAL;
8516 LOGD("Pad does not exists");
8520 LOGD("new active pad name: %s", change_pad_name);
8522 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8523 if (sinkpad == NULL) {
8524 LOGD("sinkpad is NULL");
8525 result = MM_ERROR_PLAYER_INTERNAL;
8529 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8530 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8532 caps = gst_pad_get_current_caps(sinkpad);
8533 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8536 gst_object_unref(sinkpad);
8538 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8539 _mmplayer_set_audio_attrs(player, caps);
8542 gst_caps_unref(caps);
8545 MMPLAYER_FREEIF(change_pad_name);
8550 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8552 int result = MM_ERROR_NONE;
8553 mmplayer_t *player = NULL;
8554 mmplayer_gst_element_t *mainbin = NULL;
8556 gint current_active_index = 0;
8558 GstState current_state = GST_STATE_VOID_PENDING;
8563 player = (mmplayer_t *)hplayer;
8564 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8566 if (!player->pipeline) {
8567 LOGE("Track %d pre setting -> %d", type, index);
8569 player->track[type].active_track_index = index;
8573 mainbin = player->pipeline->mainbin;
8575 current_active_index = player->track[type].active_track_index;
8577 /*If index is same as running index no need to change the pad*/
8578 if (current_active_index == index)
8581 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8582 result = MM_ERROR_PLAYER_INVALID_STATE;
8586 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8587 if (current_state < GST_STATE_PAUSED) {
8588 result = MM_ERROR_PLAYER_INVALID_STATE;
8589 LOGW("Pipeline not in proper state");
8593 if (MMPLAYER_USE_DECODEBIN(player))
8594 result = __mmplayer_change_selector_pad(player, type, index);
8596 result = __mmplayer_switch_stream(player, type, index);
8598 if (result != MM_ERROR_NONE) {
8599 LOGE("failed to change track");
8603 player->track[type].active_track_index = index;
8605 if (MMPLAYER_USE_DECODEBIN(player)) {
8606 GstEvent *event = NULL;
8607 if (current_state == GST_STATE_PLAYING) {
8608 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8609 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8610 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8612 _mmplayer_gst_send_event_to_sink(player, event);
8614 result = MM_ERROR_PLAYER_INTERNAL;
8625 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8627 mmplayer_t *player = (mmplayer_t *)hplayer;
8631 /* check player handle */
8632 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8634 *silent = player->set_mode.subtitle_off;
8636 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8640 return MM_ERROR_NONE;
8644 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8646 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8647 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8649 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8650 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8654 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8655 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8656 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8657 mmplayer_dump_t *dump_s;
8658 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8659 if (dump_s == NULL) {
8660 LOGE("malloc fail");
8664 dump_s->dump_element_file = NULL;
8665 dump_s->dump_pad = NULL;
8666 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8668 if (dump_s->dump_pad) {
8669 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8670 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]);
8671 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8672 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);
8673 /* add list for removed buffer probe and close FILE */
8674 player->dump_list = g_list_append(player->dump_list, dump_s);
8675 LOGD("%s sink pad added buffer probe for dump", factory_name);
8678 MMPLAYER_FREEIF(dump_s);
8679 LOGE("failed to get %s sink pad added", factory_name);
8686 static GstPadProbeReturn
8687 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8689 FILE *dump_data = (FILE *)u_data;
8691 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8692 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8694 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8696 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8698 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8700 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8702 gst_buffer_unmap(buffer, &probe_info);
8704 return GST_PAD_PROBE_OK;
8708 __mmplayer_release_dump_list(GList *dump_list)
8710 GList *d_list = dump_list;
8715 for (; d_list; d_list = g_list_next(d_list)) {
8716 mmplayer_dump_t *dump_s = d_list->data;
8717 if (dump_s->dump_pad) {
8718 if (dump_s->probe_handle_id)
8719 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8720 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8722 if (dump_s->dump_element_file) {
8723 fclose(dump_s->dump_element_file);
8724 dump_s->dump_element_file = NULL;
8726 MMPLAYER_FREEIF(dump_s);
8728 g_list_free(dump_list);
8733 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8735 mmplayer_t *player = (mmplayer_t *)hplayer;
8739 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8740 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8742 *exist = (bool)player->has_closed_caption;
8746 return MM_ERROR_NONE;
8750 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8755 LOGD("unref internal gst buffer %p", buffer);
8757 gst_buffer_unref((GstBuffer *)buffer);
8764 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8766 mmplayer_t *player = (mmplayer_t *)hplayer;
8770 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8771 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8773 if (MMPLAYER_IS_STREAMING(player))
8774 *timeout = (int)player->ini.live_state_change_timeout;
8776 *timeout = (int)player->ini.localplayback_state_change_timeout;
8778 LOGD("timeout = %d", *timeout);
8781 return MM_ERROR_NONE;
8785 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8789 MMPLAYER_RETURN_IF_FAIL(player);
8791 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8793 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8794 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8795 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8796 player->storage_info[i].id = -1;
8797 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8799 if (path_type != MMPLAYER_PATH_MAX)
8808 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8810 int ret = MM_ERROR_NONE;
8811 mmplayer_t *player = (mmplayer_t *)hplayer;
8812 MMMessageParamType msg_param = {0, };
8815 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8817 LOGW("state changed storage %d:%d", id, state);
8819 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8820 return MM_ERROR_NONE;
8822 /* FIXME: text path should be handled separately. */
8823 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8824 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8825 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8826 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8827 LOGW("external storage is removed");
8829 if (player->msg_posted == FALSE) {
8830 memset(&msg_param, 0, sizeof(MMMessageParamType));
8831 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8832 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8833 player->msg_posted = TRUE;
8836 /* unrealize the player */
8837 ret = _mmplayer_unrealize(hplayer);
8838 if (ret != MM_ERROR_NONE)
8839 LOGE("failed to unrealize");
8847 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8849 int ret = MM_ERROR_NONE;
8850 mmplayer_t *player = (mmplayer_t *)hplayer;
8851 int idx = 0, total = 0;
8852 gchar *result = NULL, *tmp = NULL;
8855 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8856 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8858 total = *num = g_list_length(player->adaptive_info.var_list);
8860 LOGW("There is no stream variant info.");
8864 result = g_strdup("");
8865 for (idx = 0 ; idx < total ; idx++) {
8866 stream_variant_t *v_data = NULL;
8867 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8870 gchar data[64] = {0};
8871 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8873 tmp = g_strconcat(result, data, NULL);
8877 LOGW("There is no variant data in %d", idx);
8882 *var_info = (char *)result;
8884 LOGD("variant info %d:%s", *num, *var_info);
8890 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8892 int ret = MM_ERROR_NONE;
8893 mmplayer_t *player = (mmplayer_t *)hplayer;
8896 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8898 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8900 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8901 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8902 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8904 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8905 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8906 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8907 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8909 /* FIXME: seek to current position for applying new variant limitation */
8918 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8920 int ret = MM_ERROR_NONE;
8921 mmplayer_t *player = (mmplayer_t *)hplayer;
8924 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8925 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8927 *bandwidth = player->adaptive_info.limit.bandwidth;
8928 *width = player->adaptive_info.limit.width;
8929 *height = player->adaptive_info.limit.height;
8931 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8938 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8940 int ret = MM_ERROR_NONE;
8941 mmplayer_t *player = (mmplayer_t *)hplayer;
8944 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8945 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8946 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8948 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8950 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8951 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8952 else /* live case */
8953 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8955 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8962 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8964 #define IDX_FIRST_SW_CODEC 0
8965 mmplayer_t *player = (mmplayer_t *)hplayer;
8966 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8967 const char *attr_name = NULL;
8968 const char *default_type = NULL;
8969 const char *element_hw = NULL;
8970 const char *element_sw = NULL;
8973 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8975 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8977 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8978 switch (stream_type) {
8979 case MM_PLAYER_STREAM_TYPE_AUDIO:
8980 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8981 default_type = player->ini.audiocodec_default_type;
8982 element_hw = player->ini.audiocodec_element_hw;
8983 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8985 case MM_PLAYER_STREAM_TYPE_VIDEO:
8986 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8987 default_type = player->ini.videocodec_default_type;
8988 element_hw = player->ini.videocodec_element_hw;
8989 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8992 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8993 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8997 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8999 if (!strcmp(default_type, "sw"))
9000 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9002 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9004 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9005 codec_type = default_codec_type;
9007 /* to support codec selection, codec info have to be added in ini file.
9008 in case of hw codec is selected, filter elements should be applied
9009 depending on the hw capabilities. */
9010 if (codec_type != default_codec_type) {
9011 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9012 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9013 LOGE("There is no codec for type %d", codec_type);
9014 return MM_ERROR_PLAYER_NO_OP;
9017 LOGD("sorting is required");
9018 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9019 player->need_audio_dec_sorting = TRUE;
9021 player->need_video_dec_sorting = TRUE;
9024 LOGD("update %s codec_type to %d", attr_name, codec_type);
9025 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9028 return MM_ERROR_NONE;
9032 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9034 mmplayer_t *player = (mmplayer_t *)hplayer;
9035 GstElement *rg_vol_element = NULL;
9039 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9041 player->sound.rg_enable = enabled;
9043 /* just hold rgvolume enable value if pipeline is not ready */
9044 if (!player->pipeline || !player->pipeline->audiobin) {
9045 LOGD("pipeline is not ready. holding rgvolume enable value");
9046 return MM_ERROR_NONE;
9049 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9051 if (!rg_vol_element) {
9052 LOGD("rgvolume element is not created");
9053 return MM_ERROR_PLAYER_INTERNAL;
9057 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9059 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9063 return MM_ERROR_NONE;
9067 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9069 mmplayer_t *player = (mmplayer_t *)hplayer;
9070 GstElement *rg_vol_element = NULL;
9071 gboolean enable = FALSE;
9075 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9076 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9078 /* just hold enable_rg value if pipeline is not ready */
9079 if (!player->pipeline || !player->pipeline->audiobin) {
9080 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9081 *enabled = player->sound.rg_enable;
9082 return MM_ERROR_NONE;
9085 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9087 if (!rg_vol_element) {
9088 LOGD("rgvolume element is not created");
9089 return MM_ERROR_PLAYER_INTERNAL;
9092 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9093 *enabled = (bool)enable;
9097 return MM_ERROR_NONE;
9101 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9103 mmplayer_t *player = (mmplayer_t *)hplayer;
9104 MMHandleType attrs = 0;
9106 int ret = MM_ERROR_NONE;
9110 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9112 attrs = MMPLAYER_GET_ATTRS(player);
9113 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9115 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9117 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9118 return MM_ERROR_PLAYER_INTERNAL;
9121 player->video_roi.scale_x = scale_x;
9122 player->video_roi.scale_y = scale_y;
9123 player->video_roi.scale_width = scale_width;
9124 player->video_roi.scale_height = scale_height;
9126 /* check video sinkbin is created */
9127 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9128 return MM_ERROR_NONE;
9130 if (!gst_video_overlay_set_video_roi_area(
9131 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9132 scale_x, scale_y, scale_width, scale_height))
9133 ret = MM_ERROR_PLAYER_INTERNAL;
9135 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9136 scale_x, scale_y, scale_width, scale_height);
9144 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9146 mmplayer_t *player = (mmplayer_t *)hplayer;
9147 int ret = MM_ERROR_NONE;
9151 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9152 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9154 *scale_x = player->video_roi.scale_x;
9155 *scale_y = player->video_roi.scale_y;
9156 *scale_width = player->video_roi.scale_width;
9157 *scale_height = player->video_roi.scale_height;
9159 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9160 *scale_x, *scale_y, *scale_width, *scale_height);
9166 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9168 mmplayer_t *player = (mmplayer_t *)hplayer;
9172 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9174 player->client_pid = pid;
9176 LOGD("client pid[%d] %p", pid, player);
9180 return MM_ERROR_NONE;
9184 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9186 mmplayer_t *player = (mmplayer_t *)hplayer;
9187 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9188 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9192 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9193 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9196 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9198 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9200 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9201 return MM_ERROR_NONE;
9203 /* in case of audio codec default type is HW */
9205 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9206 if (player->ini.support_audio_effect)
9207 return MM_ERROR_NONE;
9208 elem_id = MMPLAYER_A_FILTER;
9210 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9211 if (player->ini.support_replaygain_control)
9212 return MM_ERROR_NONE;
9213 elem_id = MMPLAYER_A_RGVOL;
9215 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9216 if (player->ini.support_pitch_control)
9217 return MM_ERROR_NONE;
9218 elem_id = MMPLAYER_A_PITCH;
9220 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9221 if (player->ini.support_audio_effect)
9222 return MM_ERROR_NONE;
9224 /* default case handling is not required */
9227 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9228 LOGW("audio control option [%d] is not available", opt);
9231 /* setting pcm exporting option is allowed before READY state */
9232 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9233 return MM_ERROR_PLAYER_INVALID_STATE;
9235 /* check whether the audio filter exist or not after READY state,
9236 because the sw codec could be added during auto-plugging in some cases */
9237 if (!player->pipeline ||
9238 !player->pipeline->audiobin ||
9239 !player->pipeline->audiobin[elem_id].gst) {
9240 LOGW("there is no audio elem [%d]", elem_id);
9245 LOGD("audio control opt %d, available %d", opt, *available);
9249 return MM_ERROR_NONE;
9253 __mmplayer_update_duration_value(mmplayer_t *player)
9255 gboolean ret = FALSE;
9256 gint64 dur_nsec = 0;
9257 LOGD("try to update duration");
9259 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9260 player->duration = dur_nsec;
9261 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9265 if (player->duration < 0) {
9266 LOGW("duration is Non-Initialized !!!");
9267 player->duration = 0;
9270 /* update streaming service type */
9271 player->streaming_type = _mmplayer_get_stream_service_type(player);
9273 /* check duration is OK */
9274 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9275 /* FIXIT : find another way to get duration here. */
9276 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9282 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9284 /* update audio params
9285 NOTE : We need original audio params and it can be only obtained from src pad of audio
9286 decoder. Below code only valid when we are not using 'resampler' just before
9287 'audioconverter'. */
9288 GstCaps *caps_a = NULL;
9290 gint samplerate = 0, channels = 0;
9291 GstStructure *p = NULL;
9292 GstElement *aconv = NULL;
9294 LOGD("try to update audio attrs");
9296 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9298 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9299 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9300 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9301 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9303 LOGE("there is no audio converter");
9307 pad = gst_element_get_static_pad(aconv, "sink");
9310 LOGW("failed to get pad from audio converter");
9314 caps_a = gst_pad_get_current_caps(pad);
9316 LOGW("not ready to get audio caps");
9317 gst_object_unref(pad);
9321 p = gst_caps_get_structure(caps_a, 0);
9323 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9325 gst_structure_get_int(p, "rate", &samplerate);
9326 gst_structure_get_int(p, "channels", &channels);
9328 mm_player_set_attribute((MMHandleType)player, NULL,
9329 "content_audio_samplerate", samplerate,
9330 "content_audio_channels", channels, NULL);
9332 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9334 gst_caps_unref(caps_a);
9335 gst_object_unref(pad);
9341 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9343 LOGD("try to update video attrs");
9345 GstCaps *caps_v = NULL;
9349 GstStructure *p = NULL;
9351 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9352 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9354 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9356 LOGD("no videosink sink pad");
9360 caps_v = gst_pad_get_current_caps(pad);
9361 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9362 if (!caps_v && player->v_stream_caps) {
9363 caps_v = player->v_stream_caps;
9364 gst_caps_ref(caps_v);
9368 LOGD("no negotiated caps from videosink");
9369 gst_object_unref(pad);
9373 p = gst_caps_get_structure(caps_v, 0);
9374 gst_structure_get_int(p, "width", &width);
9375 gst_structure_get_int(p, "height", &height);
9377 mm_player_set_attribute((MMHandleType)player, NULL,
9378 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9380 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9382 SECURE_LOGD("width : %d height : %d", width, height);
9384 gst_caps_unref(caps_v);
9385 gst_object_unref(pad);
9388 mm_player_set_attribute((MMHandleType)player, NULL,
9389 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9390 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9397 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9399 gboolean ret = FALSE;
9400 guint64 data_size = 0;
9404 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9405 if (!player->duration)
9408 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9409 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9410 if (stat(path, &sb) == 0)
9411 data_size = (guint64)sb.st_size;
9413 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9414 data_size = player->http_content_size;
9417 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9420 guint64 bitrate = 0;
9421 guint64 msec_dur = 0;
9423 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9425 bitrate = data_size * 8 * 1000 / msec_dur;
9426 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9427 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9428 mm_player_set_attribute((MMHandleType)player, NULL,
9429 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9432 LOGD("player duration is less than 0");
9436 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9437 if (player->total_bitrate) {
9438 mm_player_set_attribute((MMHandleType)player, NULL,
9439 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9448 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9450 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9451 data->uri_type = uri_type;
9455 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9457 int ret = MM_ERROR_PLAYER_INVALID_URI;
9459 char *buffer = NULL;
9460 char *seperator = strchr(path, ',');
9461 char ext[100] = {0,}, size[100] = {0,};
9464 if ((buffer = strstr(path, "ext="))) {
9465 buffer += strlen("ext=");
9467 if (strlen(buffer)) {
9468 strncpy(ext, buffer, 99);
9470 if ((seperator = strchr(ext, ','))
9471 || (seperator = strchr(ext, ' '))
9472 || (seperator = strchr(ext, '\0'))) {
9473 seperator[0] = '\0';
9478 if ((buffer = strstr(path, "size="))) {
9479 buffer += strlen("size=");
9481 if (strlen(buffer) > 0) {
9482 strncpy(size, buffer, 99);
9484 if ((seperator = strchr(size, ','))
9485 || (seperator = strchr(size, ' '))
9486 || (seperator = strchr(size, '\0'))) {
9487 seperator[0] = '\0';
9490 mem_size = atoi(size);
9495 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9497 if (mem_size && param) {
9498 if (data->input_mem.buf)
9499 free(data->input_mem.buf);
9500 data->input_mem.buf = malloc(mem_size);
9502 if (data->input_mem.buf) {
9503 memcpy(data->input_mem.buf, param, mem_size);
9504 data->input_mem.len = mem_size;
9505 ret = MM_ERROR_NONE;
9507 LOGE("failed to alloc mem %d", mem_size);
9508 ret = MM_ERROR_PLAYER_INTERNAL;
9511 data->input_mem.offset = 0;
9512 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9519 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9521 gchar *location = NULL;
9524 int ret = MM_ERROR_NONE;
9526 if ((path = strstr(uri, "file://"))) {
9527 location = g_filename_from_uri(uri, NULL, &err);
9528 if (!location || (err != NULL)) {
9529 LOGE("Invalid URI '%s' for filesrc: %s", path,
9530 (err != NULL) ? err->message : "unknown error");
9534 MMPLAYER_FREEIF(location);
9536 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9537 return MM_ERROR_PLAYER_INVALID_URI;
9539 LOGD("path from uri: %s", location);
9542 path = (location != NULL) ? (location) : ((char *)uri);
9545 ret = _mmplayer_exist_file_path(path);
9547 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9548 if (ret == MM_ERROR_NONE) {
9549 if (_mmplayer_is_sdp_file(path)) {
9550 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9551 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9552 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9554 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9555 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9557 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9558 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9560 LOGE("invalid uri, could not play..");
9561 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9564 MMPLAYER_FREEIF(location);
9569 static mmplayer_video_decoded_data_info_t *
9570 __mmplayer_create_stream_from_pad(GstPad *pad)
9572 GstCaps *caps = NULL;
9573 GstStructure *structure = NULL;
9574 unsigned int fourcc = 0;
9575 const gchar *string_format = NULL;
9576 mmplayer_video_decoded_data_info_t *stream = NULL;
9578 MMPixelFormatType format;
9581 caps = gst_pad_get_current_caps(pad);
9583 LOGE("Caps is NULL.");
9588 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9590 structure = gst_caps_get_structure(caps, 0);
9591 gst_structure_get_int(structure, "width", &width);
9592 gst_structure_get_int(structure, "height", &height);
9593 string_format = gst_structure_get_string(structure, "format");
9596 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9597 format = _mmplayer_get_pixtype(fourcc);
9598 gst_video_info_from_caps(&info, caps);
9599 gst_caps_unref(caps);
9602 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9603 LOGE("Wrong condition!!");
9607 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9609 LOGE("failed to alloc mem for video data");
9613 stream->width = width;
9614 stream->height = height;
9615 stream->format = format;
9616 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9622 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9624 unsigned int pitch = 0;
9625 unsigned int size = 0;
9627 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9630 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9631 bo = gst_tizen_memory_get_bos(mem, index);
9633 stream->bo[index] = tbm_bo_ref(bo);
9635 LOGE("failed to get bo for index %d", index);
9638 for (index = 0; index < stream->plane_num; index++) {
9639 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9640 stream->stride[index] = pitch;
9642 stream->elevation[index] = size / pitch;
9644 stream->elevation[index] = stream->height;
9649 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9651 if (stream->format == MM_PIXEL_FORMAT_I420) {
9652 int ret = TBM_SURFACE_ERROR_NONE;
9653 tbm_surface_h surface;
9654 tbm_surface_info_s info;
9656 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9658 ret = tbm_surface_get_info(surface, &info);
9659 if (ret != TBM_SURFACE_ERROR_NONE) {
9660 tbm_surface_destroy(surface);
9664 tbm_surface_destroy(surface);
9665 stream->stride[0] = info.planes[0].stride;
9666 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9667 stream->stride[1] = info.planes[1].stride;
9668 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9669 stream->stride[2] = info.planes[2].stride;
9670 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9671 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9672 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9673 stream->stride[0] = stream->width * 4;
9674 stream->elevation[0] = stream->height;
9675 stream->bo_size = stream->stride[0] * stream->height;
9677 LOGE("Not support format %d", stream->format);
9685 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9687 tbm_bo_handle thandle;
9689 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9690 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9691 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9695 unsigned char *src = NULL;
9696 unsigned char *dest = NULL;
9697 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9699 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9701 LOGE("fail to gst_memory_map");
9705 if (!mapinfo.data) {
9706 LOGE("data pointer is wrong");
9710 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9711 if (!stream->bo[0]) {
9712 LOGE("Fail to tbm_bo_alloc!!");
9716 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9718 LOGE("thandle pointer is wrong");
9722 if (stream->format == MM_PIXEL_FORMAT_I420) {
9723 src_stride[0] = GST_ROUND_UP_4(stream->width);
9724 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9725 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9726 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9729 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9730 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9732 for (i = 0; i < 3; i++) {
9733 src = mapinfo.data + src_offset[i];
9734 dest = thandle.ptr + dest_offset[i];
9739 for (j = 0; j < stream->height >> k; j++) {
9740 memcpy(dest, src, stream->width>>k);
9741 src += src_stride[i];
9742 dest += stream->stride[i];
9745 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9746 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9748 LOGE("Not support format %d", stream->format);
9752 tbm_bo_unmap(stream->bo[0]);
9753 gst_memory_unmap(mem, &mapinfo);
9759 tbm_bo_unmap(stream->bo[0]);
9762 gst_memory_unmap(mem, &mapinfo);
9768 __mmplayer_set_pause_state(mmplayer_t *player)
9770 if (player->sent_bos)
9773 /* rtsp case, get content attrs by GstMessage */
9774 if (MMPLAYER_IS_RTSP_STREAMING(player))
9777 /* it's first time to update all content attrs. */
9778 _mmplayer_update_content_attrs(player, ATTR_ALL);
9782 __mmplayer_set_playing_state(mmplayer_t *player)
9784 gchar *audio_codec = NULL;
9786 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9787 /* initialize because auto resume is done well. */
9788 player->resumed_by_rewind = FALSE;
9789 player->playback_rate = 1.0;
9792 if (player->sent_bos)
9795 /* try to get content metadata */
9797 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9798 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9799 * legacy mmfw-player api
9801 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9803 if ((player->cmd == MMPLAYER_COMMAND_START)
9804 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9805 __mmplayer_handle_missed_plugin(player);
9808 /* check audio codec field is set or not
9809 * we can get it from typefinder or codec's caps.
9811 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9813 /* The codec format can't be sent for audio only case like amr, mid etc.
9814 * Because, parser don't make related TAG.
9815 * So, if it's not set yet, fill it with found data.
9818 if (g_strrstr(player->type, "audio/midi"))
9819 audio_codec = "MIDI";
9820 else if (g_strrstr(player->type, "audio/x-amr"))
9821 audio_codec = "AMR";
9822 else if (g_strrstr(player->type, "audio/mpeg")
9823 && !g_strrstr(player->type, "mpegversion=(int)1"))
9824 audio_codec = "AAC";
9826 audio_codec = "unknown";
9828 if (mm_player_set_attribute((MMHandleType)player, NULL,
9829 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9830 LOGE("failed to set attribute");
9832 LOGD("set audio codec type with caps");