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_SRC].gst = NULL;
758 /* Initialize Player values */
759 __mmplayer_initialize_gapless_play(player);
761 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
763 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
769 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
771 GSource *source = NULL;
775 source = g_main_context_find_source_by_id(context, source_id);
776 if (source != NULL) {
777 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
778 g_source_destroy(source);
785 _mmplayer_watcher_removed_notify(gpointer data)
787 mmplayer_t *player = (mmplayer_t *)data;
788 MMPLAYER_RETURN_IF_FAIL(player);
790 MMPLAYER_BUS_WATCHER_LOCK(player);
791 player->bus_watcher = 0;
792 MMPLAYER_BUS_WATCHER_SIGNAL(player);
793 MMPLAYER_BUS_WATCHER_UNLOCK(player);
797 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
799 mmplayer_t *player = (mmplayer_t *)hplayer;
802 MMPLAYER_RETURN_IF_FAIL(player);
804 /* disconnecting bus watch */
805 if (player->bus_watcher > 0) {
806 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
807 MMPLAYER_BUS_WATCHER_LOCK(player);
808 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
809 while (player->bus_watcher > 0) {
810 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
811 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
812 player->bus_watcher);
816 MMPLAYER_BUS_WATCHER_UNLOCK(player);
817 g_mutex_clear(&player->bus_watcher_mutex);
818 g_cond_clear(&player->bus_watcher_cond);
825 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
827 mmplayer_t *player = (mmplayer_t *)hplayer;
828 GstMessage *msg = NULL;
829 GQueue *queue = NULL;
832 MMPLAYER_RETURN_IF_FAIL(player);
834 /* destroy the gst bus msg thread */
835 if (player->bus_msg_thread) {
836 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
837 player->bus_msg_thread_exit = TRUE;
838 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
839 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
841 LOGD("gst bus msg thread exit.");
842 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
843 player->bus_msg_thread = NULL;
845 g_mutex_clear(&player->bus_msg_thread_mutex);
846 g_cond_clear(&player->bus_msg_thread_cond);
849 g_mutex_lock(&player->bus_msg_q_lock);
850 queue = player->bus_msg_q;
851 while (!g_queue_is_empty(queue)) {
852 msg = (GstMessage *)g_queue_pop_head(queue);
857 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
858 gst_message_unref(msg);
860 g_mutex_unlock(&player->bus_msg_q_lock);
866 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
868 GstElement *parent = NULL;
870 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
871 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
874 MMPLAYER_FSINK_LOCK(player);
876 /* get parent of fakesink */
877 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
879 LOGD("fakesink already removed");
883 gst_element_set_locked_state(fakesink->gst, TRUE);
885 /* setting the state to NULL never returns async
886 * so no need to wait for completion of state transition
888 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
889 LOGE("fakesink state change failure!");
890 /* FIXIT : should I return here? or try to proceed to next? */
893 /* remove fakesink from it's parent */
894 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
895 LOGE("failed to remove fakesink");
897 gst_object_unref(parent);
902 gst_object_unref(parent);
904 LOGD("state-holder removed");
906 gst_element_set_locked_state(fakesink->gst, FALSE);
908 MMPLAYER_FSINK_UNLOCK(player);
913 gst_element_set_locked_state(fakesink->gst, FALSE);
915 MMPLAYER_FSINK_UNLOCK(player);
919 static GstPadProbeReturn
920 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
922 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
923 return GST_PAD_PROBE_OK;
927 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
929 gint64 stop_running_time = 0;
930 gint64 position_running_time = 0;
934 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
935 if ((player->gapless.update_segment[idx] == TRUE) ||
936 !(player->track[idx].event_probe_id)) {
938 LOGW("[%d] skip", idx);
943 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
945 gst_segment_to_running_time(&player->gapless.segment[idx],
946 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
947 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
949 gst_segment_to_running_time(&player->gapless.segment[idx],
950 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
952 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
954 gst_segment_to_running_time(&player->gapless.segment[idx],
955 GST_FORMAT_TIME, player->duration);
958 position_running_time =
959 gst_segment_to_running_time(&player->gapless.segment[idx],
960 GST_FORMAT_TIME, player->gapless.segment[idx].position);
962 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
963 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
965 GST_TIME_ARGS(stop_running_time),
966 GST_TIME_ARGS(position_running_time),
967 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
968 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
970 position_running_time = MAX(position_running_time, stop_running_time);
971 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
972 GST_FORMAT_TIME, player->gapless.segment[idx].start);
973 position_running_time = MAX(0, position_running_time);
974 position = MAX(position, position_running_time);
978 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
979 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
980 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
982 player->gapless.start_time[stream_type] += position;
988 static GstPadProbeReturn
989 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
991 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
992 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
993 mmplayer_t *player = (mmplayer_t *)data;
994 GstCaps *caps = NULL;
995 GstStructure *str = NULL;
996 const gchar *name = NULL;
997 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
998 gboolean caps_ret = TRUE;
1000 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
1001 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
1002 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
1003 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1004 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1007 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1011 if (strstr(name, "audio")) {
1012 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1013 } else if (strstr(name, "video")) {
1014 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1016 /* text track is not supportable */
1017 LOGE("invalid name %s", name);
1021 switch (GST_EVENT_TYPE(event)) {
1024 /* in case of gapless, drop eos event not to send it to sink */
1025 if (player->gapless.reconfigure && !player->msg_posted) {
1026 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1027 ret = GST_PAD_PROBE_DROP;
1031 case GST_EVENT_STREAM_START:
1033 __mmplayer_gst_selector_update_start_time(player, stream_type);
1036 case GST_EVENT_FLUSH_STOP:
1038 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1039 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1040 player->gapless.start_time[stream_type] = 0;
1043 case GST_EVENT_SEGMENT:
1048 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1049 gst_event_copy_segment(event, &segment);
1051 if (segment.format != GST_FORMAT_TIME)
1054 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1055 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1056 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1057 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1058 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1059 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1061 /* keep the all the segment ev to cover the seeking */
1062 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1063 player->gapless.update_segment[stream_type] = TRUE;
1065 if (!player->gapless.running)
1068 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1070 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1072 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1073 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1074 gst_event_unref(event);
1075 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1081 gdouble proportion = 0.0;
1082 GstClockTimeDiff diff = 0;
1083 GstClockTime timestamp = 0;
1084 gint64 running_time_diff = -1;
1085 GstQOSType type = 0;
1086 GstEvent *tmpev = NULL;
1088 running_time_diff = player->gapless.segment[stream_type].base;
1090 if (running_time_diff <= 0) /* don't need to adjust */
1093 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1094 gst_event_unref(event);
1096 if (timestamp < running_time_diff) {
1097 LOGW("QOS event from previous group");
1098 ret = GST_PAD_PROBE_DROP;
1103 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1104 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1105 stream_type, GST_TIME_ARGS(timestamp),
1106 GST_TIME_ARGS(running_time_diff),
1107 GST_TIME_ARGS(timestamp - running_time_diff));
1110 timestamp -= running_time_diff;
1112 /* That case is invalid for QoS events */
1113 if (diff < 0 && -diff > timestamp) {
1114 LOGW("QOS event from previous group");
1115 ret = GST_PAD_PROBE_DROP;
1119 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1120 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1130 gst_caps_unref(caps);
1134 /* create fakesink for audio or video path without audiobin or videobin */
1136 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1138 GstElement *pipeline = NULL;
1139 GstElement *fakesink = NULL;
1140 GstPad *sinkpad = NULL;
1143 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1145 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1148 fakesink = gst_element_factory_make("fakesink", NULL);
1149 if (fakesink == NULL) {
1150 LOGE("failed to create fakesink");
1154 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1155 LOGE("failed to add fakesink to pipeline");
1160 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1162 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1164 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1165 LOGE("failed to link fakesink");
1169 if (strstr(name, "video")) {
1170 if (player->v_stream_caps) {
1171 gst_caps_unref(player->v_stream_caps);
1172 player->v_stream_caps = NULL;
1174 if (player->ini.set_dump_element_flag)
1175 __mmplayer_add_dump_buffer_probe(player, fakesink);
1178 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1179 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1181 /* store it as it's sink element */
1182 __mmplayer_add_sink(player, fakesink, FALSE);
1185 gst_object_unref(GST_OBJECT(sinkpad));
1193 gst_object_unref(GST_OBJECT(sinkpad));
1196 gst_element_set_state(fakesink, GST_STATE_NULL);
1198 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1199 gst_object_unref(GST_OBJECT(fakesink));
1206 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1208 GstElement *pipeline = NULL;
1209 GstElement *concat = NULL;
1212 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1214 concat = gst_element_factory_make("concat", NULL);
1216 LOGE("failed to create concat");
1220 gst_element_set_state(concat, GST_STATE_PAUSED);
1222 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1223 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1224 LOGE("failed to add concat to pipeline");
1225 gst_element_set_state(concat, GST_STATE_NULL);
1226 gst_object_unref(GST_OBJECT(concat));
1230 LOGD("Create concat [%d] element", elem_idx);
1232 player->pipeline->mainbin[elem_idx].id = elem_idx;
1233 player->pipeline->mainbin[elem_idx].gst = concat;
1240 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1242 GstElement *pipeline = NULL;
1243 GstElement *selector = NULL;
1244 GstPad *srcpad = NULL;
1247 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1249 selector = gst_element_factory_make("input-selector", NULL);
1251 LOGE("failed to create input-selector");
1254 g_object_set(selector, "sync-streams", TRUE, NULL);
1256 srcpad = gst_element_get_static_pad(selector, "src");
1258 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1259 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1260 __mmplayer_gst_selector_blocked, NULL, NULL);
1261 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1262 __mmplayer_gst_selector_event_probe, player, NULL);
1264 gst_element_set_state(selector, GST_STATE_PAUSED);
1266 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1267 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1268 LOGE("failed to add selector to pipeline");
1270 if (player->track[stream_type].block_id != 0)
1271 gst_pad_remove_probe (srcpad, player->track[stream_type].block_id);
1272 player->track[stream_type].block_id = 0;
1274 if (player->track[stream_type].event_probe_id != 0)
1275 gst_pad_remove_probe (srcpad, player->track[stream_type].event_probe_id);
1276 player->track[stream_type].event_probe_id = 0;
1278 gst_object_unref(GST_OBJECT(srcpad));
1280 gst_element_set_state(selector, GST_STATE_NULL);
1281 gst_object_unref(GST_OBJECT(selector));
1285 gst_object_unref(GST_OBJECT(srcpad));
1287 player->pipeline->mainbin[elem_idx].id = elem_idx;
1288 player->pipeline->mainbin[elem_idx].gst = selector;
1295 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1297 mmplayer_t *player = (mmplayer_t *)data;
1298 GstElement *combiner = NULL;
1299 GstCaps *caps = NULL;
1300 GstStructure *str = NULL;
1301 const gchar *name = NULL;
1302 GstPad *sinkpad = NULL;
1303 gboolean first_track = FALSE;
1304 gboolean caps_ret = TRUE;
1306 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1307 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1310 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1311 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1313 LOGD("pad-added signal handling");
1315 /* get mimetype from caps */
1316 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1320 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1322 LOGD("detected mimetype : %s", name);
1325 if (strstr(name, "video")) {
1327 gchar *caps_str = NULL;
1329 caps_str = gst_caps_to_string(caps);
1330 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1331 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1332 player->set_mode.video_zc = true;
1334 MMPLAYER_FREEIF(caps_str);
1336 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1337 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1339 LOGD("surface type : %d", stype);
1341 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1342 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1346 /* in case of exporting video frame, it requires the 360 video filter.
1347 * it will be handled in _no_more_pads(). */
1348 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1349 __mmplayer_gst_make_fakesink(player, pad, name);
1353 if (MMPLAYER_USE_DECODEBIN(player)) {
1354 LOGD("video selector is required");
1355 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1357 LOGD("video concat is required");
1358 elem_idx = MMPLAYER_M_V_CONCAT;
1360 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1361 } else if (strstr(name, "audio")) {
1362 gint samplerate = 0;
1365 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1366 if (player->build_audio_offload)
1367 player->no_more_pad = TRUE; /* remove state holder */
1368 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1372 gst_structure_get_int(str, "rate", &samplerate);
1373 gst_structure_get_int(str, "channels", &channels);
1375 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1376 __mmplayer_gst_make_fakesink(player, pad, name);
1379 if (MMPLAYER_USE_DECODEBIN(player)) {
1380 LOGD("audio selector is required");
1381 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1383 LOGD("audio concat is required");
1384 elem_idx = MMPLAYER_M_A_CONCAT;
1386 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1388 } else if (strstr(name, "text")) {
1389 if (MMPLAYER_USE_DECODEBIN(player)) {
1390 LOGD("text selector is required");
1391 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1393 LOGD("text concat is required");
1394 elem_idx = MMPLAYER_M_T_CONCAT;
1396 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1398 LOGE("invalid caps info");
1402 /* check selector and create it */
1403 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1404 if (MMPLAYER_USE_DECODEBIN(player))
1405 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1407 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1413 LOGD("Combiner element is already created.");
1417 sinkpad = gst_element_request_pad_simple(combiner, "sink_%u");
1419 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1421 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1422 LOGE("failed to link combiner");
1423 gst_object_unref(GST_OBJECT(combiner));
1428 if (MMPLAYER_USE_DECODEBIN(player)) {
1429 LOGD("this track will be activated");
1430 g_object_set(combiner, "active-pad", sinkpad, NULL);
1434 if (MMPLAYER_USE_DECODEBIN(player)) {
1435 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1437 /* apply the text track information */
1438 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1439 mm_player_set_attribute((MMHandleType)player, NULL,
1440 "content_text_track_num", player->track[stream_type].total_track_num,
1441 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1442 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1449 gst_caps_unref(caps);
1452 gst_object_unref(GST_OBJECT(sinkpad));
1456 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1461 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1463 GstPad *srcpad = NULL;
1466 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1468 LOGD("type %d", type);
1471 LOGD("there is no %d track", type);
1475 srcpad = gst_element_get_static_pad(combiner, "src");
1477 LOGE("failed to get srcpad from combiner");
1481 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1483 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1485 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1486 if (player->track[type].block_id) {
1487 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1488 player->track[type].block_id = 0;
1492 gst_object_unref(GST_OBJECT(srcpad));
1501 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1503 gint active_index = 0;
1506 MMPLAYER_RETURN_IF_FAIL(player);
1508 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1510 /* change track to active pad */
1511 active_index = player->track[type].active_track_index;
1512 if ((active_index != DEFAULT_TRACK_INDEX) &&
1513 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1514 LOGW("failed to change %d type track to %d", type, active_index);
1515 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1519 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1520 mm_player_set_attribute((MMHandleType)player, NULL,
1521 "content_text_track_num", player->track[type].total_track_num,
1522 "current_text_track_index", player->track[type].active_track_index, NULL);
1529 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1532 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1534 if (!audio_selector) {
1535 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1537 /* in case the source is changed, output can be changed. */
1538 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1539 LOGD("remove previous audiobin if it exist");
1541 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1542 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1544 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1545 MMPLAYER_FREEIF(player->pipeline->audiobin);
1548 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1549 _mmplayer_pipeline_complete(NULL, player);
1554 /* apply the audio track information */
1555 if (MMPLAYER_USE_DECODEBIN(player))
1556 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1558 /* create audio sink path */
1559 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1560 LOGE("failed to create audio sink path");
1569 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1572 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1574 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1575 LOGD("text path is not supported");
1579 /* apply the text track information */
1580 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1582 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1583 player->has_closed_caption = TRUE;
1585 /* create text decode path */
1586 player->no_more_pad = TRUE;
1588 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1589 LOGE("failed to create text sink path");
1598 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1600 gint64 dur_bytes = 0L;
1603 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1604 player->pipeline->mainbin && player->streamer, FALSE);
1606 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1607 LOGE("fail to get duration.");
1609 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1610 * use file information was already set on Q2 when it was created. */
1611 _mm_player_streaming_set_queue2(player->streamer,
1612 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1613 TRUE, /* use_buffering */
1614 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1615 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1622 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1624 mmplayer_t *player = NULL;
1625 GstElement *video_selector = NULL;
1626 GstElement *audio_selector = NULL;
1627 GstElement *text_selector = NULL;
1630 player = (mmplayer_t *)data;
1632 LOGD("no-more-pad signal handling");
1634 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1635 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1636 LOGW("player is shutting down");
1640 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1641 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1642 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1643 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1644 LOGE("failed to set queue2 buffering");
1649 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1650 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1651 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1653 if (!video_selector && !audio_selector && !text_selector) {
1654 LOGW("there is no selector");
1655 player->no_more_pad = TRUE;
1659 /* create video path followed by video-select */
1660 if (video_selector && !audio_selector && !text_selector)
1661 player->no_more_pad = TRUE;
1663 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1666 /* create audio path followed by audio-select */
1667 if (audio_selector && !text_selector)
1668 player->no_more_pad = TRUE;
1670 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1673 /* create text path followed by text-select */
1674 __mmplayer_create_text_sink_path(player, text_selector);
1677 _mmplayer_set_reconfigure_state(player, FALSE);
1682 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1684 gboolean ret = FALSE;
1685 GstElement *pipeline = NULL;
1686 GstPad *sinkpad = NULL;
1689 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1690 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1692 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1694 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1696 LOGE("failed to get pad from sinkbin");
1702 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1703 LOGE("failed to link sinkbin for reusing");
1704 goto EXIT; /* exit either pass or fail */
1708 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1709 LOGE("failed to set state(READY) to sinkbin");
1714 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1715 LOGE("failed to add sinkbin to pipeline");
1720 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1721 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1726 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1727 LOGE("failed to set state(PAUSED) to sinkbin");
1736 gst_object_unref(GST_OBJECT(sinkpad));
1744 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1746 mmplayer_t *player = NULL;
1747 GstCaps *caps = NULL;
1748 gchar *caps_str = NULL;
1749 GstStructure *str = NULL;
1750 const gchar *name = NULL;
1751 GstElement *sinkbin = NULL;
1752 gboolean reusing = FALSE;
1753 gboolean caps_ret = TRUE;
1754 gchar *sink_pad_name = "sink";
1757 player = (mmplayer_t *)data;
1760 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1761 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1762 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1764 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1768 gst_caps_unref(caps);
1769 caps = gst_caps_ref(ref_caps);
1772 caps_str = gst_caps_to_string(caps);
1774 LOGD("detected mimetype : %s", name);
1776 if (strstr(name, "audio")) {
1777 if (player->pipeline->audiobin == NULL) {
1778 const gchar *audio_format = gst_structure_get_string(str, "format");
1780 LOGD("original audio format %s", audio_format);
1781 mm_player_set_attribute((MMHandleType)player, NULL,
1782 "content_audio_format", audio_format, strlen(audio_format), NULL);
1785 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1786 LOGE("failed to create audiobin. continuing without audio");
1790 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1791 LOGD("creating audiobin success");
1794 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1795 LOGD("reusing audiobin");
1796 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1798 } else if (strstr(name, "video")) {
1799 /* 1. zero copy is updated at _decode_pad_added()
1800 * 2. NULL surface type is handled in _decode_pad_added() */
1801 LOGD("zero copy %d", player->set_mode.video_zc);
1802 if (player->pipeline->videobin == NULL) {
1803 int surface_type = 0;
1804 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1805 LOGD("display_surface_type (%d)", surface_type);
1807 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1808 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1809 LOGE("failed to acquire video overlay resource");
1813 player->interrupted_by_resource = FALSE;
1815 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1816 LOGE("failed to create videobin. continuing without video");
1820 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1821 LOGD("creating videosink bin success");
1824 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1825 LOGD("re-using videobin");
1826 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1828 } else if (strstr(name, "text")) {
1829 if (player->pipeline->textbin == NULL) {
1830 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1831 LOGE("failed to create text sink bin. continuing without text");
1835 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1836 player->textsink_linked = 1;
1837 LOGD("creating textsink bin success");
1839 if (!player->textsink_linked) {
1840 LOGD("re-using textbin");
1842 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1843 player->textsink_linked = 1;
1845 /* linked textbin exist which means that the external subtitle path exist already */
1846 LOGW("ignoring internal subtitle since external subtitle is available");
1849 sink_pad_name = "text_sink";
1851 LOGW("unknown mime type %s, ignoring it", name);
1855 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1858 LOGD("[handle: %p] success to create and link sink bin", player);
1860 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1861 * streaming task. if the task blocked, then buffer will not flow to the next element
1862 *(autoplugging element). so this is special hack for streaming. please try to remove it
1864 /* dec stream count. we can remove fakesink if it's zero */
1865 if (player->num_dynamic_pad)
1866 player->num_dynamic_pad--;
1868 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1870 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1871 _mmplayer_pipeline_complete(NULL, player);
1875 MMPLAYER_FREEIF(caps_str);
1878 gst_caps_unref(caps);
1884 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1886 int required_angle = 0; /* Angle required for straight view */
1887 int rotation_angle = 0;
1889 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1890 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1892 /* Counter clockwise */
1893 switch (orientation) {
1898 required_angle = 270;
1901 required_angle = 180;
1904 required_angle = 90;
1908 rotation_angle = display_angle + required_angle;
1909 if (rotation_angle >= 360)
1910 rotation_angle -= 360;
1912 /* check if supported or not */
1913 if (rotation_angle % 90) {
1914 LOGD("not supported rotation angle = %d", rotation_angle);
1918 switch (rotation_angle) {
1920 *value = MM_DISPLAY_ROTATION_NONE;
1923 *value = MM_DISPLAY_ROTATION_90;
1926 *value = MM_DISPLAY_ROTATION_180;
1929 *value = MM_DISPLAY_ROTATION_270;
1933 LOGD("setting rotation property value : %d", *value);
1939 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1941 int display_rotation = 0;
1942 gchar *org_orient = NULL;
1943 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1946 LOGE("cannot get content attribute");
1947 return MM_ERROR_PLAYER_INTERNAL;
1950 if (display_angle) {
1951 /* update user rotation */
1952 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1954 /* Counter clockwise */
1955 switch (display_rotation) {
1956 case MM_DISPLAY_ROTATION_NONE:
1959 case MM_DISPLAY_ROTATION_90:
1960 *display_angle = 90;
1962 case MM_DISPLAY_ROTATION_180:
1963 *display_angle = 180;
1965 case MM_DISPLAY_ROTATION_270:
1966 *display_angle = 270;
1969 LOGW("wrong angle type : %d", display_rotation);
1972 LOGD("check user angle: %d", *display_angle);
1976 /* Counter clockwise */
1977 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1980 if (!strcmp(org_orient, "rotate-90"))
1982 else if (!strcmp(org_orient, "rotate-180"))
1984 else if (!strcmp(org_orient, "rotate-270"))
1987 LOGD("original rotation is %s", org_orient);
1989 LOGD("content_video_orientation get fail");
1992 LOGD("check orientation: %d", *orientation);
1995 return MM_ERROR_NONE;
1998 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
2000 int rotation_value = 0;
2001 int orientations = 0; // current supported angle values are 0, 90, 180, 270
2002 int display_angle = 0;
2005 /* check video sinkbin is created */
2006 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2009 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2011 /* get rotation value to set */
2012 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2013 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2014 LOGD("set video param : rotate %d", rotation_value);
2017 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2019 MMHandleType attrs = 0;
2023 /* check video sinkbin is created */
2024 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2025 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2028 attrs = MMPLAYER_GET_ATTRS(player);
2029 MMPLAYER_RETURN_IF_FAIL(attrs);
2031 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2032 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2033 LOGD("set video param : visible %d", visible);
2036 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2038 MMHandleType attrs = 0;
2039 int display_method = 0;
2042 /* check video sinkbin is created */
2043 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2046 attrs = MMPLAYER_GET_ATTRS(player);
2047 MMPLAYER_RETURN_IF_FAIL(attrs);
2049 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2050 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2051 LOGD("set video param : method %d", display_method);
2054 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2056 MMHandleType attrs = 0;
2060 /* check video sinkbin is created */
2061 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2064 attrs = MMPLAYER_GET_ATTRS(player);
2065 MMPLAYER_RETURN_IF_FAIL(attrs);
2067 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2068 MMPLAYER_RETURN_IF_FAIL(handle);
2070 gst_video_overlay_set_video_roi_area(
2071 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2072 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2073 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2074 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2077 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2079 MMHandleType attrs = 0;
2084 int win_roi_width = 0;
2085 int win_roi_height = 0;
2088 /* check video sinkbin is created */
2089 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2092 attrs = MMPLAYER_GET_ATTRS(player);
2093 MMPLAYER_RETURN_IF_FAIL(attrs);
2095 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2096 MMPLAYER_RETURN_IF_FAIL(handle);
2098 /* It should be set after setting window */
2099 mm_attrs_multiple_get(attrs, NULL,
2100 "display_win_roi_x", &win_roi_x,
2101 "display_win_roi_y", &win_roi_y,
2102 "display_win_roi_width", &win_roi_width,
2103 "display_win_roi_height", &win_roi_height, NULL);
2105 /* After setting window handle, set display roi area */
2106 gst_video_overlay_set_display_roi_area(
2107 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2108 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2109 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2110 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2113 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2115 MMHandleType attrs = 0;
2116 gchar *handle = NULL;
2118 /* check video sinkbin is created */
2119 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2122 attrs = MMPLAYER_GET_ATTRS(player);
2123 MMPLAYER_RETURN_IF_FAIL(attrs);
2125 /* common case if using overlay surface */
2126 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2127 MMPLAYER_RETURN_IF_FAIL(handle);
2129 gst_video_overlay_set_wl_window_exported_shell_handle(
2130 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2132 LOGD("set video param: exported_shell_handle (%s)", handle);
2135 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2137 MMHandleType attrs = 0;
2140 /* check video sinkbin is created */
2141 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2144 attrs = MMPLAYER_GET_ATTRS(player);
2145 MMPLAYER_RETURN_IF_FAIL(attrs);
2147 /* common case if using overlay surface */
2148 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2149 MMPLAYER_RETURN_IF_FAIL(handle);
2151 /* default is using wl_surface_id */
2152 LOGD("set video param : wl_surface_id %d", handle);
2153 gst_video_overlay_set_wl_window_wl_surface_id(
2154 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2159 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2161 gboolean update_all_param = FALSE;
2162 int curr_type = MM_DISPLAY_SURFACE_NUM;
2166 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2167 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2168 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2169 LOGW("videosink is not ready yet");
2170 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2173 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2175 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2176 LOGE("current type(%d) is wrong", curr_type);
2177 return MM_ERROR_PLAYER_INTERNAL;
2180 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2181 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2182 return MM_ERROR_PLAYER_INTERNAL;
2185 LOGD("param_name : %s", param_name);
2186 if (!g_strcmp0(param_name, "update_all_param"))
2187 update_all_param = TRUE;
2189 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2190 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2192 return MM_ERROR_NONE;
2194 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2195 __mmplayer_video_param_set_display_overlay(player);
2196 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2197 __mmplayer_video_param_set_display_method(player);
2198 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2199 __mmplayer_video_param_set_display_visible(player);
2200 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2201 __mmplayer_video_param_set_display_rotation(player);
2202 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2203 __mmplayer_video_param_set_roi_area(player);
2204 if (update_all_param)
2205 __mmplayer_video_param_set_video_roi_area(player);
2208 return MM_ERROR_NONE;
2211 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2213 gboolean disable_overlay = FALSE;
2216 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2217 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2218 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2220 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2221 LOGW("Display control is not supported");
2222 return MM_ERROR_PLAYER_INTERNAL;
2225 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2227 if (disable == (bool)disable_overlay) {
2228 LOGE("It's the same with current setting: (%d)", disable);
2229 return MM_ERROR_NONE;
2233 LOGE("disable overlay");
2234 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2236 /* release overlay resource */
2237 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2238 LOGE("failed to release overlay resource");
2239 return MM_ERROR_PLAYER_INTERNAL;
2242 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2243 LOGE("failed to acquire video overlay resource");
2244 return MM_ERROR_PLAYER_INTERNAL;
2246 player->interrupted_by_resource = FALSE;
2248 LOGD("enable overlay");
2249 __mmplayer_video_param_set_display_overlay(player);
2250 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2251 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2255 return MM_ERROR_NONE;
2259 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2261 int ret = MM_ERROR_NONE;
2262 mmplayer_t *player = (mmplayer_t *)hplayer;
2265 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2267 if (MMPLAYER_USE_DECODEBIN(player)) {
2268 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2273 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2274 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2275 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2277 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
2279 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2281 /* release decoder resource */
2282 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2283 LOGE("failed to release video decoder resources");
2284 return MM_ERROR_PLAYER_INTERNAL;
2286 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2288 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2292 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2299 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2301 GList *bucket = element_bucket;
2302 mmplayer_gst_element_t *element = NULL;
2303 mmplayer_gst_element_t *prv_element = NULL;
2304 GstElement *tee_element = NULL;
2305 gint successful_link_count = 0;
2309 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2311 prv_element = (mmplayer_gst_element_t *)bucket->data;
2312 bucket = bucket->next;
2314 for (; bucket; bucket = bucket->next) {
2315 element = (mmplayer_gst_element_t *)bucket->data;
2317 if (element && element->gst) {
2318 if (prv_element && prv_element->gst) {
2319 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2321 prv_element->gst = tee_element;
2323 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2324 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2325 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2329 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2330 LOGD("linking [%s] to [%s] success",
2331 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2332 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2333 successful_link_count++;
2334 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2335 LOGD("keep audio-tee element for next audio pipeline branch");
2336 tee_element = prv_element->gst;
2339 LOGD("linking [%s] to [%s] failed",
2340 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2341 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2347 prv_element = element;
2352 return successful_link_count;
2356 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2358 GList *bucket = element_bucket;
2359 mmplayer_gst_element_t *element = NULL;
2360 int successful_add_count = 0;
2364 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2365 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2367 for (; bucket; bucket = bucket->next) {
2368 element = (mmplayer_gst_element_t *)bucket->data;
2370 if (element && element->gst) {
2371 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2372 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2373 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2374 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2377 successful_add_count++;
2383 return successful_add_count;
2387 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2389 mmplayer_t *player = (mmplayer_t *)data;
2390 GstCaps *caps = NULL;
2391 GstStructure *str = NULL;
2393 gboolean caps_ret = TRUE;
2397 MMPLAYER_RETURN_IF_FAIL(pad);
2398 MMPLAYER_RETURN_IF_FAIL(unused);
2399 MMPLAYER_RETURN_IF_FAIL(data);
2401 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2405 LOGD("name = %s", name);
2407 if (strstr(name, "audio")) {
2408 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2410 if (player->audio_stream_changed_cb) {
2411 LOGE("call the audio stream changed cb");
2412 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2414 } else if (strstr(name, "video")) {
2415 if ((name = gst_structure_get_string(str, "format")))
2416 player->set_mode.video_zc = name[0] == 'S';
2418 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2419 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2421 LOGW("invalid caps info");
2426 gst_caps_unref(caps);
2434 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2439 MMPLAYER_RETURN_IF_FAIL(player);
2441 if (player->audio_stream_buff_list) {
2442 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2443 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2446 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2447 __mmplayer_audio_stream_send_data(player, tmp);
2449 MMPLAYER_FREEIF(tmp->pcm_data);
2450 MMPLAYER_FREEIF(tmp);
2453 g_list_free(player->audio_stream_buff_list);
2454 player->audio_stream_buff_list = NULL;
2461 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2463 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2466 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2468 audio_stream.bitrate = a_buffer->bitrate;
2469 audio_stream.channel = a_buffer->channel;
2470 audio_stream.channel_mask = a_buffer->channel_mask;
2471 audio_stream.data_size = a_buffer->data_size;
2472 audio_stream.data = a_buffer->pcm_data;
2473 audio_stream.pcm_format = a_buffer->pcm_format;
2475 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2477 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2483 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2485 mmplayer_t *player = (mmplayer_t *)data;
2486 const gchar *pcm_format = NULL;
2489 guint64 channel_mask = 0;
2490 void *a_data = NULL;
2492 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2493 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2497 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2499 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2500 a_data = mapinfo.data;
2501 a_size = mapinfo.size;
2503 GstCaps *caps = gst_pad_get_current_caps(pad);
2504 GstStructure *structure = gst_caps_get_structure(caps, 0);
2506 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2508 pcm_format = gst_structure_get_string(structure, "format");
2509 gst_structure_get_int(structure, "rate", &rate);
2510 gst_structure_get_int(structure, "channels", &channel);
2511 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2512 gst_caps_unref(GST_CAPS(caps));
2514 /* In case of the sync is false, use buffer list. *
2515 * The num of buffer list depends on the num of audio channels */
2516 if (player->audio_stream_buff_list) {
2517 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2518 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2520 if (channel_mask == tmp->channel_mask) {
2522 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2524 if (tmp->data_size + a_size < tmp->buff_size) {
2525 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2526 tmp->data_size += a_size;
2528 /* send data to client */
2529 __mmplayer_audio_stream_send_data(player, tmp);
2531 if (a_size > tmp->buff_size) {
2532 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2533 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2534 if (tmp->pcm_data == NULL) {
2535 LOGE("failed to realloc data.");
2538 tmp->buff_size = a_size;
2540 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2541 memcpy(tmp->pcm_data, a_data, a_size);
2542 tmp->data_size = a_size;
2547 LOGE("data is empty in list.");
2553 /* create new audio stream data for newly found audio channel */
2554 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2555 if (a_buffer == NULL) {
2556 LOGE("failed to alloc data.");
2559 a_buffer->bitrate = rate;
2560 a_buffer->channel = channel;
2561 a_buffer->channel_mask = channel_mask;
2562 a_buffer->data_size = a_size;
2563 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2565 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2566 /* If sync is FALSE, use buffer list to reduce the IPC. */
2567 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2568 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2569 if (a_buffer->pcm_data == NULL) {
2570 LOGE("failed to alloc data.");
2571 MMPLAYER_FREEIF(a_buffer);
2574 memcpy(a_buffer->pcm_data, a_data, a_size);
2576 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2578 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2580 /* If sync is TRUE, send data directly. */
2581 a_buffer->pcm_data = a_data;
2582 __mmplayer_audio_stream_send_data(player, a_buffer);
2583 MMPLAYER_FREEIF(a_buffer);
2587 gst_buffer_unmap(buffer, &mapinfo);
2592 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2594 mmplayer_t *player = (mmplayer_t *)data;
2595 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2596 GstPad *sinkpad = NULL;
2597 GstElement *queue = NULL, *sink = NULL;
2600 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2602 queue = gst_element_factory_make("queue", NULL);
2603 if (queue == NULL) {
2604 LOGD("fail make queue");
2608 sink = gst_element_factory_make("fakesink", NULL);
2610 LOGD("fail make fakesink");
2614 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2616 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2617 LOGW("failed to link queue & sink");
2621 sinkpad = gst_element_get_static_pad(queue, "sink");
2623 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2624 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2628 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2630 gst_object_unref(sinkpad);
2631 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2632 g_object_set(sink, "sync", TRUE, NULL);
2633 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2635 /* keep the first sink reference only */
2636 if (!audiobin[MMPLAYER_A_SINK].gst) {
2637 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2638 audiobin[MMPLAYER_A_SINK].gst = sink;
2642 _mmplayer_add_signal_connection(player,
2644 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2646 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2649 __mmplayer_add_sink(player, sink, FALSE);
2651 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2652 LOGE("failed to sync state");
2656 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2657 LOGE("failed to sync state");
2665 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2667 gst_object_unref(GST_OBJECT(queue));
2671 gst_object_unref(GST_OBJECT(sink));
2675 gst_object_unref(GST_OBJECT(sinkpad));
2683 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2685 mmplayer_t *player = (mmplayer_t *)data;
2688 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2690 player->no_more_pad = TRUE;
2691 _mmplayer_pipeline_complete(NULL, player);
2698 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2700 #define MAX_PROPS_LEN 128
2701 mmplayer_gst_element_t *audiobin = NULL;
2702 gint latency_mode = 0;
2703 gchar *stream_type = NULL;
2704 gchar *latency = NULL;
2706 gchar stream_props[MAX_PROPS_LEN] = {0,};
2707 GstStructure *props = NULL;
2710 * It should be set after player creation through attribute.
2711 * But, it can not be changed during playing.
2714 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2716 audiobin = player->pipeline->audiobin;
2718 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2719 if (player->sound.mute) {
2720 LOGD("mute enabled");
2721 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2724 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2725 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2728 snprintf(stream_props, sizeof(stream_props) - 1,
2729 "props,application.process.id.origin=%d", player->client_pid);
2731 snprintf(stream_props, sizeof(stream_props) - 1,
2732 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2733 stream_type, stream_id, player->client_pid);
2735 props = gst_structure_from_string(stream_props, NULL);
2736 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2737 LOGI("props result[%s].", stream_props);
2738 gst_structure_free(props);
2740 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2742 switch (latency_mode) {
2743 case AUDIO_LATENCY_MODE_LOW:
2744 latency = g_strdup("low");
2746 case AUDIO_LATENCY_MODE_MID:
2747 latency = g_strdup("mid");
2749 case AUDIO_LATENCY_MODE_HIGH:
2750 latency = g_strdup("high");
2753 latency = g_strdup("mid");
2757 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2759 LOGD("audiosink property - latency=%s", latency);
2761 MMPLAYER_FREEIF(latency);
2767 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2769 mmplayer_gst_element_t *audiobin = NULL;
2772 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2773 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2775 audiobin = player->pipeline->audiobin;
2777 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2778 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2779 LOGE("failed to create media stream info");
2780 return MM_ERROR_PLAYER_INTERNAL;
2783 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2785 if (player->video360_yaw_radians <= M_PI &&
2786 player->video360_yaw_radians >= -M_PI &&
2787 player->video360_pitch_radians <= M_PI_2 &&
2788 player->video360_pitch_radians >= -M_PI_2) {
2789 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2790 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2791 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2792 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2793 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2794 "source-orientation-y", player->video360_metadata.init_view_heading,
2795 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2799 return MM_ERROR_NONE;
2803 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2805 mmplayer_gst_element_t *audiobin = NULL;
2806 GstPad *sink_pad = NULL;
2807 GstCaps *acaps = NULL;
2809 int pitch_control = 0;
2810 double pitch_value = 1.0;
2813 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2814 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2816 audiobin = player->pipeline->audiobin;
2818 LOGD("make element for normal audio playback");
2820 /* audio bin structure for playback. {} means optional.
2821 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2823 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2824 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2827 /* for pitch control */
2828 mm_attrs_multiple_get(player->attrs, NULL,
2829 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2830 MM_PLAYER_PITCH_VALUE, &pitch_value,
2833 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2834 if (pitch_control && (player->videodec_linked == 0)) {
2835 GstElementFactory *factory;
2837 factory = gst_element_factory_find("pitch");
2839 gst_object_unref(factory);
2842 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2845 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2846 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2848 LOGW("there is no pitch element");
2853 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2855 /* replaygain volume */
2856 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2857 if (player->sound.rg_enable)
2858 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2860 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2863 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2865 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2866 /* currently, only openalsink uses volume element */
2867 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2868 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2870 if (player->sound.mute) {
2871 LOGD("mute enabled");
2872 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2876 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2878 /* audio effect element. if audio effect is enabled */
2879 if ((strcmp(player->ini.audioeffect_element, ""))
2881 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2882 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2884 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2886 if ((!player->bypass_audio_effect)
2887 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2888 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2889 if (!_mmplayer_audio_effect_custom_apply(player))
2890 LOGI("apply audio effect(custom) setting success");
2894 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2895 && (player->set_mode.rich_audio)) {
2896 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2900 /* create audio sink */
2901 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2902 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2903 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2905 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2906 if (player->is_360_feature_enabled &&
2907 player->is_content_spherical &&
2909 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2910 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2911 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2913 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2915 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2917 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2918 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2919 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2920 gst_caps_unref(acaps);
2922 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2924 player->is_openal_plugin_used = TRUE;
2926 if (player->is_360_feature_enabled && player->is_content_spherical)
2927 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2928 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2931 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2932 (player->videodec_linked && player->ini.use_system_clock)) {
2933 LOGD("system clock will be used.");
2934 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2937 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2938 __mmplayer_gst_set_pulsesink_property(player);
2939 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2940 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2945 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2946 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2948 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2949 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2950 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2951 gst_object_unref(GST_OBJECT(sink_pad));
2953 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2956 return MM_ERROR_NONE;
2958 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2960 return MM_ERROR_PLAYER_INTERNAL;
2964 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2966 mmplayer_gst_element_t *audiobin = NULL;
2967 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2969 gchar *dst_format = NULL;
2971 int dst_samplerate = 0;
2972 int dst_channels = 0;
2973 GstCaps *caps = NULL;
2974 char *caps_str = NULL;
2977 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2978 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2980 audiobin = player->pipeline->audiobin;
2982 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2984 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2986 [case 1] extract interleave audio pcm without playback
2987 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2988 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2990 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2992 [case 2] deinterleave for each channel without playback
2993 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2994 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2996 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2997 - fakesink (sync or not)
3000 [case 3] [case 1(sync only)] + playback
3001 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
3003 * src - ... - tee - queue1 - playback path
3004 - queue2 - [case1 pipeline with sync]
3006 [case 4] [case 2(sync only)] + playback
3007 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3009 * src - ... - tee - queue1 - playback path
3010 - queue2 - [case2 pipeline with sync]
3014 /* 1. create tee and playback path
3015 'tee' should be added at first to copy the decoded stream
3017 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3018 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3019 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3021 /* tee - path 1 : for playback path */
3022 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3023 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3025 /* tee - path 2 : for extract path */
3026 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3027 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3030 /* if there is tee, 'tee - path 2' is linked here */
3032 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3035 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3037 /* 2. decide the extract pcm format */
3038 mm_attrs_multiple_get(player->attrs, NULL,
3039 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3040 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3041 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3044 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3045 dst_format, dst_len, dst_samplerate, dst_channels);
3047 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3048 mm_attrs_multiple_get(player->attrs, NULL,
3049 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3050 "content_audio_samplerate", &dst_samplerate,
3051 "content_audio_channels", &dst_channels,
3054 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3055 dst_format, dst_len, dst_samplerate, dst_channels);
3057 /* If there is no enough information, set it to platform default value. */
3058 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3059 LOGD("set platform default format");
3060 dst_format = DEFAULT_PCM_OUT_FORMAT;
3062 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3063 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3066 /* 3. create capsfilter */
3067 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3068 caps = gst_caps_new_simple("audio/x-raw",
3069 "format", G_TYPE_STRING, dst_format,
3070 "rate", G_TYPE_INT, dst_samplerate,
3071 "channels", G_TYPE_INT, dst_channels,
3074 caps_str = gst_caps_to_string(caps);
3075 LOGD("new caps : %s", caps_str);
3077 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3080 gst_caps_unref(caps);
3081 MMPLAYER_FREEIF(caps_str);
3083 /* 4-1. create deinterleave to extract pcm for each channel */
3084 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3085 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3086 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3088 /* audiosink will be added after getting signal for each channel */
3089 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3090 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3091 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3092 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3093 player->no_more_pad = FALSE;
3095 /* 4-2. create fakesink to extract interleaved pcm */
3096 LOGD("add audio fakesink for interleaved audio");
3097 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3098 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3099 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3100 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3102 _mmplayer_add_signal_connection(player,
3103 G_OBJECT(audiobin[extract_sink_id].gst),
3104 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3106 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3109 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3113 return MM_ERROR_NONE;
3115 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3117 return MM_ERROR_PLAYER_INTERNAL;
3121 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3123 int ret = MM_ERROR_NONE;
3124 mmplayer_gst_element_t *audiobin = NULL;
3125 GList *element_bucket = NULL;
3128 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3129 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3131 audiobin = player->pipeline->audiobin;
3133 if (player->build_audio_offload) { /* skip all the audio filters */
3134 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3136 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3137 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3138 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3140 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3144 /* FIXME: need to mention the supportable condition at API reference */
3145 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3146 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3148 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3150 if (ret != MM_ERROR_NONE)
3153 LOGD("success to make audio bin element");
3154 *bucket = element_bucket;
3157 return MM_ERROR_NONE;
3160 LOGE("failed to make audio bin element");
3161 g_list_free(element_bucket);
3165 return MM_ERROR_PLAYER_INTERNAL;
3169 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3171 mmplayer_gst_element_t *first_element = NULL;
3172 mmplayer_gst_element_t *audiobin = NULL;
3174 GstPad *ghostpad = NULL;
3175 GList *element_bucket = NULL;
3179 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3182 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3184 LOGE("failed to allocate memory for audiobin");
3185 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3189 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3190 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3191 if (!audiobin[MMPLAYER_A_BIN].gst) {
3192 LOGE("failed to create audiobin");
3197 player->pipeline->audiobin = audiobin;
3199 /* create audio filters and audiosink */
3200 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3203 /* adding created elements to bin */
3204 LOGD("adding created elements to bin");
3205 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3208 /* linking elements in the bucket by added order. */
3209 LOGD("Linking elements in the bucket by added order.");
3210 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3213 /* get first element's sinkpad for creating ghostpad */
3214 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3215 if (!first_element) {
3216 LOGE("failed to get first elem");
3220 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3222 LOGE("failed to get pad from first element of audiobin");
3226 ghostpad = gst_ghost_pad_new("sink", pad);
3228 LOGE("failed to create ghostpad");
3232 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3233 LOGE("failed to add ghostpad to audiobin");
3237 gst_object_unref(pad);
3239 g_list_free(element_bucket);
3242 return MM_ERROR_NONE;
3245 LOGD("ERROR : releasing audiobin");
3248 gst_object_unref(GST_OBJECT(pad));
3251 gst_object_unref(GST_OBJECT(ghostpad));
3254 g_list_free(element_bucket);
3256 /* release element which are not added to bin */
3257 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3258 /* NOTE : skip bin */
3259 if (audiobin[i].gst) {
3260 GstObject *parent = NULL;
3261 parent = gst_element_get_parent(audiobin[i].gst);
3264 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3265 audiobin[i].gst = NULL;
3267 gst_object_unref(GST_OBJECT(parent));
3271 /* release audiobin with it's children */
3272 if (audiobin[MMPLAYER_A_BIN].gst)
3273 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3275 MMPLAYER_FREEIF(audiobin);
3277 player->pipeline->audiobin = NULL;
3279 return MM_ERROR_PLAYER_INTERNAL;
3283 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3285 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3289 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3291 int ret = MM_ERROR_NONE;
3293 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3294 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3296 MMPLAYER_VIDEO_BO_LOCK(player);
3298 if (player->video_bo_list) {
3299 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3300 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3301 if (tmp && tmp->bo == bo) {
3303 LOGD("release bo %p", bo);
3304 tbm_bo_unref(tmp->bo);
3305 MMPLAYER_VIDEO_BO_UNLOCK(player);
3306 MMPLAYER_VIDEO_BO_SIGNAL(player);
3311 /* hw codec is running or the list was reset for DRC. */
3312 LOGW("there is no bo list.");
3314 MMPLAYER_VIDEO_BO_UNLOCK(player);
3316 LOGW("failed to find bo %p", bo);
3320 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3326 tbm_bo_unref(tmp->bo);
3331 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3334 MMPLAYER_RETURN_IF_FAIL(player);
3336 MMPLAYER_VIDEO_BO_LOCK(player);
3337 if (player->video_bo_list) {
3338 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3339 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3340 player->video_bo_list = NULL;
3342 player->video_bo_size = 0;
3343 MMPLAYER_VIDEO_BO_UNLOCK(player);
3350 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3353 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3354 gboolean ret = TRUE;
3355 gint64 end_time = 0;
3357 /* check DRC, if it is, destroy the prev bo list to create again */
3358 if (player->video_bo_size != size) {
3359 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3360 __mmplayer_video_stream_destroy_bo_list(player);
3361 player->video_bo_size = size;
3364 MMPLAYER_VIDEO_BO_LOCK(player);
3366 if ((!player->video_bo_list) ||
3367 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3369 /* create bo list */
3371 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3373 if (player->video_bo_list) {
3374 /* if bo list did not created all, try it again. */
3375 idx = g_list_length(player->video_bo_list);
3376 LOGD("bo list exist(len: %d)", idx);
3379 for (; idx < player->ini.num_of_video_bo; idx++) {
3380 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3382 LOGE("Fail to alloc bo_info.");
3385 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3387 LOGE("Fail to tbm_bo_alloc.");
3388 MMPLAYER_FREEIF(bo_info);
3391 bo_info->used = FALSE;
3392 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3395 /* update video num buffers */
3396 LOGD("video_num_buffers : %d", idx);
3397 mm_player_set_attribute((MMHandleType)player, NULL,
3398 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3399 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3403 MMPLAYER_VIDEO_BO_UNLOCK(player);
3408 if (player->ini.video_bo_timeout > 0)
3409 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3412 /* get bo from list*/
3413 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3414 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3415 if (tmp && (tmp->used == FALSE)) {
3416 LOGD("found bo %p to use", tmp->bo);
3418 MMPLAYER_VIDEO_BO_UNLOCK(player);
3419 return tbm_bo_ref(tmp->bo);
3423 if (player->ini.video_bo_timeout <= 0) {
3424 MMPLAYER_VIDEO_BO_WAIT(player);
3426 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3428 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3434 MMPLAYER_VIDEO_BO_UNLOCK(player);
3439 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3441 mmplayer_t *player = (mmplayer_t *)data;
3443 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3445 /* send prerolled pkt */
3446 player->video_stream_prerolled = false;
3448 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3450 /* not to send prerolled pkt again */
3451 player->video_stream_prerolled = true;
3455 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3457 mmplayer_t *player = (mmplayer_t *)data;
3458 mmplayer_video_decoded_data_info_t *stream = NULL;
3459 GstMemory *mem = NULL;
3462 MMPLAYER_RETURN_IF_FAIL(player);
3463 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3465 if (player->video_stream_prerolled) {
3466 player->video_stream_prerolled = false;
3467 LOGD("skip the prerolled pkt not to send it again");
3471 /* clear stream data structure */
3472 stream = __mmplayer_create_stream_from_pad(pad);
3474 LOGE("failed to alloc stream");
3478 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3480 /* set size and timestamp */
3481 mem = gst_buffer_peek_memory(buffer, 0);
3482 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3483 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3485 /* check zero-copy */
3486 if (player->set_mode.video_zc &&
3487 player->set_mode.video_export &&
3488 gst_is_tizen_memory(mem)) {
3489 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3490 stream->internal_buffer = gst_buffer_ref(buffer);
3491 } else { /* sw codec */
3492 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3495 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3499 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3500 LOGE("failed to send video decoded data.");
3507 LOGE("release video stream resource.");
3508 if (gst_is_tizen_memory(mem)) {
3510 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3512 tbm_bo_unref(stream->bo[i]);
3515 /* unref gst buffer */
3516 if (stream->internal_buffer)
3517 gst_buffer_unref(stream->internal_buffer);
3520 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3522 MMPLAYER_FREEIF(stream);
3527 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3529 mmplayer_gst_element_t *videobin = NULL;
3532 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3534 videobin = player->pipeline->videobin;
3536 /* Set spatial media metadata and/or user settings to the element.
3538 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3539 "projection-type", player->video360_metadata.projection_type, NULL);
3541 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3542 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3544 if (player->video360_metadata.full_pano_width_pixels &&
3545 player->video360_metadata.full_pano_height_pixels &&
3546 player->video360_metadata.cropped_area_image_width &&
3547 player->video360_metadata.cropped_area_image_height) {
3548 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3549 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3550 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3551 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3552 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3553 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3554 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3558 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3559 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3560 "horizontal-fov", player->video360_horizontal_fov,
3561 "vertical-fov", player->video360_vertical_fov, NULL);
3564 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3565 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3566 "zoom", 1.0f / player->video360_zoom, NULL);
3569 if (player->video360_yaw_radians <= M_PI &&
3570 player->video360_yaw_radians >= -M_PI &&
3571 player->video360_pitch_radians <= M_PI_2 &&
3572 player->video360_pitch_radians >= -M_PI_2) {
3573 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3574 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3575 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3576 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3577 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3578 "pose-yaw", player->video360_metadata.init_view_heading,
3579 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3582 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3583 "passthrough", !player->is_video360_enabled, NULL);
3590 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3592 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3593 GList *element_bucket = NULL;
3596 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3598 /* create video360 filter */
3599 if (player->is_360_feature_enabled && player->is_content_spherical) {
3600 LOGD("create video360 element");
3601 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3602 __mmplayer_gst_set_video360_property(player);
3606 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3607 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3608 player->set_mode.video_zc) {
3609 LOGD("skip creating the videoconv and rotator");
3610 return MM_ERROR_NONE;
3613 /* in case of sw codec & overlay surface type, except 360 playback.
3614 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3615 LOGD("create video converter: %s", video_csc);
3616 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3619 *bucket = element_bucket;
3621 return MM_ERROR_NONE;
3623 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3624 g_list_free(element_bucket);
3628 return MM_ERROR_PLAYER_INTERNAL;
3632 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3634 gchar *factory_name = NULL;
3636 switch (surface_type) {
3637 case MM_DISPLAY_SURFACE_OVERLAY:
3639 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3640 if (strlen(player->ini.videosink_element_overlay) > 0)
3641 factory_name = player->ini.videosink_element_overlay;
3643 case MM_DISPLAY_SURFACE_REMOTE:
3645 case MM_DISPLAY_SURFACE_NULL:
3646 if (strlen(player->ini.videosink_element_fake) > 0)
3647 factory_name = player->ini.videosink_element_fake;
3650 LOGE("unidentified surface type");
3654 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3655 return factory_name;
3659 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3661 gchar *factory_name = NULL;
3662 mmplayer_gst_element_t *videobin = NULL;
3667 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3669 videobin = player->pipeline->videobin;
3670 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3672 attrs = MMPLAYER_GET_ATTRS(player);
3674 LOGE("cannot get content attribute");
3675 return MM_ERROR_PLAYER_INTERNAL;
3678 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3679 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3680 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3681 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3682 "use-tbm", use_tbm, NULL);
3685 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3686 return MM_ERROR_PLAYER_INTERNAL;
3688 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3691 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3692 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3695 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3697 LOGD("disable last-sample");
3698 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3701 if (player->set_mode.video_export) {
3703 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3704 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3705 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3707 _mmplayer_add_signal_connection(player,
3708 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3709 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3711 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3714 _mmplayer_add_signal_connection(player,
3715 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3716 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3718 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3722 if (videobin[MMPLAYER_V_SINK].gst) {
3723 GstPad *sink_pad = NULL;
3724 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3726 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3727 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3728 gst_object_unref(GST_OBJECT(sink_pad));
3730 LOGE("failed to get sink pad from videosink");
3734 return MM_ERROR_NONE;
3739 * - video overlay surface(arm/x86) : tizenwlsink
3742 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3745 GList *element_bucket = NULL;
3746 mmplayer_gst_element_t *first_element = NULL;
3747 mmplayer_gst_element_t *videobin = NULL;
3748 gchar *videosink_factory_name = NULL;
3751 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3754 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3756 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3758 player->pipeline->videobin = videobin;
3761 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3762 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3763 if (!videobin[MMPLAYER_V_BIN].gst) {
3764 LOGE("failed to create videobin");
3768 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3771 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3772 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3774 /* additional setting for sink plug-in */
3775 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3776 LOGE("failed to set video property");
3780 /* store it as it's sink element */
3781 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3783 /* adding created elements to bin */
3784 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3785 LOGE("failed to add elements");
3789 /* Linking elements in the bucket by added order */
3790 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3791 LOGE("failed to link elements");
3795 /* get first element's sinkpad for creating ghostpad */
3796 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3797 if (!first_element) {
3798 LOGE("failed to get first element from bucket");
3802 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3804 LOGE("failed to get pad from first element");
3808 /* create ghostpad */
3809 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3810 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3811 LOGE("failed to add ghostpad to videobin");
3814 gst_object_unref(pad);
3816 /* done. free allocated variables */
3817 g_list_free(element_bucket);
3821 return MM_ERROR_NONE;
3824 LOGE("ERROR : releasing videobin");
3825 g_list_free(element_bucket);
3828 gst_object_unref(GST_OBJECT(pad));
3830 /* release videobin with it's children */
3831 if (videobin[MMPLAYER_V_BIN].gst)
3832 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3834 MMPLAYER_FREEIF(videobin);
3835 player->pipeline->videobin = NULL;
3837 return MM_ERROR_PLAYER_INTERNAL;
3841 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3843 GList *element_bucket = NULL;
3844 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3846 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3847 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3848 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3849 "signal-handoffs", FALSE,
3852 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3853 _mmplayer_add_signal_connection(player,
3854 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3855 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3857 G_CALLBACK(__mmplayer_update_subtitle),
3860 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3861 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3863 if (!player->play_subtitle) {
3864 LOGD("add textbin sink as sink element of whole pipeline.");
3865 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3868 /* adding created elements to bin */
3869 LOGD("adding created elements to bin");
3870 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3871 LOGE("failed to add elements");
3875 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3876 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3877 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3879 /* linking elements in the bucket by added order. */
3880 LOGD("Linking elements in the bucket by added order.");
3881 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3882 LOGE("failed to link elements");
3886 if (textbin[MMPLAYER_T_QUEUE].gst) {
3888 GstPad *ghostpad = NULL;
3890 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3892 LOGE("failed to get sink pad of text queue");
3896 ghostpad = gst_ghost_pad_new("text_sink", pad);
3897 gst_object_unref(pad);
3900 LOGE("failed to create ghostpad of textbin");
3904 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3905 LOGE("failed to add ghostpad to textbin");
3906 gst_object_unref(ghostpad);
3911 g_list_free(element_bucket);
3913 return MM_ERROR_NONE;
3917 g_list_free(element_bucket);
3919 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3920 LOGE("remove textbin sink from sink list");
3921 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3924 /* release element at __mmplayer_gst_create_text_sink_bin */
3925 return MM_ERROR_PLAYER_INTERNAL;
3929 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3931 mmplayer_gst_element_t *textbin = NULL;
3932 int surface_type = 0;
3937 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3940 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3942 LOGE("failed to allocate memory for textbin");
3943 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3947 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3948 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3949 if (!textbin[MMPLAYER_T_BIN].gst) {
3950 LOGE("failed to create textbin");
3955 player->pipeline->textbin = textbin;
3958 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3959 LOGD("surface type for subtitle : %d", surface_type);
3960 switch (surface_type) {
3961 case MM_DISPLAY_SURFACE_OVERLAY:
3962 case MM_DISPLAY_SURFACE_NULL:
3963 case MM_DISPLAY_SURFACE_REMOTE:
3964 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3965 LOGE("failed to make plain text elements");
3976 return MM_ERROR_NONE;
3980 LOGD("ERROR : releasing textbin");
3982 /* release signal */
3983 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3985 /* release element which are not added to bin */
3986 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3987 /* NOTE : skip bin */
3988 if (textbin[i].gst) {
3989 GstObject *parent = NULL;
3990 parent = gst_element_get_parent(textbin[i].gst);
3993 gst_object_unref(GST_OBJECT(textbin[i].gst));
3994 textbin[i].gst = NULL;
3996 gst_object_unref(GST_OBJECT(parent));
4001 /* release textbin with it's children */
4002 if (textbin[MMPLAYER_T_BIN].gst)
4003 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4005 MMPLAYER_FREEIF(textbin);
4006 player->pipeline->textbin = NULL;
4009 return MM_ERROR_PLAYER_INTERNAL;
4013 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4015 mmplayer_gst_element_t *mainbin = NULL;
4016 mmplayer_gst_element_t *textbin = NULL;
4017 MMHandleType attrs = 0;
4018 GstElement *subsrc = NULL;
4019 GstElement *subparse = NULL;
4020 gchar *subtitle_uri = NULL;
4021 const gchar *charset = NULL;
4027 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4029 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4031 mainbin = player->pipeline->mainbin;
4033 attrs = MMPLAYER_GET_ATTRS(player);
4035 LOGE("cannot get content attribute");
4036 return MM_ERROR_PLAYER_INTERNAL;
4039 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4040 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4041 LOGE("subtitle uri is not proper filepath.");
4042 return MM_ERROR_PLAYER_INVALID_URI;
4045 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4046 LOGE("failed to get storage info of subtitle path");
4047 return MM_ERROR_PLAYER_INVALID_URI;
4050 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4052 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4053 player->subtitle_language_list = NULL;
4054 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4056 /* create the subtitle source */
4057 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4059 LOGE("failed to create filesrc element");
4062 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4064 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4065 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4067 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4068 LOGW("failed to add queue");
4069 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4070 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4071 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4076 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4078 LOGE("failed to create subparse element");
4082 charset = _mmplayer_get_charset(subtitle_uri);
4084 LOGD("detected charset is %s", charset);
4085 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4088 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4089 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4091 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4092 LOGW("failed to add subparse");
4093 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4094 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4095 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4099 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4100 LOGW("failed to link subsrc and subparse");
4104 player->play_subtitle = TRUE;
4105 player->adjust_subtitle_pos = 0;
4107 LOGD("play subtitle using subtitle file");
4109 if (player->pipeline->textbin == NULL) {
4110 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4111 LOGE("failed to create text sink bin. continuing without text");
4115 textbin = player->pipeline->textbin;
4117 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4118 LOGW("failed to add textbin");
4120 /* release signal */
4121 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4123 /* release textbin with it's children */
4124 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4125 MMPLAYER_FREEIF(player->pipeline->textbin);
4126 player->pipeline->textbin = textbin = NULL;
4130 LOGD("link text input selector and textbin ghost pad");
4132 player->textsink_linked = 1;
4133 player->external_text_idx = 0;
4134 LOGI("textsink is linked");
4136 textbin = player->pipeline->textbin;
4137 LOGD("text bin has been created. reuse it.");
4138 player->external_text_idx = 1;
4141 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4142 LOGW("failed to link subparse and textbin");
4146 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4148 LOGE("failed to get sink pad from textsink to probe data");
4152 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4153 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4155 gst_object_unref(pad);
4158 /* create dot. for debugging */
4159 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4162 return MM_ERROR_NONE;
4165 /* release text pipeline resource */
4166 player->textsink_linked = 0;
4168 /* release signal */
4169 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4171 if (player->pipeline->textbin) {
4172 LOGE("remove textbin");
4174 /* release textbin with it's children */
4175 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4176 MMPLAYER_FREEIF(player->pipeline->textbin);
4177 player->pipeline->textbin = NULL;
4181 /* release subtitle elem */
4182 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4183 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4185 return MM_ERROR_PLAYER_INTERNAL;
4189 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4191 mmplayer_t *player = (mmplayer_t *)data;
4192 MMMessageParamType msg = {0, };
4193 GstClockTime duration = 0;
4194 gpointer text = NULL;
4195 guint text_size = 0;
4196 gboolean ret = TRUE;
4197 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4201 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4202 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4204 if (player->is_subtitle_force_drop) {
4205 LOGW("subtitle is dropped forcedly.");
4209 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4210 text = mapinfo.data;
4211 text_size = mapinfo.size;
4213 if (player->set_mode.subtitle_off) {
4214 LOGD("subtitle is OFF.");
4218 if (!text || (text_size == 0)) {
4219 LOGD("There is no subtitle to be displayed.");
4223 msg.data = (void *)text;
4225 duration = GST_BUFFER_DURATION(buffer);
4227 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4228 if (player->duration > GST_BUFFER_PTS(buffer))
4229 duration = player->duration - GST_BUFFER_PTS(buffer);
4232 LOGI("subtitle duration is invalid, subtitle duration change "
4233 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4235 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4237 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4239 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4240 gst_buffer_unmap(buffer, &mapinfo);
4247 static GstPadProbeReturn
4248 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4250 mmplayer_t *player = (mmplayer_t *)u_data;
4251 GstClockTime cur_timestamp = 0;
4252 gint64 adjusted_timestamp = 0;
4253 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4255 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4257 if (player->set_mode.subtitle_off) {
4258 LOGD("subtitle is OFF.");
4262 if (player->adjust_subtitle_pos == 0) {
4263 LOGD("nothing to do");
4267 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4268 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4270 if (adjusted_timestamp < 0) {
4271 LOGD("adjusted_timestamp under zero");
4276 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4277 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4278 GST_TIME_ARGS(cur_timestamp),
4279 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4281 return GST_PAD_PROBE_OK;
4285 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4289 /* check player and subtitlebin are created */
4290 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4291 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4293 if (position == 0) {
4294 LOGD("nothing to do");
4296 return MM_ERROR_NONE;
4299 /* check current position */
4300 player->adjust_subtitle_pos = position;
4302 LOGD("save adjust_subtitle_pos in player");
4306 return MM_ERROR_NONE;
4310 * This function is to create audio or video pipeline for playing.
4312 * @param player [in] handle of player
4314 * @return This function returns zero on success.
4319 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4321 int ret = MM_ERROR_NONE;
4322 mmplayer_gst_element_t *mainbin = NULL;
4323 MMHandleType attrs = 0;
4326 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4328 /* get profile attribute */
4329 attrs = MMPLAYER_GET_ATTRS(player);
4331 LOGE("failed to get content attribute");
4335 /* create pipeline handles */
4336 if (player->pipeline) {
4337 LOGE("pipeline should be released before create new one");
4341 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4343 /* create mainbin */
4344 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4345 if (mainbin == NULL)
4348 /* create pipeline */
4349 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4350 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4351 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4352 LOGE("failed to create pipeline");
4357 player->pipeline->mainbin = mainbin;
4359 /* create the source and decoder elements */
4360 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4361 ret = _mmplayer_gst_build_es_pipeline(player);
4363 if (MMPLAYER_USE_DECODEBIN(player))
4364 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4366 ret = _mmplayer_gst_build_pipeline_with_src(player);
4369 if (ret != MM_ERROR_NONE) {
4370 LOGE("failed to create some elements");
4374 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4375 if (__mmplayer_check_subtitle(player)
4376 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4377 LOGE("failed to create text pipeline");
4380 ret = _mmplayer_gst_add_bus_watch(player);
4381 if (ret != MM_ERROR_NONE) {
4382 LOGE("failed to add bus watch");
4387 return MM_ERROR_NONE;
4390 _mmplayer_bus_watcher_remove(player);
4391 __mmplayer_gst_destroy_pipeline(player);
4392 return MM_ERROR_PLAYER_INTERNAL;
4396 __mmplayer_reset_gapless_state(mmplayer_t *player)
4399 MMPLAYER_RETURN_IF_FAIL(player
4401 && player->pipeline->audiobin
4402 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4404 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4411 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4414 int ret = MM_ERROR_NONE;
4418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4420 /* cleanup stuffs */
4421 MMPLAYER_FREEIF(player->type);
4422 player->no_more_pad = FALSE;
4423 player->num_dynamic_pad = 0;
4425 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4426 player->subtitle_language_list = NULL;
4427 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4429 MMPLAYER_RECONFIGURE_LOCK(player);
4430 __mmplayer_reset_gapless_state(player);
4431 MMPLAYER_RECONFIGURE_UNLOCK(player);
4433 if (player->streamer) {
4434 _mm_player_streaming_initialize(player->streamer, FALSE);
4435 _mm_player_streaming_destroy(player->streamer);
4436 player->streamer = NULL;
4439 /* cleanup unlinked mime type */
4440 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4441 MMPLAYER_FREEIF(player->unlinked_video_mime);
4442 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4444 /* cleanup running stuffs */
4445 _mmplayer_cancel_eos_timer(player);
4447 /* cleanup gst stuffs */
4448 if (player->pipeline) {
4449 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4450 GstTagList *tag_list = player->pipeline->tag_list;
4452 /* first we need to disconnect all signal hander */
4453 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4456 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4457 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4458 gst_object_unref(bus);
4460 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4461 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4462 if (ret != MM_ERROR_NONE) {
4463 LOGE("fail to change state to NULL");
4464 return MM_ERROR_PLAYER_INTERNAL;
4467 LOGW("succeeded in changing state to NULL");
4469 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4472 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4473 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4475 MMPLAYER_FREEIF(player->pipeline->audiobin);
4476 MMPLAYER_FREEIF(player->pipeline->videobin);
4477 MMPLAYER_FREEIF(player->pipeline->textbin);
4478 MMPLAYER_FREEIF(mainbin);
4482 gst_tag_list_unref(tag_list);
4484 MMPLAYER_FREEIF(player->pipeline);
4486 MMPLAYER_FREEIF(player->album_art);
4488 if (player->type_caps) {
4489 gst_caps_unref(player->type_caps);
4490 player->type_caps = NULL;
4493 if (player->v_stream_caps) {
4494 gst_caps_unref(player->v_stream_caps);
4495 player->v_stream_caps = NULL;
4498 if (player->a_stream_caps) {
4499 gst_caps_unref(player->a_stream_caps);
4500 player->a_stream_caps = NULL;
4503 if (player->s_stream_caps) {
4504 gst_caps_unref(player->s_stream_caps);
4505 player->s_stream_caps = NULL;
4507 _mmplayer_track_destroy(player);
4509 if (player->sink_elements)
4510 g_list_free(player->sink_elements);
4511 player->sink_elements = NULL;
4513 if (player->bufmgr) {
4514 tbm_bufmgr_deinit(player->bufmgr);
4515 player->bufmgr = NULL;
4518 LOGW("finished destroy pipeline");
4526 __mmplayer_gst_realize(mmplayer_t *player)
4529 int ret = MM_ERROR_NONE;
4533 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4535 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4537 ret = __mmplayer_gst_create_pipeline(player);
4539 LOGE("failed to create pipeline");
4543 /* set pipeline state to READY */
4544 /* NOTE : state change to READY must be performed sync. */
4545 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4546 ret = _mmplayer_gst_set_state(player,
4547 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4549 if (ret != MM_ERROR_NONE) {
4550 /* return error if failed to set state */
4551 LOGE("failed to set READY state");
4555 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4557 /* create dot before error-return. for debugging */
4558 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4566 __mmplayer_gst_unrealize(mmplayer_t *player)
4568 int ret = MM_ERROR_NONE;
4572 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4574 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4575 MMPLAYER_PRINT_STATE(player);
4577 /* release miscellaneous information */
4578 __mmplayer_release_misc(player);
4580 /* destroy pipeline */
4581 ret = __mmplayer_gst_destroy_pipeline(player);
4582 if (ret != MM_ERROR_NONE) {
4583 LOGE("failed to destroy pipeline");
4587 /* release miscellaneous information.
4588 these info needs to be released after pipeline is destroyed. */
4589 __mmplayer_release_misc_post(player);
4591 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4599 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4604 LOGW("set_message_callback is called with invalid player handle");
4605 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4608 player->msg_cb = callback;
4609 player->msg_cb_param = user_param;
4611 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4615 return MM_ERROR_NONE;
4619 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4621 int ret = MM_ERROR_NONE;
4626 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4627 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4628 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4630 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4632 if (strstr(uri, "es_buff://")) {
4633 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4634 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4635 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4636 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4638 tmp = g_ascii_strdown(uri, strlen(uri));
4639 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4640 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4642 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4644 } else if (strstr(uri, "mms://")) {
4645 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4646 } else if ((path = strstr(uri, "mem://"))) {
4647 ret = __mmplayer_set_mem_uri(data, path, param);
4649 ret = __mmplayer_set_file_uri(data, uri);
4652 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4653 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4654 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4655 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4657 /* dump parse result */
4658 SECURE_LOGW("incoming uri : %s", uri);
4659 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4660 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4668 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4671 mmplayer_t *player = NULL;
4672 MMMessageParamType msg = {0, };
4674 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4679 LOGE("user_data is null");
4683 player = (mmplayer_t *)user_data;
4685 if (!player->pipeline || !player->attrs) {
4686 LOGW("not initialized");
4690 LOGD("cmd lock player, cmd state : %d", player->cmd);
4691 MMPLAYER_CMD_LOCK(player);
4692 LOGD("cmd locked player");
4694 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4695 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4696 LOGW("player already destroyed");
4697 MMPLAYER_CMD_UNLOCK(player);
4701 player->interrupted_by_resource = TRUE;
4703 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4705 /* get last play position */
4706 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4707 msg.union_type = MM_MSG_UNION_TIME;
4708 msg.time.elapsed = pos;
4709 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4711 LOGW("failed to get play position.");
4714 LOGD("video resource conflict so, resource will be freed by unrealizing");
4715 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4716 LOGE("failed to unrealize");
4718 MMPLAYER_CMD_UNLOCK(player);
4720 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4721 player->hw_resource[res_idx] = NULL;
4725 return TRUE; /* release all the resources */
4729 __mmplayer_initialize_video_roi(mmplayer_t *player)
4731 player->video_roi.scale_x = 0.0;
4732 player->video_roi.scale_y = 0.0;
4733 player->video_roi.scale_width = 1.0;
4734 player->video_roi.scale_height = 1.0;
4738 _mmplayer_create_player(MMHandleType handle)
4740 int ret = MM_ERROR_PLAYER_INTERNAL;
4741 bool enabled = false;
4743 mmplayer_t *player = MM_PLAYER_CAST(handle);
4747 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4749 /* initialize player state */
4750 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4751 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4752 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4753 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4755 /* check current state */
4756 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4758 /* construct attributes */
4759 player->attrs = _mmplayer_construct_attribute(handle);
4761 if (!player->attrs) {
4762 LOGE("Failed to construct attributes");
4766 /* initialize gstreamer with configured parameter */
4767 if (!__mmplayer_init_gstreamer(player)) {
4768 LOGE("Initializing gstreamer failed");
4769 _mmplayer_deconstruct_attribute(handle);
4773 /* create lock. note that g_tread_init() has already called in gst_init() */
4774 g_mutex_init(&player->fsink_lock);
4776 /* create update tag lock */
4777 g_mutex_init(&player->update_tag_lock);
4779 /* create gapless play mutex */
4780 g_mutex_init(&player->gapless_play_thread_mutex);
4782 /* create gapless play cond */
4783 g_cond_init(&player->gapless_play_thread_cond);
4785 /* create gapless play thread */
4786 player->gapless_play_thread =
4787 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4788 if (!player->gapless_play_thread) {
4789 LOGE("failed to create gapless play thread");
4790 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4791 g_mutex_clear(&player->gapless_play_thread_mutex);
4792 g_cond_clear(&player->gapless_play_thread_cond);
4796 player->bus_msg_q = g_queue_new();
4797 if (!player->bus_msg_q) {
4798 LOGE("failed to create queue for bus_msg");
4799 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4803 ret = _mmplayer_initialize_video_capture(player);
4804 if (ret != MM_ERROR_NONE) {
4805 LOGW("video capture is not supported");
4806 /* do not handle as error for headless profile */
4809 /* initialize resource manager */
4810 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4811 __resource_release_cb, player, &player->resource_manager)
4812 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4813 LOGE("failed to create resource manager");
4814 ret = MM_ERROR_PLAYER_INTERNAL;
4818 /* create video bo lock and cond */
4819 g_mutex_init(&player->video_bo_mutex);
4820 g_cond_init(&player->video_bo_cond);
4822 /* create subtitle info lock and cond */
4823 g_mutex_init(&player->subtitle_info_mutex);
4824 g_cond_init(&player->subtitle_info_cond);
4826 player->streaming_type = STREAMING_SERVICE_NONE;
4828 /* give default value of audio effect setting */
4829 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4830 player->sound.rg_enable = false;
4831 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4833 player->play_subtitle = FALSE;
4834 player->has_closed_caption = FALSE;
4835 player->pending_resume = FALSE;
4836 if (player->ini.dump_element_keyword[0][0] == '\0')
4837 player->ini.set_dump_element_flag = FALSE;
4839 player->ini.set_dump_element_flag = TRUE;
4841 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4842 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4843 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4845 /* Set video360 settings to their defaults for just-created player.
4848 player->is_360_feature_enabled = FALSE;
4849 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4850 LOGI("spherical feature info: %d", enabled);
4852 player->is_360_feature_enabled = TRUE;
4854 LOGE("failed to get spherical feature info");
4857 player->is_content_spherical = FALSE;
4858 player->is_video360_enabled = TRUE;
4859 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4860 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4861 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4862 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4863 player->video360_zoom = 1.0f;
4864 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4865 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4867 __mmplayer_initialize_video_roi(player);
4869 /* set player state to null */
4870 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4871 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4875 return MM_ERROR_NONE;
4879 g_mutex_clear(&player->fsink_lock);
4880 /* free update tag lock */
4881 g_mutex_clear(&player->update_tag_lock);
4882 g_queue_free(player->bus_msg_q);
4883 player->bus_msg_q = NULL;
4884 /* free gapless play thread */
4885 if (player->gapless_play_thread) {
4886 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4887 player->gapless_play_thread_exit = TRUE;
4888 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4889 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4891 g_thread_join(player->gapless_play_thread);
4892 player->gapless_play_thread = NULL;
4894 g_mutex_clear(&player->gapless_play_thread_mutex);
4895 g_cond_clear(&player->gapless_play_thread_cond);
4898 /* release attributes */
4899 _mmplayer_deconstruct_attribute(handle);
4907 __mmplayer_init_gstreamer(mmplayer_t *player)
4909 static gboolean initialized = FALSE;
4910 static const int max_argc = 50;
4912 gchar **argv = NULL;
4913 gchar **argv2 = NULL;
4919 LOGD("gstreamer already initialized.");
4924 argc = malloc(sizeof(int));
4925 argv = malloc(sizeof(gchar *) * max_argc);
4926 argv2 = malloc(sizeof(gchar *) * max_argc);
4928 if (!argc || !argv || !argv2)
4931 memset(argv, 0, sizeof(gchar *) * max_argc);
4932 memset(argv2, 0, sizeof(gchar *) * max_argc);
4936 argv[0] = g_strdup("mmplayer");
4939 for (i = 0; i < 5; i++) {
4940 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4941 if (strlen(player->ini.gst_param[i]) > 0) {
4942 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4947 /* we would not do fork for scanning plugins */
4948 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4951 /* check disable registry scan */
4952 if (player->ini.skip_rescan) {
4953 argv[*argc] = g_strdup("--gst-disable-registry-update");
4957 /* check disable segtrap */
4958 if (player->ini.disable_segtrap) {
4959 argv[*argc] = g_strdup("--gst-disable-segtrap");
4963 LOGD("initializing gstreamer with following parameter");
4964 LOGD("argc : %d", *argc);
4967 for (i = 0; i < arg_count; i++) {
4969 LOGD("argv[%d] : %s", i, argv2[i]);
4972 /* initializing gstreamer */
4973 if (!gst_init_check(argc, &argv, &err)) {
4974 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4981 for (i = 0; i < arg_count; i++) {
4983 LOGD("release - argv[%d] : %s", i, argv2[i]);
4985 MMPLAYER_FREEIF(argv2[i]);
4988 MMPLAYER_FREEIF(argv);
4989 MMPLAYER_FREEIF(argv2);
4990 MMPLAYER_FREEIF(argc);
5000 for (i = 0; i < arg_count; i++) {
5001 LOGD("free[%d] : %s", i, argv2[i]);
5002 MMPLAYER_FREEIF(argv2[i]);
5005 MMPLAYER_FREEIF(argv);
5006 MMPLAYER_FREEIF(argv2);
5007 MMPLAYER_FREEIF(argc);
5013 __mmplayer_check_async_state_transition(mmplayer_t *player)
5015 GstState element_state = GST_STATE_VOID_PENDING;
5016 GstState element_pending_state = GST_STATE_VOID_PENDING;
5017 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5018 GstElement *element = NULL;
5019 gboolean async = FALSE;
5021 /* check player handle */
5022 MMPLAYER_RETURN_IF_FAIL(player &&
5024 player->pipeline->mainbin &&
5025 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5028 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5030 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5031 LOGD("don't need to check the pipeline state");
5035 MMPLAYER_PRINT_STATE(player);
5037 /* wait for state transition */
5038 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5039 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5041 if (ret == GST_STATE_CHANGE_FAILURE) {
5042 LOGE(" [%s] state : %s pending : %s",
5043 GST_ELEMENT_NAME(element),
5044 gst_element_state_get_name(element_state),
5045 gst_element_state_get_name(element_pending_state));
5047 /* dump state of all element */
5048 _mmplayer_dump_pipeline_state(player);
5053 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5058 _mmplayer_destroy(MMHandleType handle)
5060 mmplayer_t *player = MM_PLAYER_CAST(handle);
5064 /* check player handle */
5065 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5067 /* destroy can called at anytime */
5068 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5070 /* check async state transition */
5071 __mmplayer_check_async_state_transition(player);
5073 /* release gapless play thread */
5074 if (player->gapless_play_thread) {
5075 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5076 player->gapless_play_thread_exit = TRUE;
5077 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5078 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5080 LOGD("waiting for gapless play thread exit");
5081 g_thread_join(player->gapless_play_thread);
5082 g_mutex_clear(&player->gapless_play_thread_mutex);
5083 g_cond_clear(&player->gapless_play_thread_cond);
5084 LOGD("gapless play thread released");
5087 _mmplayer_release_video_capture(player);
5089 /* release miscellaneous information */
5090 __mmplayer_release_misc(player);
5092 /* release pipeline */
5093 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5094 LOGE("failed to destroy pipeline");
5095 return MM_ERROR_PLAYER_INTERNAL;
5098 __mmplayer_destroy_hw_resource(player);
5100 g_queue_free(player->bus_msg_q);
5102 /* release subtitle info lock and cond */
5103 g_mutex_clear(&player->subtitle_info_mutex);
5104 g_cond_clear(&player->subtitle_info_cond);
5106 __mmplayer_release_dump_list(player->dump_list);
5108 /* release miscellaneous information.
5109 these info needs to be released after pipeline is destroyed. */
5110 __mmplayer_release_misc_post(player);
5112 /* release attributes */
5113 _mmplayer_deconstruct_attribute(handle);
5115 if (player->uri_info.uri_list) {
5116 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5117 player->uri_info.uri_list = NULL;
5121 g_mutex_clear(&player->fsink_lock);
5124 g_mutex_clear(&player->update_tag_lock);
5126 /* release video bo lock and cond */
5127 g_mutex_clear(&player->video_bo_mutex);
5128 g_cond_clear(&player->video_bo_cond);
5132 return MM_ERROR_NONE;
5136 _mmplayer_realize(MMHandleType hplayer)
5138 mmplayer_t *player = (mmplayer_t *)hplayer;
5139 int ret = MM_ERROR_NONE;
5142 MMHandleType attrs = 0;
5146 /* check player handle */
5147 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5149 /* check current state */
5150 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5152 attrs = MMPLAYER_GET_ATTRS(player);
5154 LOGE("fail to get attributes.");
5155 return MM_ERROR_PLAYER_INTERNAL;
5157 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5158 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5160 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5161 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5163 if (ret != MM_ERROR_NONE) {
5164 LOGE("failed to parse profile");
5169 if (uri && (strstr(uri, "es_buff://"))) {
5170 if (strstr(uri, "es_buff://push_mode"))
5171 player->es_player_push_mode = TRUE;
5173 player->es_player_push_mode = FALSE;
5176 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5177 LOGW("mms protocol is not supported format.");
5178 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5181 if (MMPLAYER_IS_STREAMING(player))
5182 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5184 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5186 player->smooth_streaming = FALSE;
5187 player->videodec_linked = 0;
5188 player->audiodec_linked = 0;
5189 player->textsink_linked = 0;
5190 player->is_external_subtitle_present = FALSE;
5191 player->is_external_subtitle_added_now = FALSE;
5192 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5193 player->video360_metadata.is_spherical = -1;
5194 player->is_openal_plugin_used = FALSE;
5195 player->subtitle_language_list = NULL;
5196 player->is_subtitle_force_drop = FALSE;
5198 _mmplayer_track_initialize(player);
5199 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5201 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5202 gint prebuffer_ms = 0, rebuffer_ms = 0;
5204 player->streamer = _mm_player_streaming_create();
5205 _mm_player_streaming_initialize(player->streamer, TRUE);
5207 mm_attrs_multiple_get(player->attrs, NULL,
5208 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5209 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5211 if (prebuffer_ms > 0) {
5212 prebuffer_ms = MAX(prebuffer_ms, 1000);
5213 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5216 if (rebuffer_ms > 0) {
5217 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5218 rebuffer_ms = MAX(rebuffer_ms, 1000);
5219 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5222 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5223 player->streamer->buffering_req.rebuffer_time);
5226 /* realize pipeline */
5227 ret = __mmplayer_gst_realize(player);
5228 if (ret != MM_ERROR_NONE)
5229 LOGE("fail to realize the player.");
5231 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5239 _mmplayer_unrealize(MMHandleType hplayer)
5241 mmplayer_t *player = (mmplayer_t *)hplayer;
5242 int ret = MM_ERROR_NONE;
5243 int rm_ret = MM_ERROR_NONE;
5244 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5248 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5250 MMPLAYER_CMD_UNLOCK(player);
5251 _mmplayer_bus_watcher_remove(player);
5252 /* destroy the gst bus msg thread which is created during realize.
5253 this funct have to be called before getting cmd lock. */
5254 _mmplayer_bus_msg_thread_destroy(player);
5255 MMPLAYER_CMD_LOCK(player);
5257 /* check current state */
5258 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5260 /* check async state transition */
5261 __mmplayer_check_async_state_transition(player);
5263 /* unrealize pipeline */
5264 ret = __mmplayer_gst_unrealize(player);
5266 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5267 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5268 if (rm_ret != MM_ERROR_NONE)
5269 LOGE("failed to release [%d] resources", res_idx);
5272 player->interrupted_by_resource = FALSE;
5279 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5281 mmplayer_t *player = (mmplayer_t *)hplayer;
5283 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5285 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5289 _mmplayer_get_state(MMHandleType hplayer, int *state)
5291 mmplayer_t *player = (mmplayer_t *)hplayer;
5293 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5295 *state = MMPLAYER_CURRENT_STATE(player);
5297 return MM_ERROR_NONE;
5301 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5303 GstElement *vol_element = NULL;
5304 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5307 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5308 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5310 /* check pipeline handle */
5311 if (!player->pipeline || !player->pipeline->audiobin) {
5312 LOGD("'%s' will be applied when audiobin is created", prop_name);
5314 /* NOTE : stored value will be used in create_audiobin
5315 * returning MM_ERROR_NONE here makes application to able to
5316 * set audio volume or mute at anytime.
5318 return MM_ERROR_NONE;
5321 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5322 volume_elem_id = MMPLAYER_A_SINK;
5324 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5326 LOGE("failed to get vol element %d", volume_elem_id);
5327 return MM_ERROR_PLAYER_INTERNAL;
5330 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5332 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5333 LOGE("there is no '%s' property", prop_name);
5334 return MM_ERROR_PLAYER_INTERNAL;
5337 if (!strcmp(prop_name, "volume")) {
5338 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5339 } else if (!strcmp(prop_name, "mute")) {
5340 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5342 LOGE("invalid property %s", prop_name);
5343 return MM_ERROR_PLAYER_INTERNAL;
5346 return MM_ERROR_NONE;
5350 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5352 int ret = MM_ERROR_NONE;
5353 mmplayer_t *player = (mmplayer_t *)hplayer;
5356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5358 LOGD("volume = %f", volume);
5360 /* invalid factor range or not */
5361 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5362 LOGE("Invalid volume value");
5363 return MM_ERROR_INVALID_ARGUMENT;
5366 player->sound.volume = volume;
5368 ret = __mmplayer_gst_set_volume_property(player, "volume");
5375 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5377 mmplayer_t *player = (mmplayer_t *)hplayer;
5381 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5382 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5384 *volume = player->sound.volume;
5386 LOGD("current vol = %f", *volume);
5389 return MM_ERROR_NONE;
5393 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5395 int ret = MM_ERROR_NONE;
5396 mmplayer_t *player = (mmplayer_t *)hplayer;
5399 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5401 LOGD("mute = %d", mute);
5403 player->sound.mute = mute;
5405 ret = __mmplayer_gst_set_volume_property(player, "mute");
5412 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5414 mmplayer_t *player = (mmplayer_t *)hplayer;
5418 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5419 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5421 *mute = player->sound.mute;
5423 LOGD("current mute = %d", *mute);
5427 return MM_ERROR_NONE;
5431 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5433 mmplayer_t *player = (mmplayer_t *)hplayer;
5437 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5439 player->audio_stream_changed_cb = callback;
5440 player->audio_stream_changed_cb_user_param = user_param;
5441 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5445 return MM_ERROR_NONE;
5449 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5451 mmplayer_t *player = (mmplayer_t *)hplayer;
5455 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5457 player->audio_decoded_cb = callback;
5458 player->audio_decoded_cb_user_param = user_param;
5459 player->audio_extract_opt = opt;
5460 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5464 return MM_ERROR_NONE;
5468 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5470 mmplayer_t *player = (mmplayer_t *)hplayer;
5474 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5476 if (callback && !player->bufmgr)
5477 player->bufmgr = tbm_bufmgr_init(-1);
5479 player->set_mode.video_export = (callback) ? true : false;
5480 player->video_decoded_cb = callback;
5481 player->video_decoded_cb_user_param = user_param;
5483 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5487 return MM_ERROR_NONE;
5491 _mmplayer_start(MMHandleType hplayer)
5493 mmplayer_t *player = (mmplayer_t *)hplayer;
5494 gint ret = MM_ERROR_NONE;
5498 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5500 /* check current state */
5501 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5503 /* start pipeline */
5504 ret = _mmplayer_gst_start(player);
5505 if (ret != MM_ERROR_NONE)
5506 LOGE("failed to start player.");
5508 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5509 LOGD("force playing start even during buffering");
5510 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5518 /* NOTE: post "not supported codec message" to application
5519 * when one codec is not found during AUTOPLUGGING in MSL.
5520 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5521 * And, if any codec is not found, don't send message here.
5522 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5525 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5527 MMMessageParamType msg_param;
5528 memset(&msg_param, 0, sizeof(MMMessageParamType));
5529 gboolean post_msg_direct = FALSE;
5533 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5535 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5536 player->not_supported_codec, player->can_support_codec);
5538 if (player->not_found_demuxer) {
5539 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5540 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5542 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5543 MMPLAYER_FREEIF(msg_param.data);
5545 return MM_ERROR_NONE;
5548 if (player->not_supported_codec) {
5549 if (player->can_support_codec) {
5550 // There is one codec to play
5551 post_msg_direct = TRUE;
5553 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5554 post_msg_direct = TRUE;
5557 if (post_msg_direct) {
5558 MMMessageParamType msg_param;
5559 memset(&msg_param, 0, sizeof(MMMessageParamType));
5561 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5562 LOGW("not found AUDIO codec, posting error code to application.");
5564 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5565 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5566 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5567 LOGW("not found VIDEO codec, posting error code to application.");
5569 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5570 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5573 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5575 MMPLAYER_FREEIF(msg_param.data);
5577 return MM_ERROR_NONE;
5579 // no any supported codec case
5580 LOGW("not found any codec, posting error code to application.");
5582 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5583 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5584 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5586 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5587 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5590 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5592 MMPLAYER_FREEIF(msg_param.data);
5598 return MM_ERROR_NONE;
5601 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5603 GstState element_state = GST_STATE_VOID_PENDING;
5604 GstState element_pending_state = GST_STATE_VOID_PENDING;
5605 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5606 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5608 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5610 MMPLAYER_RECONFIGURE_LOCK(player);
5611 if (!player->gapless.reconfigure) {
5612 MMPLAYER_RECONFIGURE_UNLOCK(player);
5616 LOGI("reconfigure is under process");
5617 MMPLAYER_RECONFIGURE_WAIT(player);
5618 MMPLAYER_RECONFIGURE_UNLOCK(player);
5619 LOGI("reconfigure is completed.");
5621 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5622 &element_state, &element_pending_state, timeout * GST_SECOND);
5623 if (result == GST_STATE_CHANGE_FAILURE)
5624 LOGW("failed to get pipeline state in %d sec", timeout);
5629 /* NOTE : it should be able to call 'stop' anytime*/
5631 _mmplayer_stop(MMHandleType hplayer)
5633 mmplayer_t *player = (mmplayer_t *)hplayer;
5634 int ret = MM_ERROR_NONE;
5638 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5640 /* check current state */
5641 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5643 /* need to wait till the rebuilding pipeline is completed */
5644 __mmplayer_check_pipeline_reconfigure_state(player);
5645 MMPLAYER_RECONFIGURE_LOCK(player);
5646 __mmplayer_reset_gapless_state(player);
5647 MMPLAYER_RECONFIGURE_UNLOCK(player);
5649 /* NOTE : application should not wait for EOS after calling STOP */
5650 _mmplayer_cancel_eos_timer(player);
5653 player->seek_state = MMPLAYER_SEEK_NONE;
5656 ret = _mmplayer_gst_stop(player);
5658 if (ret != MM_ERROR_NONE)
5659 LOGE("failed to stop player.");
5667 _mmplayer_pause(MMHandleType hplayer)
5669 mmplayer_t *player = (mmplayer_t *)hplayer;
5670 gint64 pos_nsec = 0;
5671 gboolean async = FALSE;
5672 gint ret = MM_ERROR_NONE;
5676 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5678 /* check current state */
5679 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5681 /* check pipeline reconfigure state */
5682 __mmplayer_check_pipeline_reconfigure_state(player);
5684 switch (MMPLAYER_CURRENT_STATE(player)) {
5685 case MM_PLAYER_STATE_READY:
5687 /* check prepare async or not.
5688 * In the case of streaming playback, it's recommended to avoid blocking wait.
5690 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5691 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5693 /* Changing back sync of rtspsrc to async */
5694 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5695 LOGD("async prepare working mode for rtsp");
5701 case MM_PLAYER_STATE_PLAYING:
5703 /* NOTE : store current point to overcome some bad operation
5704 *(returning zero when getting current position in paused state) of some
5707 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5708 LOGW("getting current position failed in paused");
5710 player->last_position = pos_nsec;
5712 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5713 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5714 This causes problem is position calculation during normal pause resume scenarios also.
5715 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5716 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5717 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5718 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5724 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5725 LOGD("doing async pause in case of ms buff src");
5729 /* pause pipeline */
5730 ret = _mmplayer_gst_pause(player, async);
5731 if (ret != MM_ERROR_NONE) {
5732 LOGE("failed to pause player. ret : 0x%x", ret);
5733 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5737 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5738 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5739 LOGE("failed to update display_rotation");
5743 return MM_ERROR_NONE;
5746 /* in case of streaming, pause could take long time.*/
5748 _mmplayer_abort_pause(MMHandleType hplayer)
5750 mmplayer_t *player = (mmplayer_t *)hplayer;
5751 int ret = MM_ERROR_NONE;
5755 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5757 player->pipeline->mainbin,
5758 MM_ERROR_PLAYER_NOT_INITIALIZED);
5760 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5761 LOGD("set the videobin state to READY");
5762 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5763 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5767 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5768 LOGD("set the audiobin state to READY");
5769 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5770 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5774 LOGD("set the pipeline state to READY");
5775 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5776 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5778 if (ret != MM_ERROR_NONE) {
5779 LOGE("fail to change state to READY");
5780 return MM_ERROR_PLAYER_INTERNAL;
5783 LOGD("succeeded in changing state to READY");
5788 _mmplayer_resume(MMHandleType hplayer)
5790 mmplayer_t *player = (mmplayer_t *)hplayer;
5791 int ret = MM_ERROR_NONE;
5792 gboolean async = FALSE;
5796 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5798 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5799 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5800 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5804 /* Changing back sync mode rtspsrc to async */
5805 LOGD("async resume for rtsp case");
5809 /* check current state */
5810 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5812 ret = _mmplayer_gst_resume(player, async);
5813 if (ret != MM_ERROR_NONE)
5814 LOGE("failed to resume player.");
5816 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5817 LOGD("force resume even during buffering");
5818 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5827 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5829 mmplayer_t *player = (mmplayer_t *)hplayer;
5830 gint64 pos_nsec = 0;
5831 int ret = MM_ERROR_NONE;
5833 signed long long start = 0, stop = 0;
5834 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5837 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5838 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5840 /* The sound of video is not supported under 0.0 and over 2.0. */
5841 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5842 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5845 _mmplayer_set_mute(hplayer, mute);
5847 if (player->playback_rate == rate)
5848 return MM_ERROR_NONE;
5850 /* If the position is reached at start potion during fast backward, EOS is posted.
5851 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5853 player->playback_rate = rate;
5855 current_state = MMPLAYER_CURRENT_STATE(player);
5857 if (current_state != MM_PLAYER_STATE_PAUSED)
5858 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5860 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5862 if ((current_state == MM_PLAYER_STATE_PAUSED)
5863 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5864 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5865 pos_nsec = player->last_position;
5870 stop = GST_CLOCK_TIME_NONE;
5872 start = GST_CLOCK_TIME_NONE;
5876 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5877 player->playback_rate,
5879 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5880 GST_SEEK_TYPE_SET, start,
5881 GST_SEEK_TYPE_SET, stop)) {
5882 LOGE("failed to set speed playback");
5883 return MM_ERROR_PLAYER_SEEK;
5886 LOGD("succeeded to set speed playback as %0.1f", rate);
5890 return MM_ERROR_NONE;;
5894 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5896 mmplayer_t *player = (mmplayer_t *)hplayer;
5897 int ret = MM_ERROR_NONE;
5901 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5903 /* check pipeline reconfigure state */
5904 __mmplayer_check_pipeline_reconfigure_state(player);
5906 ret = _mmplayer_gst_set_position(player, position, FALSE);
5914 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5916 mmplayer_t *player = (mmplayer_t *)hplayer;
5917 int ret = MM_ERROR_NONE;
5919 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5920 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5922 if (g_strrstr(player->type, "video/mpegts"))
5923 __mmplayer_update_duration_value(player);
5925 *duration = player->duration;
5930 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5932 mmplayer_t *player = (mmplayer_t *)hplayer;
5933 int ret = MM_ERROR_NONE;
5935 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5937 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5943 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5945 mmplayer_t *player = (mmplayer_t *)hplayer;
5946 int ret = MM_ERROR_NONE;
5950 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5952 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5960 __mmplayer_is_midi_type(gchar *str_caps)
5962 if ((g_strrstr(str_caps, "audio/midi")) ||
5963 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5964 (g_strrstr(str_caps, "application/x-smaf")) ||
5965 (g_strrstr(str_caps, "audio/x-imelody")) ||
5966 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5967 (g_strrstr(str_caps, "audio/xmf")) ||
5968 (g_strrstr(str_caps, "audio/mxmf"))) {
5977 __mmplayer_is_only_mp3_type(gchar *str_caps)
5979 if (g_strrstr(str_caps, "application/x-id3") ||
5980 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5986 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5988 GstStructure *caps_structure = NULL;
5989 gint samplerate = 0;
5993 MMPLAYER_RETURN_IF_FAIL(player && caps);
5995 caps_structure = gst_caps_get_structure(caps, 0);
5997 /* set stream information */
5998 gst_structure_get_int(caps_structure, "rate", &samplerate);
5999 gst_structure_get_int(caps_structure, "channels", &channels);
6001 mm_player_set_attribute((MMHandleType)player, NULL,
6002 "content_audio_samplerate", samplerate,
6003 "content_audio_channels", channels, NULL);
6005 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6009 __mmplayer_update_content_type_info(mmplayer_t *player)
6012 MMPLAYER_RETURN_IF_FAIL(player && player->type);
6014 if (__mmplayer_is_midi_type(player->type)) {
6015 player->bypass_audio_effect = TRUE;
6019 if (!player->streamer) {
6020 LOGD("no need to check streaming type");
6024 if (g_strrstr(player->type, "application/x-hls")) {
6025 /* If it can't know exact type when it parses uri because of redirection case,
6026 * it will be fixed by typefinder or when doing autoplugging.
6028 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6029 player->streamer->is_adaptive_streaming = TRUE;
6030 } else if (g_strrstr(player->type, "application/dash+xml")) {
6031 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6032 player->streamer->is_adaptive_streaming = TRUE;
6035 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6036 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
6037 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6039 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6040 if (player->streamer->is_adaptive_streaming)
6041 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6043 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6047 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6052 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6053 GstCaps *caps, gpointer data)
6055 mmplayer_t *player = (mmplayer_t *)data;
6059 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6061 /* store type string */
6062 if (player->type_caps) {
6063 gst_caps_unref(player->type_caps);
6064 player->type_caps = NULL;
6067 player->type_caps = gst_caps_copy(caps);
6068 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
6070 MMPLAYER_FREEIF(player->type);
6071 player->type = gst_caps_to_string(caps);
6073 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6074 player, player->type, probability, gst_caps_get_size(caps));
6076 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6077 (g_strrstr(player->type, "audio/x-raw-int"))) {
6078 LOGE("not support media format");
6080 if (player->msg_posted == FALSE) {
6081 MMMessageParamType msg_param;
6082 memset(&msg_param, 0, sizeof(MMMessageParamType));
6084 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6085 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6087 /* don't post more if one was sent already */
6088 player->msg_posted = TRUE;
6093 __mmplayer_update_content_type_info(player);
6095 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6098 pad = gst_element_get_static_pad(tf, "src");
6100 LOGE("fail to get typefind src pad.");
6104 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6105 gboolean async = FALSE;
6106 LOGE("failed to autoplug %s", player->type);
6108 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6110 if (async && player->msg_posted == FALSE)
6111 __mmplayer_handle_missed_plugin(player);
6113 gst_object_unref(GST_OBJECT(pad));
6120 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6122 GstElement *decodebin = NULL;
6126 /* create decodebin */
6127 decodebin = gst_element_factory_make("decodebin", NULL);
6130 LOGE("fail to create decodebin");
6134 /* raw pad handling signal */
6135 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6136 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6138 /* no-more-pad pad handling signal */
6139 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6140 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6142 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6143 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6145 /* This signal is emitted when a pad for which there is no further possible
6146 decoding is added to the decodebin.*/
6147 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6148 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6150 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6151 before looking for any elements that can handle that stream.*/
6152 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6153 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6155 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6156 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6157 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6159 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6160 before looking for any elements that can handle that stream.*/
6161 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6162 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6164 /* This signal is emitted once decodebin has finished decoding all the data.*/
6165 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6166 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6168 /* This signal is emitted when a element is added to the bin.*/
6169 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6170 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6177 __mmplayer_gst_make_queue2(mmplayer_t *player)
6179 GstElement *queue2 = NULL;
6180 gint64 dur_bytes = 0L;
6181 mmplayer_gst_element_t *mainbin = NULL;
6182 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6185 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6187 mainbin = player->pipeline->mainbin;
6189 queue2 = gst_element_factory_make("queue2", "queue2");
6191 LOGE("failed to create buffering queue element");
6195 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6196 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6198 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6200 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6201 * skip the pull mode(file or ring buffering) setting. */
6202 if (dur_bytes > 0) {
6203 if (!g_strrstr(player->type, "video/mpegts")) {
6204 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6205 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6211 _mm_player_streaming_set_queue2(player->streamer,
6215 (guint64)dur_bytes); /* no meaning at the moment */
6221 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6223 mmplayer_gst_element_t *mainbin = NULL;
6224 GstElement *decodebin = NULL;
6225 GstElement *queue2 = NULL;
6226 GstPad *sinkpad = NULL;
6227 GstPad *qsrcpad = NULL;
6230 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6232 mainbin = player->pipeline->mainbin;
6234 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6236 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6237 LOGW("need to check: muxed buffer is not null");
6240 queue2 = __mmplayer_gst_make_queue2(player);
6242 LOGE("failed to make queue2");
6246 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6247 LOGE("failed to add buffering queue");
6251 sinkpad = gst_element_get_static_pad(queue2, "sink");
6252 qsrcpad = gst_element_get_static_pad(queue2, "src");
6254 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6255 LOGE("failed to link [%s:%s]-[%s:%s]",
6256 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6260 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6261 LOGE("failed to sync queue2 state with parent");
6265 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6266 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6270 gst_object_unref(GST_OBJECT(sinkpad));
6274 /* create decodebin */
6275 decodebin = _mmplayer_gst_make_decodebin(player);
6277 LOGE("failed to make decodebin");
6281 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6282 LOGE("failed to add decodebin");
6286 /* to force caps on the decodebin element and avoid reparsing stuff by
6287 * typefind. It also avoids a deadlock in the way typefind activates pads in
6288 * the state change */
6289 g_object_set(decodebin, "sink-caps", caps, NULL);
6291 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6293 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6294 LOGE("failed to link [%s:%s]-[%s:%s]",
6295 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6299 gst_object_unref(GST_OBJECT(sinkpad));
6301 gst_object_unref(GST_OBJECT(qsrcpad));
6304 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6305 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6307 /* set decodebin property about buffer in streaming playback. *
6308 * in case of HLS/DASH, it does not need to have big buffer *
6309 * because it is kind of adaptive streaming. */
6310 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6311 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6312 gint high_percent = 0;
6314 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6315 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6317 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6319 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6321 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6322 "high-percent", high_percent,
6323 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6324 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6325 "max-size-buffers", 0, NULL); // disable or automatic
6328 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6329 LOGE("failed to sync decodebin state with parent");
6340 gst_object_unref(GST_OBJECT(sinkpad));
6343 gst_object_unref(GST_OBJECT(qsrcpad));
6346 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6347 * You need to explicitly set elements to the NULL state before
6348 * dropping the final reference, to allow them to clean up.
6350 gst_element_set_state(queue2, GST_STATE_NULL);
6352 /* And, it still has a parent "player".
6353 * You need to let the parent manage the object instead of unreffing the object directly.
6355 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6356 LOGE("failed to remove queue2");
6357 gst_object_unref(queue2);
6363 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6364 * You need to explicitly set elements to the NULL state before
6365 * dropping the final reference, to allow them to clean up.
6367 gst_element_set_state(decodebin, GST_STATE_NULL);
6369 /* And, it still has a parent "player".
6370 * You need to let the parent manage the object instead of unreffing the object directly.
6373 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6374 LOGE("failed to remove decodebin");
6375 gst_object_unref(decodebin);
6384 _mmplayer_update_not_supported_codec_info(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6388 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6389 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6391 LOGD("class : %s, mime : %s", factory_class, mime);
6393 /* add missing plugin */
6394 /* NOTE : msl should check missing plugin for image mime type.
6395 * Some motion jpeg clips can have playable audio track.
6396 * So, msl have to play audio after displaying popup written video format not supported.
6398 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6399 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6400 LOGD("not found demuxer");
6401 player->not_found_demuxer = TRUE;
6402 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6408 if (!g_strrstr(factory_class, "Demuxer")) {
6409 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6410 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6411 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6413 /* check that clip have multi tracks or not */
6414 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6415 LOGD("video plugin is already linked");
6417 LOGW("add VIDEO to missing plugin");
6418 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6419 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6421 } else if (g_str_has_prefix(mime, "audio")) {
6422 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6423 LOGD("audio plugin is already linked");
6425 LOGW("add AUDIO to missing plugin");
6426 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6427 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6435 return MM_ERROR_NONE;
6439 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6441 mmplayer_t *player = (mmplayer_t *)data;
6445 MMPLAYER_RETURN_IF_FAIL(player);
6447 /* remove fakesink. */
6448 if (!_mmplayer_gst_remove_fakesink(player,
6449 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6450 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6451 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6452 * source element are not same. To overcome this situation, this function will called
6453 * several places and several times. Therefore, this is not an error case.
6458 LOGD("[handle: %p] pipeline has completely constructed", player);
6460 if ((player->msg_posted == FALSE) &&
6461 (player->cmd >= MMPLAYER_COMMAND_START))
6462 __mmplayer_handle_missed_plugin(player);
6464 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6468 __mmplayer_check_profile(void)
6471 static int profile_tv = -1;
6473 if (__builtin_expect(profile_tv != -1, 1))
6476 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6477 switch (*profileName) {
6492 __mmplayer_get_next_uri(mmplayer_t *player)
6494 mmplayer_parse_profile_t profile;
6496 guint num_of_list = 0;
6499 num_of_list = g_list_length(player->uri_info.uri_list);
6500 uri_idx = player->uri_info.uri_idx;
6502 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6503 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6504 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6506 LOGW("next uri does not exist");
6510 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6511 LOGE("failed to parse profile");
6515 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6516 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6517 LOGW("uri type is not supported(%d)", profile.uri_type);
6521 LOGD("success to find next uri %d", uri_idx);
6525 if (!uri || uri_idx == num_of_list) {
6526 LOGE("failed to find next uri");
6530 player->uri_info.uri_idx = uri_idx;
6531 if (mm_player_set_attribute((MMHandleType)player, NULL,
6532 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6533 LOGE("failed to set attribute");
6537 SECURE_LOGD("next playback uri: %s", uri);
6542 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6544 #define REPEAT_COUNT_INFINITE -1
6545 #define REPEAT_COUNT_MIN 2
6546 #define ORIGINAL_URI_ONLY 1
6548 MMHandleType attrs = 0;
6552 guint num_of_uri = 0;
6553 int profile_tv = -1;
6557 LOGD("checking for gapless play option");
6559 if (player->build_audio_offload) {
6560 LOGE("offload path is not supportable.");
6564 if (player->pipeline->textbin) {
6565 LOGE("subtitle path is enabled. gapless play is not supported.");
6569 attrs = MMPLAYER_GET_ATTRS(player);
6571 LOGE("fail to get attributes.");
6575 mm_attrs_multiple_get(player->attrs, NULL,
6576 "content_video_found", &video,
6577 "profile_play_count", &count,
6578 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6580 /* gapless playback is not supported in case of video at TV profile. */
6581 profile_tv = __mmplayer_check_profile();
6582 if (profile_tv && video) {
6583 LOGW("not support video gapless playback");
6587 /* check repeat count in case of audio */
6589 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6590 LOGW("gapless is disabled");
6594 num_of_uri = g_list_length(player->uri_info.uri_list);
6596 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6598 if (num_of_uri == ORIGINAL_URI_ONLY) {
6599 /* audio looping path */
6600 if (count >= REPEAT_COUNT_MIN) {
6601 /* decrease play count */
6602 /* we succeeded to rewind. update play count and then wait for next EOS */
6604 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6605 } else if (count != REPEAT_COUNT_INFINITE) {
6606 LOGD("there is no next uri and no repeat");
6609 LOGD("looping cnt %d", count);
6611 /* gapless playback path */
6612 if (!__mmplayer_get_next_uri(player)) {
6613 LOGE("failed to get next uri");
6620 LOGE("unable to play gapless path. EOS will be posted soon");
6625 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6627 GstPad *sinkpad = g_value_get_object (item);
6628 GstElement *element = GST_ELEMENT(user_data);
6629 if (!sinkpad || !element) {
6630 LOGE("invalid parameter");
6634 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6635 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6639 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6641 mmplayer_gst_element_t *sinkbin = NULL;
6642 main_element_id_e concatId = MMPLAYER_M_NUM;
6643 main_element_id_e sinkId = MMPLAYER_M_NUM;
6644 gboolean send_notice = FALSE;
6645 GstElement *element;
6649 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6651 LOGD("type %d", type);
6654 case MM_PLAYER_TRACK_TYPE_AUDIO:
6655 concatId = MMPLAYER_M_A_CONCAT;
6656 sinkId = MMPLAYER_A_BIN;
6657 sinkbin = player->pipeline->audiobin;
6659 case MM_PLAYER_TRACK_TYPE_VIDEO:
6660 concatId = MMPLAYER_M_V_CONCAT;
6661 sinkId = MMPLAYER_V_BIN;
6662 sinkbin = player->pipeline->videobin;
6665 case MM_PLAYER_TRACK_TYPE_TEXT:
6666 concatId = MMPLAYER_M_T_CONCAT;
6667 sinkId = MMPLAYER_T_BIN;
6668 sinkbin = player->pipeline->textbin;
6671 LOGE("requested type is not supportable");
6676 element = player->pipeline->mainbin[concatId].gst;
6680 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6681 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6682 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6683 if (srcpad && sinkpad) {
6684 /* after getting drained signal there is no data flows, so no need to do pad_block */
6685 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6686 gst_pad_unlink(srcpad, sinkpad);
6688 /* send custom event to sink pad to handle it at video sink */
6690 LOGD("send custom event to sinkpad");
6691 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6692 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6693 gst_pad_send_event(sinkpad, event);
6696 gst_object_unref(srcpad);
6697 gst_object_unref(sinkpad);
6700 LOGD("release concat request pad");
6701 /* release and unref requests pad from the selector */
6702 iter = gst_element_iterate_sink_pads(element);
6703 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6704 gst_iterator_resync(iter);
6705 gst_iterator_free(iter);
6711 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6713 mmplayer_track_t *selector = &player->track[type];
6714 mmplayer_gst_element_t *sinkbin = NULL;
6715 main_element_id_e selectorId = MMPLAYER_M_NUM;
6716 main_element_id_e sinkId = MMPLAYER_M_NUM;
6717 GstPad *srcpad = NULL;
6718 GstPad *sinkpad = NULL;
6719 gboolean send_notice = FALSE;
6722 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6724 LOGD("type %d", type);
6727 case MM_PLAYER_TRACK_TYPE_AUDIO:
6728 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6729 sinkId = MMPLAYER_A_BIN;
6730 sinkbin = player->pipeline->audiobin;
6732 case MM_PLAYER_TRACK_TYPE_VIDEO:
6733 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6734 sinkId = MMPLAYER_V_BIN;
6735 sinkbin = player->pipeline->videobin;
6738 case MM_PLAYER_TRACK_TYPE_TEXT:
6739 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6740 sinkId = MMPLAYER_T_BIN;
6741 sinkbin = player->pipeline->textbin;
6744 LOGE("requested type is not supportable");
6749 if (player->pipeline->mainbin[selectorId].gst) {
6752 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6754 if (selector->event_probe_id != 0)
6755 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6756 selector->event_probe_id = 0;
6758 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6759 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6761 if (srcpad && sinkpad) {
6762 /* after getting drained signal there is no data flows, so no need to do pad_block */
6763 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6764 gst_pad_unlink(srcpad, sinkpad);
6766 /* send custom event to sink pad to handle it at video sink */
6768 LOGD("send custom event to sinkpad");
6769 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6770 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6771 gst_pad_send_event(sinkpad, event);
6775 gst_object_unref(sinkpad);
6778 gst_object_unref(srcpad);
6781 LOGD("selector release");
6783 /* release and unref requests pad from the selector */
6784 for (n = 0; n < selector->streams->len; n++) {
6785 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6786 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6789 g_ptr_array_set_size(selector->streams, 0);
6791 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6792 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6793 player->pipeline->mainbin[selectorId].gst)) {
6794 LOGE("failed to remove selector");
6795 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6798 player->pipeline->mainbin[selectorId].gst = NULL;
6806 __mmplayer_deactivate_old_path(mmplayer_t *player)
6809 MMPLAYER_RETURN_IF_FAIL(player);
6811 if (MMPLAYER_USE_DECODEBIN(player)) {
6812 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6813 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6814 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6815 LOGE("deactivate selector error");
6819 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6820 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6821 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6822 LOGE("deactivate concat error");
6827 _mmplayer_track_destroy(player);
6828 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6830 if (player->streamer) {
6831 _mm_player_streaming_initialize(player->streamer, FALSE);
6832 _mm_player_streaming_destroy(player->streamer);
6833 player->streamer = NULL;
6836 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6842 if (!player->msg_posted) {
6843 MMMessageParamType msg = {0,};
6846 msg.code = MM_ERROR_PLAYER_INTERNAL;
6847 LOGE("gapless_uri_play> deactivate error");
6849 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6850 player->msg_posted = TRUE;
6856 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6858 int result = MM_ERROR_NONE;
6859 mmplayer_t *player = (mmplayer_t *)hplayer;
6862 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6863 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6865 if (mm_player_set_attribute(hplayer, NULL,
6866 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6867 LOGE("failed to set attribute");
6868 result = MM_ERROR_PLAYER_INTERNAL;
6870 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6871 LOGE("failed to add the original uri in the uri list.");
6879 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6881 mmplayer_t *player = (mmplayer_t *)hplayer;
6882 guint num_of_list = 0;
6886 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6887 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6889 if (player->pipeline && player->pipeline->textbin) {
6890 LOGE("subtitle path is enabled.");
6891 return MM_ERROR_PLAYER_INVALID_STATE;
6894 num_of_list = g_list_length(player->uri_info.uri_list);
6896 if (is_first_path) {
6897 if (num_of_list == 0) {
6898 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6899 SECURE_LOGD("add original path : %s", uri);
6901 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6902 player->uri_info.uri_list = g_list_prepend(
6903 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6904 SECURE_LOGD("change original path : %s", uri);
6907 MMHandleType attrs = 0;
6908 attrs = MMPLAYER_GET_ATTRS(player);
6910 if (num_of_list == 0) {
6911 char *original_uri = NULL;
6914 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6916 if (!original_uri) {
6917 LOGE("there is no original uri.");
6918 return MM_ERROR_PLAYER_INVALID_STATE;
6921 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6922 player->uri_info.uri_idx = 0;
6924 SECURE_LOGD("add original path at first : %s", original_uri);
6928 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6929 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6933 return MM_ERROR_NONE;
6937 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6939 mmplayer_t *player = (mmplayer_t *)hplayer;
6940 char *next_uri = NULL;
6941 guint num_of_list = 0;
6944 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6946 num_of_list = g_list_length(player->uri_info.uri_list);
6948 if (num_of_list > 0) {
6949 gint uri_idx = player->uri_info.uri_idx;
6951 if (uri_idx < num_of_list - 1)
6956 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6957 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6959 *uri = g_strdup(next_uri);
6963 return MM_ERROR_NONE;
6967 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6968 GstCaps *caps, gpointer data)
6970 mmplayer_t *player = (mmplayer_t *)data;
6971 const gchar *klass = NULL;
6972 const gchar *mime = NULL;
6973 gchar *caps_str = NULL;
6975 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6976 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6977 caps_str = gst_caps_to_string(caps);
6979 LOGW("unknown type of caps : %s from %s",
6980 caps_str, GST_ELEMENT_NAME(elem));
6982 MMPLAYER_FREEIF(caps_str);
6984 /* There is no available codec. */
6985 _mmplayer_update_not_supported_codec_info(player, klass, mime);
6989 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6990 GstCaps *caps, gpointer data)
6992 mmplayer_t *player = (mmplayer_t *)data;
6993 const char *mime = NULL;
6994 gboolean ret = TRUE;
6996 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6997 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6999 if (g_str_has_prefix(mime, "audio")) {
7000 GstStructure *caps_structure = NULL;
7001 gint samplerate = 0;
7003 gchar *caps_str = NULL;
7005 caps_structure = gst_caps_get_structure(caps, 0);
7006 gst_structure_get_int(caps_structure, "rate", &samplerate);
7007 gst_structure_get_int(caps_structure, "channels", &channels);
7009 if ((channels > 0 && samplerate == 0)) {
7010 LOGD("exclude audio...");
7014 caps_str = gst_caps_to_string(caps);
7015 /* set it directly because not sent by TAG */
7016 if (g_strrstr(caps_str, "mobile-xmf"))
7017 mm_player_set_attribute((MMHandleType)player, NULL,
7018 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7020 MMPLAYER_FREEIF(caps_str);
7021 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7022 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7023 LOGD("video is already linked, allow the stream switch");
7026 LOGD("video is already linked");
7030 LOGD("found new stream");
7037 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7039 gboolean ret = FALSE;
7040 GDBusConnection *conn = NULL;
7042 GVariant *result = NULL;
7043 const gchar *dbus_device_type = NULL;
7044 const gchar *dbus_ret = NULL;
7047 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7049 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7054 result = g_dbus_connection_call_sync(conn,
7055 "org.pulseaudio.Server",
7056 "/org/pulseaudio/StreamManager",
7057 "org.pulseaudio.StreamManager",
7058 "GetCurrentMediaRoutingPath",
7059 g_variant_new("(s)", "out"),
7060 G_VARIANT_TYPE("(ss)"),
7061 G_DBUS_CALL_FLAGS_NONE,
7065 if (!result || err) {
7066 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7071 /* device type is listed in stream-map.json at mmfw-sysconf */
7072 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7074 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7075 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7078 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7079 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7080 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7081 LOGD("audio offload is supportable");
7087 LOGD("audio offload is not supportable");
7090 g_variant_unref(result);
7092 g_object_unref(conn);
7097 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7099 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7100 gint64 position = 0;
7102 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7103 player->pipeline && player->pipeline->mainbin);
7105 MMPLAYER_CMD_LOCK(player);
7106 current_state = MMPLAYER_CURRENT_STATE(player);
7108 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7109 LOGW("getting current position failed in paused");
7111 _mmplayer_unrealize((MMHandleType)player);
7112 _mmplayer_realize((MMHandleType)player);
7114 _mmplayer_set_position((MMHandleType)player, position);
7116 /* async not to be blocked in streaming case */
7117 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7119 _mmplayer_pause((MMHandleType)player);
7121 if (current_state == MM_PLAYER_STATE_PLAYING)
7122 _mmplayer_start((MMHandleType)player);
7123 MMPLAYER_CMD_UNLOCK(player);
7125 LOGD("rebuilding audio pipeline is completed.");
7128 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7130 mmplayer_t *player = (mmplayer_t *)user_data;
7131 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7132 gboolean is_supportable = FALSE;
7134 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7135 LOGW("failed to get device type");
7137 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7139 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7140 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7141 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7142 LOGD("ignore this dev connected info");
7146 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7147 if (player->build_audio_offload == is_supportable) {
7148 LOGD("keep current pipeline without re-building");
7152 /* rebuild pipeline */
7153 LOGD("re-build pipeline - offload: %d", is_supportable);
7154 player->build_audio_offload = FALSE;
7155 __mmplayer_rebuild_audio_pipeline(player);
7161 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7163 unsigned int id = 0;
7165 if (player->audio_device_cb_id != 0) {
7166 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7170 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7171 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7172 LOGD("added device connected cb (%u)", id);
7173 player->audio_device_cb_id = id;
7175 LOGW("failed to add device connected cb");
7182 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7184 mmplayer_t *player = (mmplayer_t *)hplayer;
7187 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7188 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7190 *activated = player->build_audio_offload;
7192 LOGD("offload activated : %d", (int)*activated);
7195 return MM_ERROR_NONE;
7199 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7202 this function need to be updated according to the supported media format
7203 @see player->ini.audio_offload_media_format */
7205 if (__mmplayer_is_only_mp3_type(player->type)) {
7206 LOGD("offload supportable media format type");
7214 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7216 gboolean ret = FALSE;
7217 GstElementFactory *factory = NULL;
7220 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7222 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7223 if (!__mmplayer_is_offload_supported_type(player))
7226 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7227 LOGD("there is no audio offload sink");
7231 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7232 LOGW("there is no audio device type to support offload");
7236 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7238 LOGW("there is no installed audio offload sink element");
7241 gst_object_unref(factory);
7243 if (_mmplayer_acquire_hw_resource(player,
7244 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7245 LOGE("failed to acquire audio offload decoder resource");
7249 if (!__mmplayer_add_audio_device_connected_cb(player))
7252 if (!__mmplayer_is_audio_offload_device_type(player))
7255 LOGD("audio offload can be built");
7260 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7266 static GstAutoplugSelectResult
7267 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7269 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7270 int audio_offload = 0;
7272 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7273 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7275 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7276 LOGD("expose audio path to build offload output path");
7277 player->build_audio_offload = TRUE;
7278 /* update codec info */
7279 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7280 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7281 player->audiodec_linked = 1;
7283 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7287 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7288 And need to consider the multi-track audio content.
7289 There is no HW audio decoder in public. */
7291 /* set stream information */
7292 if (!player->audiodec_linked)
7293 _mmplayer_set_audio_attrs(player, caps);
7295 /* update codec info */
7296 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7297 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7298 player->audiodec_linked = 1;
7300 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7302 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7303 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7305 /* mark video decoder for acquire */
7306 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7307 LOGW("video decoder resource is already acquired, skip it.");
7308 ret = GST_AUTOPLUG_SELECT_SKIP;
7312 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7313 LOGE("failed to acquire video decoder resource");
7314 ret = GST_AUTOPLUG_SELECT_SKIP;
7317 player->interrupted_by_resource = FALSE;
7320 /* update codec info */
7321 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7322 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7323 player->videodec_linked = 1;
7331 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7332 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7334 #define DEFAULT_IDX 0xFFFF
7335 #define MIN_FACTORY_NUM 2
7336 mmplayer_t *player = (mmplayer_t *)data;
7337 GValueArray *new_factories = NULL;
7338 GValue val = { 0, };
7339 GstElementFactory *factory = NULL;
7340 const gchar *klass = NULL;
7341 gchar *factory_name = NULL;
7342 guint hw_dec_idx = DEFAULT_IDX;
7343 guint first_sw_dec_idx = DEFAULT_IDX;
7344 guint last_sw_dec_idx = DEFAULT_IDX;
7345 guint new_pos = DEFAULT_IDX;
7346 guint rm_pos = DEFAULT_IDX;
7347 int audio_codec_type;
7348 int video_codec_type;
7349 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7351 if (factories->n_values < MIN_FACTORY_NUM)
7354 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7355 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7358 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7360 for (int i = 0 ; i < factories->n_values ; i++) {
7361 gchar *hw_dec_info = NULL;
7362 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7364 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7366 LOGW("failed to get factory object");
7369 klass = gst_element_factory_get_klass(factory);
7370 factory_name = GST_OBJECT_NAME(factory);
7373 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7375 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7376 if (!player->need_audio_dec_sorting) {
7377 LOGD("sorting is not required");
7380 codec_type = audio_codec_type;
7381 hw_dec_info = player->ini.audiocodec_element_hw;
7382 sw_dec_info = player->ini.audiocodec_element_sw;
7383 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7384 if (!player->need_video_dec_sorting) {
7385 LOGD("sorting is not required");
7388 codec_type = video_codec_type;
7389 hw_dec_info = player->ini.videocodec_element_hw;
7390 sw_dec_info = player->ini.videocodec_element_sw;
7395 if (g_strrstr(factory_name, hw_dec_info)) {
7398 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7399 if (strstr(factory_name, sw_dec_info[j])) {
7400 last_sw_dec_idx = i;
7401 if (first_sw_dec_idx == DEFAULT_IDX) {
7402 first_sw_dec_idx = i;
7407 if (first_sw_dec_idx == DEFAULT_IDX)
7408 LOGW("unknown codec %s", factory_name);
7412 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7415 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7416 if (hw_dec_idx < first_sw_dec_idx)
7418 new_pos = first_sw_dec_idx;
7419 rm_pos = hw_dec_idx + 1;
7420 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7421 if (last_sw_dec_idx < hw_dec_idx)
7423 new_pos = last_sw_dec_idx + 1;
7424 rm_pos = hw_dec_idx;
7429 /* change position - insert H/W decoder according to the new position */
7430 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7432 LOGW("failed to get factory object");
7435 new_factories = g_value_array_copy(factories);
7436 g_value_init (&val, G_TYPE_OBJECT);
7437 g_value_set_object (&val, factory);
7438 g_value_array_insert(new_factories, new_pos, &val);
7439 g_value_unset (&val);
7440 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7442 for (int i = 0 ; i < new_factories->n_values ; i++) {
7443 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7445 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7446 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7448 LOGE("[Re-arranged] failed to get factory object");
7451 return new_factories;
7455 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7456 GstCaps *caps, GstElementFactory *factory, gpointer data)
7458 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7459 mmplayer_t *player = (mmplayer_t *)data;
7461 gchar *factory_name = NULL;
7462 gchar *caps_str = NULL;
7463 const gchar *klass = NULL;
7466 factory_name = GST_OBJECT_NAME(factory);
7467 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7468 caps_str = gst_caps_to_string(caps);
7470 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7472 /* store type string */
7473 if (player->type == NULL) {
7474 player->type = gst_caps_to_string(caps);
7475 __mmplayer_update_content_type_info(player);
7478 /* filtering exclude keyword */
7479 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7480 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7481 LOGW("skipping [%s] by exclude keyword [%s]",
7482 factory_name, player->ini.exclude_element_keyword[idx]);
7484 result = GST_AUTOPLUG_SELECT_SKIP;
7489 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7490 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7491 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7492 factory_name, player->ini.unsupported_codec_keyword[idx]);
7493 result = GST_AUTOPLUG_SELECT_SKIP;
7498 /* exclude webm format */
7499 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7500 * because webm format is not supportable.
7501 * If webm is disabled in "autoplug-continue", there is no state change
7502 * failure or error because the decodebin will expose the pad directly.
7503 * It make MSL invoke _prepare_async_callback.
7504 * So, we need to disable webm format in "autoplug-select" */
7505 if (caps_str && strstr(caps_str, "webm")) {
7506 LOGW("webm is not supported");
7507 result = GST_AUTOPLUG_SELECT_SKIP;
7511 /* check factory class for filtering */
7512 /* NOTE : msl don't need to use image plugins.
7513 * So, those plugins should be skipped for error handling.
7515 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7516 LOGD("skipping [%s] by not required", factory_name);
7517 result = GST_AUTOPLUG_SELECT_SKIP;
7521 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7522 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7523 // TO CHECK : subtitle if needed, add subparse exception.
7524 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7525 result = GST_AUTOPLUG_SELECT_SKIP;
7529 if (g_strrstr(factory_name, "mpegpsdemux")) {
7530 LOGD("skipping PS container - not support");
7531 result = GST_AUTOPLUG_SELECT_SKIP;
7535 if (g_strrstr(factory_name, "mssdemux"))
7536 player->smooth_streaming = TRUE;
7538 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7539 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7542 GstStructure *str = NULL;
7543 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7545 /* don't make video because of not required */
7546 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7547 (!player->set_mode.video_export)) {
7548 LOGD("no need video decoding, expose pad");
7549 result = GST_AUTOPLUG_SELECT_EXPOSE;
7553 /* get w/h for omx state-tune */
7554 /* FIXME: deprecated? */
7555 str = gst_caps_get_structure(caps, 0);
7556 gst_structure_get_int(str, "width", &width);
7559 if (player->v_stream_caps) {
7560 gst_caps_unref(player->v_stream_caps);
7561 player->v_stream_caps = NULL;
7564 player->v_stream_caps = gst_caps_copy(caps);
7565 LOGD("take caps for video state tune");
7566 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7570 if (g_strrstr(klass, "Codec/Decoder")) {
7571 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7572 if (result != GST_AUTOPLUG_SELECT_TRY) {
7573 LOGW("skip add decoder");
7579 MMPLAYER_FREEIF(caps_str);
7585 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7588 int ret = MM_ERROR_NONE;
7589 mmplayer_t *player = (mmplayer_t *)data;
7590 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7591 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7592 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7595 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7597 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7599 if (MMPLAYER_USE_DECODEBIN(player))
7602 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7605 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7607 __mmplayer_del_sink(player, videobin[MMPLAYER_V_SINK].gst);
7609 LOGD("remove videobin");
7610 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst,
7611 GST_STATE_NULL, FALSE, timeout);
7612 if (ret != MM_ERROR_NONE) {
7613 LOGE("fail to change state of videobin to NULL");
7617 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7618 LOGE("failed to remove videobin");
7619 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7622 LOGD("remove concat");
7623 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst,
7624 GST_STATE_NULL, FALSE, timeout);
7625 if (ret != MM_ERROR_NONE) {
7626 LOGE("fail to change state of concat to NULL");
7630 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7631 LOGE("failed to remove video concat");
7632 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7635 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7636 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7637 MMPLAYER_FREEIF(player->pipeline->videobin);
7639 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7640 if (ret != MM_ERROR_NONE)
7641 LOGE("failed to release overlay resources");
7643 player->videodec_linked = 0;
7645 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7650 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7652 mmplayer_t *player = (mmplayer_t *)data;
7655 MMPLAYER_RETURN_IF_FAIL(player);
7657 LOGD("got about to finish signal");
7659 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7660 LOGW("Fail to get cmd lock");
7664 if (!__mmplayer_verify_gapless_play_path(player)) {
7665 LOGD("decoding is finished.");
7666 MMPLAYER_CMD_UNLOCK(player);
7670 _mmplayer_set_reconfigure_state(player, TRUE);
7671 MMPLAYER_CMD_UNLOCK(player);
7673 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7674 __mmplayer_deactivate_old_path(player);
7680 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7682 mmplayer_t *player = (mmplayer_t *)data;
7683 GstIterator *iter = NULL;
7684 GValue item = { 0, };
7686 gboolean done = FALSE;
7687 gboolean is_all_drained = TRUE;
7690 MMPLAYER_RETURN_IF_FAIL(player);
7692 LOGD("got drained signal");
7694 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7695 LOGW("Fail to get cmd lock");
7699 if (!__mmplayer_verify_gapless_play_path(player)) {
7700 LOGD("decoding is finished.");
7701 MMPLAYER_CMD_UNLOCK(player);
7705 _mmplayer_set_reconfigure_state(player, TRUE);
7706 MMPLAYER_CMD_UNLOCK(player);
7708 /* check decodebin src pads whether they received EOS or not */
7709 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7712 switch (gst_iterator_next(iter, &item)) {
7713 case GST_ITERATOR_OK:
7714 pad = g_value_get_object(&item);
7715 if (pad && !GST_PAD_IS_EOS(pad)) {
7716 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7717 is_all_drained = FALSE;
7720 g_value_reset(&item);
7722 case GST_ITERATOR_RESYNC:
7723 gst_iterator_resync(iter);
7725 case GST_ITERATOR_ERROR:
7726 case GST_ITERATOR_DONE:
7731 g_value_unset(&item);
7732 gst_iterator_free(iter);
7734 if (!is_all_drained) {
7735 LOGD("Wait util the all pads get EOS.");
7740 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7741 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7743 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7744 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7745 __mmplayer_deactivate_old_path(player);
7751 _mmplayer_gst_element_added(GstBin *bin, GstElement *element, gpointer data)
7753 mmplayer_t *player = (mmplayer_t *)data;
7754 const gchar *klass = NULL;
7755 gchar *factory_name = NULL;
7757 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7758 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7760 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7762 if (__mmplayer_add_dump_buffer_probe(player, element))
7763 LOGD("add buffer probe");
7765 if (g_strrstr(klass, "Decoder")) {
7766 if (g_strrstr(klass, "Audio")) {
7767 player->audio_decoders = g_list_append(player->audio_decoders,
7768 g_strdup(GST_ELEMENT_NAME(element)));
7770 /* update codec info */
7771 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7772 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7773 player->audiodec_linked = 1;
7774 } else if (g_strrstr(klass, "Video")) {
7775 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7776 /* update codec info */
7777 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7778 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7779 player->videodec_linked = 1;
7782 GstPad *srcpad = gst_element_get_static_pad (video_parse, "src");
7784 GstCaps *caps = NULL;
7785 GstStructure *str = NULL;
7786 const gchar *name = NULL;
7787 gboolean caps_ret = TRUE;
7789 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD (srcpad, caps, str, name, caps_ret);
7790 if (caps_ret && str) {
7791 const gchar *stream_format = gst_structure_get_string (str, "stream-format");
7792 if (stream_format && g_strrstr(stream_format, "byte-stream")) {
7793 if ((g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7794 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7795 LOGD("Send SPS and PPS Insertion every IDR frame");
7799 gst_object_unref(GST_OBJECT(srcpad));
7803 } else if (g_strrstr(klass, "Demuxer")) {
7804 if (g_strrstr(klass, "Adaptive")) {
7805 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7806 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7808 MMPLAYER_FREEIF(player->type);
7810 if (g_strrstr(factory_name, "hlsdemux")) {
7811 player->type = g_strdup("application/x-hls");
7812 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
7813 } else if (g_strrstr(factory_name, "dashdemux")) {
7814 player->type = g_strdup("application/dash+xml");
7815 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
7817 LOGE("not supported type");
7820 player->streamer->is_adaptive_streaming = TRUE;
7822 if (player->streamer->buffering_req.prebuffer_time <= MIN_BUFFERING_TIME)
7823 player->streamer->buffering_req.prebuffer_time = DEFAULT_PREBUFFERING_TIME;
7825 LOGD("max variant limit: %d, %d, %d, prebuffer time: %d ms",
7826 player->adaptive_info.limit.bandwidth,
7827 player->adaptive_info.limit.width,
7828 player->adaptive_info.limit.height,
7829 player->streamer->buffering_req.prebuffer_time);
7831 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7832 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7833 "max-video-width", player->adaptive_info.limit.width,
7834 "max-video-height", player->adaptive_info.limit.height,
7835 "low-watermark-time", (guint64)(player->streamer->buffering_req.prebuffer_time * GST_MSECOND),
7839 LOGD("plugged element is demuxer. take it");
7841 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7842 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7844 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7845 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7846 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7849 if (g_strrstr(factory_name, "mpegaudioparse")) {
7850 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7851 (__mmplayer_is_only_mp3_type(player->type))) {
7852 LOGD("[mpegaudioparse] set streaming pull mode.");
7853 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7855 } else if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7856 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7857 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7859 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7860 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7862 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
7863 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7864 _mm_player_streaming_set_multiqueue(player->streamer, element);
7865 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7873 __mmplayer_release_misc(mmplayer_t *player)
7876 bool cur_mode = player->set_mode.rich_audio;
7879 MMPLAYER_RETURN_IF_FAIL(player);
7881 player->sent_bos = FALSE;
7882 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7884 player->seek_state = MMPLAYER_SEEK_NONE;
7886 player->total_bitrate = 0;
7887 player->total_maximum_bitrate = 0;
7889 player->not_found_demuxer = 0;
7891 player->last_position = 0;
7892 player->duration = 0;
7893 player->http_content_size = 0;
7894 player->not_supported_codec = MISSING_PLUGIN_NONE;
7895 player->can_support_codec = FOUND_PLUGIN_NONE;
7896 player->pending_seek.is_pending = false;
7897 player->pending_seek.pos = 0;
7898 player->msg_posted = FALSE;
7899 player->has_many_types = FALSE;
7900 player->is_subtitle_force_drop = FALSE;
7901 player->play_subtitle = FALSE;
7902 player->adjust_subtitle_pos = 0;
7903 player->has_closed_caption = FALSE;
7904 player->set_mode.video_export = false;
7905 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7906 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7908 player->set_mode.rich_audio = cur_mode;
7910 if (player->audio_device_cb_id > 0 &&
7911 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7912 LOGW("failed to remove audio device_connected_callback");
7913 player->audio_device_cb_id = 0;
7915 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7916 player->bitrate[i] = 0;
7917 player->maximum_bitrate[i] = 0;
7920 /* free memory related to audio effect */
7921 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7923 if (player->adaptive_info.var_list) {
7924 g_list_free_full(player->adaptive_info.var_list, g_free);
7925 player->adaptive_info.var_list = NULL;
7928 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7929 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7930 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7932 /* Reset video360 settings to their defaults in case if the pipeline is to be
7935 player->video360_metadata.is_spherical = -1;
7936 player->is_openal_plugin_used = FALSE;
7938 player->is_content_spherical = FALSE;
7939 player->is_video360_enabled = TRUE;
7940 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7941 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7942 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7943 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7944 player->video360_zoom = 1.0f;
7945 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7946 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7948 player->sound.rg_enable = false;
7950 __mmplayer_initialize_video_roi(player);
7955 __mmplayer_release_misc_post(mmplayer_t *player)
7957 gchar *original_uri = NULL;
7960 /* player->pipeline is already released before. */
7961 MMPLAYER_RETURN_IF_FAIL(player);
7963 player->video_decoded_cb = NULL;
7964 player->video_decoded_cb_user_param = NULL;
7965 player->video_stream_prerolled = false;
7967 player->audio_decoded_cb = NULL;
7968 player->audio_decoded_cb_user_param = NULL;
7969 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7971 player->audio_stream_changed_cb = NULL;
7972 player->audio_stream_changed_cb_user_param = NULL;
7974 mm_player_set_attribute((MMHandleType)player, NULL,
7975 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7977 /* clean found audio decoders */
7978 if (player->audio_decoders) {
7979 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7980 player->audio_decoders = NULL;
7983 /* clean the uri list except original uri */
7984 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7986 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7987 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7988 g_list_free_full(tmp, (GDestroyNotify)g_free);
7991 LOGW("failed to get original uri info");
7993 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7994 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7995 MMPLAYER_FREEIF(original_uri);
7998 /* clear the audio stream buffer list */
7999 _mmplayer_audio_stream_clear_buffer(player, FALSE);
8001 /* clear the video stream bo list */
8002 __mmplayer_video_stream_destroy_bo_list(player);
8003 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
8005 if (player->profile.input_mem.buf) {
8006 free(player->profile.input_mem.buf);
8007 player->profile.input_mem.buf = NULL;
8009 player->profile.input_mem.len = 0;
8010 player->profile.input_mem.offset = 0;
8012 player->uri_info.uri_idx = 0;
8017 __mmplayer_check_subtitle(mmplayer_t *player)
8019 MMHandleType attrs = 0;
8020 char *subtitle_uri = NULL;
8024 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8026 /* get subtitle attribute */
8027 attrs = MMPLAYER_GET_ATTRS(player);
8031 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8032 if (!subtitle_uri || !strlen(subtitle_uri))
8035 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
8036 player->is_external_subtitle_present = TRUE;
8044 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8046 MMPLAYER_RETURN_IF_FAIL(player);
8048 if (player->eos_timer) {
8049 LOGD("cancel eos timer");
8050 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8051 player->eos_timer = 0;
8058 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8062 MMPLAYER_RETURN_IF_FAIL(player);
8063 MMPLAYER_RETURN_IF_FAIL(sink);
8066 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8068 player->sink_elements = g_list_append(player->sink_elements, sink);
8074 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8078 MMPLAYER_RETURN_IF_FAIL(player);
8079 MMPLAYER_RETURN_IF_FAIL(sink);
8081 player->sink_elements = g_list_remove(player->sink_elements, sink);
8087 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8088 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8090 mmplayer_signal_item_t *item = NULL;
8093 MMPLAYER_RETURN_IF_FAIL(player);
8095 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8096 LOGE("invalid signal type [%d]", type);
8100 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8102 LOGE("cannot connect signal [%s]", signal);
8107 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8108 player->signals[type] = g_list_append(player->signals[type], item);
8114 /* NOTE : be careful with calling this api. please refer to below glib comment
8115 * glib comment : Note that there is a bug in GObject that makes this function much
8116 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8117 * will no longer be called, but, the signal handler is not currently disconnected.
8118 * If the instance is itself being freed at the same time than this doesn't matter,
8119 * since the signal will automatically be removed, but if instance persists,
8120 * then the signal handler will leak. You should not remove the signal yourself
8121 * because in a future versions of GObject, the handler will automatically be
8124 * It's possible to work around this problem in a way that will continue to work
8125 * with future versions of GObject by checking that the signal handler is still
8126 * connected before disconnected it:
8128 * if (g_signal_handler_is_connected(instance, id))
8129 * g_signal_handler_disconnect(instance, id);
8132 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8134 GList *sig_list = NULL;
8135 mmplayer_signal_item_t *item = NULL;
8139 MMPLAYER_RETURN_IF_FAIL(player);
8141 LOGD("release signals type : %d", type);
8143 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8144 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8145 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8146 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8147 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8148 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8152 sig_list = player->signals[type];
8154 for (; sig_list; sig_list = sig_list->next) {
8155 item = sig_list->data;
8157 if (item && item->obj) {
8158 if (g_signal_handler_is_connected(item->obj, item->sig))
8159 g_signal_handler_disconnect(item->obj, item->sig);
8162 MMPLAYER_FREEIF(item);
8165 g_list_free(player->signals[type]);
8166 player->signals[type] = NULL;
8174 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8176 mmplayer_t *player = 0;
8177 int prev_display_surface_type = 0;
8181 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8183 player = MM_PLAYER_CAST(handle);
8185 /* check video sinkbin is created */
8186 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8187 LOGW("Videosink is already created");
8188 return MM_ERROR_NONE;
8191 LOGD("videosink element is not yet ready");
8193 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8194 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8196 return MM_ERROR_INVALID_ARGUMENT;
8199 /* load previous attributes */
8200 if (player->attrs) {
8201 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8202 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8203 if (prev_display_surface_type == surface_type) {
8204 LOGD("incoming display surface type is same as previous one, do nothing..");
8206 return MM_ERROR_NONE;
8209 LOGE("failed to load attributes");
8211 return MM_ERROR_PLAYER_INTERNAL;
8214 /* videobin is not created yet, so we just set attributes related to display surface */
8215 LOGD("store display attribute for given surface type(%d)", surface_type);
8216 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8217 "display_overlay", wl_surface_id, NULL);
8220 return MM_ERROR_NONE;
8223 /* Note : if silent is true, then subtitle would not be displayed. :*/
8225 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8227 mmplayer_t *player = (mmplayer_t *)hplayer;
8231 /* check player handle */
8232 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8234 player->set_mode.subtitle_off = silent;
8236 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8240 return MM_ERROR_NONE;
8244 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8246 mmplayer_gst_element_t *mainbin = NULL;
8247 mmplayer_gst_element_t *textbin = NULL;
8248 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8249 GstState current_state = GST_STATE_VOID_PENDING;
8250 GstState element_state = GST_STATE_VOID_PENDING;
8251 GstState element_pending_state = GST_STATE_VOID_PENDING;
8253 GstEvent *event = NULL;
8254 int result = MM_ERROR_NONE;
8256 GstClock *curr_clock = NULL;
8257 GstClockTime base_time, start_time, curr_time;
8262 /* check player handle */
8263 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8265 player->pipeline->mainbin &&
8266 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8268 mainbin = player->pipeline->mainbin;
8269 textbin = player->pipeline->textbin;
8271 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8273 // sync clock with current pipeline
8274 curr_clock = gst_element_get_clock(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8275 curr_time = gst_clock_get_time(curr_clock);
8277 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8278 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8280 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8281 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8283 if (current_state > GST_STATE_READY) {
8284 // sync state with current pipeline
8285 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8286 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8287 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8289 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8290 if (GST_STATE_CHANGE_FAILURE == ret) {
8291 LOGE("fail to state change.");
8292 result = MM_ERROR_PLAYER_INTERNAL;
8294 gst_object_unref(curr_clock);
8298 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8299 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8302 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8303 gst_object_unref(curr_clock);
8306 // seek to current position
8307 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8308 result = MM_ERROR_PLAYER_INVALID_STATE;
8309 LOGE("gst_element_query_position failed, invalid state");
8313 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8314 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);
8316 _mmplayer_gst_send_event_to_sink(player, event);
8318 result = MM_ERROR_PLAYER_INTERNAL;
8319 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8323 /* sync state with current pipeline */
8324 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8325 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8326 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8328 return MM_ERROR_NONE;
8331 /* release text pipeline resource */
8332 player->textsink_linked = 0;
8334 /* release signal */
8335 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8337 /* release textbin with it's children */
8338 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8339 MMPLAYER_FREEIF(player->pipeline->textbin);
8340 player->pipeline->textbin = NULL;
8342 /* release subtitle elem */
8343 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8344 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8350 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8352 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8353 GstState current_state = GST_STATE_VOID_PENDING;
8355 MMHandleType attrs = 0;
8356 mmplayer_gst_element_t *mainbin = NULL;
8357 mmplayer_gst_element_t *textbin = NULL;
8359 gchar *subtitle_uri = NULL;
8360 int result = MM_ERROR_NONE;
8361 const gchar *charset = NULL;
8365 /* check player handle */
8366 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8368 player->pipeline->mainbin &&
8369 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8370 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8372 mainbin = player->pipeline->mainbin;
8373 textbin = player->pipeline->textbin;
8375 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8376 if (current_state < GST_STATE_READY) {
8377 result = MM_ERROR_PLAYER_INVALID_STATE;
8378 LOGE("Pipeline is not in proper state");
8382 attrs = MMPLAYER_GET_ATTRS(player);
8384 LOGE("cannot get content attribute");
8385 result = MM_ERROR_PLAYER_INTERNAL;
8389 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8390 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8391 LOGE("subtitle uri is not proper filepath");
8392 result = MM_ERROR_PLAYER_INVALID_URI;
8396 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8397 LOGE("failed to get storage info of subtitle path");
8398 result = MM_ERROR_PLAYER_INVALID_URI;
8402 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8403 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8405 if (!strcmp(filepath, subtitle_uri)) {
8406 LOGD("subtitle path is not changed");
8409 if (mm_player_set_attribute((MMHandleType)player, NULL,
8410 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8411 LOGE("failed to set attribute");
8416 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8417 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8418 player->subtitle_language_list = NULL;
8419 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8421 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8422 if (ret != GST_STATE_CHANGE_SUCCESS) {
8423 LOGE("failed to change state of textbin to READY");
8424 result = MM_ERROR_PLAYER_INTERNAL;
8428 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8429 if (ret != GST_STATE_CHANGE_SUCCESS) {
8430 LOGE("failed to change state of subparse to READY");
8431 result = MM_ERROR_PLAYER_INTERNAL;
8435 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8436 if (ret != GST_STATE_CHANGE_SUCCESS) {
8437 LOGE("failed to change state of filesrc to READY");
8438 result = MM_ERROR_PLAYER_INTERNAL;
8442 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8444 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8446 charset = _mmplayer_get_charset(filepath);
8448 LOGD("detected charset is %s", charset);
8449 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8452 result = _mmplayer_sync_subtitle_pipeline(player);
8459 /* API to switch between external subtitles */
8461 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8463 int result = MM_ERROR_NONE;
8464 mmplayer_t *player = (mmplayer_t *)hplayer;
8469 /* check player handle */
8470 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8472 /* filepath can be null in idle state */
8474 /* check file path */
8475 if ((path = strstr(filepath, "file://")))
8476 result = _mmplayer_exist_file_path(path + 7);
8478 result = _mmplayer_exist_file_path(filepath);
8480 if (result != MM_ERROR_NONE) {
8481 LOGE("invalid subtitle path 0x%X", result);
8482 return result; /* file not found or permission denied */
8486 if (!player->pipeline) {
8488 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8489 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8490 LOGE("failed to set attribute");
8491 return MM_ERROR_PLAYER_INTERNAL;
8494 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8495 /* check filepath */
8496 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8498 if (!__mmplayer_check_subtitle(player)) {
8499 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8500 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8501 LOGE("failed to set attribute");
8502 return MM_ERROR_PLAYER_INTERNAL;
8505 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8506 LOGE("fail to create text pipeline");
8507 return MM_ERROR_PLAYER_INTERNAL;
8510 result = _mmplayer_sync_subtitle_pipeline(player);
8512 result = __mmplayer_change_external_subtitle_language(player, filepath);
8515 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8516 player->is_external_subtitle_added_now = TRUE;
8518 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8519 if (!player->subtitle_language_list) {
8520 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8521 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8522 LOGW("subtitle language list is not updated yet");
8524 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8532 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8534 guint active_idx = 0;
8535 GstStream *stream = NULL;
8536 GList *streams = NULL;
8537 GstCaps *caps = NULL;
8540 LOGD("Switching Streams... type: %d, index: %d", type, index);
8542 player->track[type].active_track_index = index;
8544 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8545 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8546 LOGD("track type:%d, total: %d, active: %d", i,
8547 player->track[i].total_track_num, player->track[i].active_track_index);
8548 if (player->track[i].total_track_num > 0 &&
8549 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8550 active_idx = player->track[i].active_track_index;
8551 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8552 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8553 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8555 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8556 caps = gst_stream_get_caps(stream);
8558 _mmplayer_set_audio_attrs(player, caps);
8559 gst_caps_unref(caps);
8566 LOGD("send select stream event");
8567 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8568 gst_event_new_select_streams(streams));
8569 g_list_free(streams);
8572 /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8573 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8574 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8576 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8577 pos_nsec = player->last_position;
8579 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8581 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8582 player->playback_rate, GST_FORMAT_TIME,
8583 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8584 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8585 LOGW("failed to seek");
8586 return MM_ERROR_PLAYER_INTERNAL;
8591 return MM_ERROR_NONE;
8595 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8597 int result = MM_ERROR_NONE;
8598 gchar *change_pad_name = NULL;
8599 GstPad *sinkpad = NULL;
8600 mmplayer_gst_element_t *mainbin = NULL;
8601 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8602 GstCaps *caps = NULL;
8603 gint total_track_num = 0;
8607 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8608 MM_ERROR_PLAYER_NOT_INITIALIZED);
8610 LOGD("Change Track(%d) to %d", type, index);
8612 mainbin = player->pipeline->mainbin;
8614 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8615 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8616 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8617 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8619 /* Changing Video Track is not supported. */
8620 LOGE("Track Type Error");
8624 if (mainbin[elem_idx].gst == NULL) {
8625 result = MM_ERROR_PLAYER_NO_OP;
8626 LOGD("Req track doesn't exist");
8630 total_track_num = player->track[type].total_track_num;
8631 if (total_track_num <= 0) {
8632 result = MM_ERROR_PLAYER_NO_OP;
8633 LOGD("Language list is not available");
8637 if ((index < 0) || (index >= total_track_num)) {
8638 result = MM_ERROR_INVALID_ARGUMENT;
8639 LOGD("Not a proper index : %d", index);
8643 /*To get the new pad from the selector*/
8644 change_pad_name = g_strdup_printf("sink_%u", index);
8645 if (change_pad_name == NULL) {
8646 result = MM_ERROR_PLAYER_INTERNAL;
8647 LOGD("Pad does not exists");
8651 LOGD("new active pad name: %s", change_pad_name);
8653 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8654 if (sinkpad == NULL) {
8655 LOGD("sinkpad is NULL");
8656 result = MM_ERROR_PLAYER_INTERNAL;
8660 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8661 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8663 caps = gst_pad_get_current_caps(sinkpad);
8664 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8667 gst_object_unref(sinkpad);
8669 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8670 _mmplayer_set_audio_attrs(player, caps);
8673 gst_caps_unref(caps);
8676 MMPLAYER_FREEIF(change_pad_name);
8681 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8683 int result = MM_ERROR_NONE;
8684 mmplayer_t *player = NULL;
8685 mmplayer_gst_element_t *mainbin = NULL;
8687 gint current_active_index = 0;
8689 GstState current_state = GST_STATE_VOID_PENDING;
8694 player = (mmplayer_t *)hplayer;
8695 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8697 if (!player->pipeline) {
8698 LOGE("Track %d pre setting -> %d", type, index);
8700 player->track[type].active_track_index = index;
8704 mainbin = player->pipeline->mainbin;
8706 current_active_index = player->track[type].active_track_index;
8708 /*If index is same as running index no need to change the pad*/
8709 if (current_active_index == index)
8712 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8713 result = MM_ERROR_PLAYER_INVALID_STATE;
8717 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8718 if (current_state < GST_STATE_PAUSED) {
8719 result = MM_ERROR_PLAYER_INVALID_STATE;
8720 LOGW("Pipeline not in proper state");
8724 if (MMPLAYER_USE_DECODEBIN(player))
8725 result = __mmplayer_change_selector_pad(player, type, index);
8727 result = __mmplayer_switch_stream(player, type, index);
8729 if (result != MM_ERROR_NONE) {
8730 LOGE("failed to change track");
8734 player->track[type].active_track_index = index;
8736 if (MMPLAYER_USE_DECODEBIN(player)) {
8737 GstEvent *event = NULL;
8738 if (current_state == GST_STATE_PLAYING) {
8739 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8740 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8741 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8743 _mmplayer_gst_send_event_to_sink(player, event);
8745 result = MM_ERROR_PLAYER_INTERNAL;
8756 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8758 mmplayer_t *player = (mmplayer_t *)hplayer;
8762 /* check player handle */
8763 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8765 *silent = player->set_mode.subtitle_off;
8767 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8771 return MM_ERROR_NONE;
8775 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8777 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8778 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8780 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8781 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8785 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8786 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8787 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8788 mmplayer_dump_t *dump_s;
8789 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8790 if (dump_s == NULL) {
8791 LOGE("malloc fail");
8795 dump_s->dump_element_file = NULL;
8796 dump_s->dump_pad = NULL;
8797 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8799 if (dump_s->dump_pad) {
8800 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8801 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]);
8802 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8803 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);
8804 /* add list for removed buffer probe and close FILE */
8805 player->dump_list = g_list_append(player->dump_list, dump_s);
8806 LOGD("%s sink pad added buffer probe for dump", factory_name);
8809 MMPLAYER_FREEIF(dump_s);
8810 LOGE("failed to get %s sink pad added", factory_name);
8817 static GstPadProbeReturn
8818 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8820 FILE *dump_data = (FILE *)u_data;
8822 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8823 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8825 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8827 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8829 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8831 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8833 gst_buffer_unmap(buffer, &probe_info);
8835 return GST_PAD_PROBE_OK;
8839 __mmplayer_release_dump_list(GList *dump_list)
8841 GList *d_list = dump_list;
8846 for (; d_list; d_list = g_list_next(d_list)) {
8847 mmplayer_dump_t *dump_s = d_list->data;
8848 if (dump_s->dump_pad) {
8849 if (dump_s->probe_handle_id)
8850 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8851 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8853 if (dump_s->dump_element_file) {
8854 fclose(dump_s->dump_element_file);
8855 dump_s->dump_element_file = NULL;
8857 MMPLAYER_FREEIF(dump_s);
8859 g_list_free(dump_list);
8864 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8866 mmplayer_t *player = (mmplayer_t *)hplayer;
8870 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8871 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8873 *exist = (bool)player->has_closed_caption;
8877 return MM_ERROR_NONE;
8881 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8886 LOGD("unref internal gst buffer %p", buffer);
8888 gst_buffer_unref((GstBuffer *)buffer);
8895 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8897 mmplayer_t *player = (mmplayer_t *)hplayer;
8901 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8902 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8904 if (MMPLAYER_IS_STREAMING(player))
8905 *timeout = (int)player->ini.live_state_change_timeout;
8907 *timeout = (int)player->ini.localplayback_state_change_timeout;
8909 LOGD("timeout = %d", *timeout);
8912 return MM_ERROR_NONE;
8916 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8920 MMPLAYER_RETURN_IF_FAIL(player);
8922 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8924 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8925 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8926 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8927 player->storage_info[i].id = -1;
8928 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8930 if (path_type != MMPLAYER_PATH_MAX)
8939 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8941 int ret = MM_ERROR_NONE;
8942 mmplayer_t *player = (mmplayer_t *)hplayer;
8943 MMMessageParamType msg_param = {0, };
8946 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8948 LOGW("state changed storage %d:%d", id, state);
8950 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8951 return MM_ERROR_NONE;
8953 /* FIXME: text path should be handled separately. */
8954 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8955 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8956 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8957 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8958 LOGW("external storage is removed");
8960 if (player->msg_posted == FALSE) {
8961 memset(&msg_param, 0, sizeof(MMMessageParamType));
8962 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8963 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8964 player->msg_posted = TRUE;
8967 /* unrealize the player */
8968 ret = _mmplayer_unrealize(hplayer);
8969 if (ret != MM_ERROR_NONE)
8970 LOGE("failed to unrealize");
8978 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8980 int ret = MM_ERROR_NONE;
8981 mmplayer_t *player = (mmplayer_t *)hplayer;
8982 int idx = 0, total = 0;
8983 gchar *result = NULL, *tmp = NULL;
8986 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8987 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8989 total = *num = g_list_length(player->adaptive_info.var_list);
8991 LOGW("There is no stream variant info.");
8995 result = g_strdup("");
8996 for (idx = 0 ; idx < total ; idx++) {
8997 stream_variant_t *v_data = NULL;
8998 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
9001 gchar data[64] = {0};
9002 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
9004 tmp = g_strconcat(result, data, NULL);
9008 LOGW("There is no variant data in %d", idx);
9013 *var_info = (char *)result;
9015 LOGD("variant info %d:%s", *num, *var_info);
9021 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
9023 int ret = MM_ERROR_NONE;
9024 mmplayer_t *player = (mmplayer_t *)hplayer;
9027 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9029 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
9031 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9032 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9033 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
9035 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
9036 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
9037 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
9038 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
9040 /* FIXME: seek to current position for applying new variant limitation */
9049 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9051 int ret = MM_ERROR_NONE;
9052 mmplayer_t *player = (mmplayer_t *)hplayer;
9055 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9056 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9058 *bandwidth = player->adaptive_info.limit.bandwidth;
9059 *width = player->adaptive_info.limit.width;
9060 *height = player->adaptive_info.limit.height;
9062 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9069 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9071 int ret = MM_ERROR_NONE;
9072 mmplayer_t *player = (mmplayer_t *)hplayer;
9075 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9076 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9077 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9079 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9081 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9082 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9083 else /* live case */
9084 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9086 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9093 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9095 #define IDX_FIRST_SW_CODEC 0
9096 mmplayer_t *player = (mmplayer_t *)hplayer;
9097 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9098 const char *attr_name = NULL;
9099 const char *default_type = NULL;
9100 const char *element_hw = NULL;
9101 const char *element_sw = NULL;
9104 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9106 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9108 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9109 switch (stream_type) {
9110 case MM_PLAYER_STREAM_TYPE_AUDIO:
9111 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9112 default_type = player->ini.audiocodec_default_type;
9113 element_hw = player->ini.audiocodec_element_hw;
9114 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9116 case MM_PLAYER_STREAM_TYPE_VIDEO:
9117 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9118 default_type = player->ini.videocodec_default_type;
9119 element_hw = player->ini.videocodec_element_hw;
9120 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9123 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9124 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9128 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9130 if (!strcmp(default_type, "sw"))
9131 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9133 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9135 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9136 codec_type = default_codec_type;
9138 /* to support codec selection, codec info have to be added in ini file.
9139 in case of hw codec is selected, filter elements should be applied
9140 depending on the hw capabilities. */
9141 if (codec_type != default_codec_type) {
9142 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9143 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9144 LOGE("There is no codec for type %d", codec_type);
9145 return MM_ERROR_PLAYER_NO_OP;
9148 LOGD("sorting is required");
9149 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9150 player->need_audio_dec_sorting = TRUE;
9152 player->need_video_dec_sorting = TRUE;
9155 LOGD("update %s codec_type to %d", attr_name, codec_type);
9156 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9159 return MM_ERROR_NONE;
9163 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9165 mmplayer_t *player = (mmplayer_t *)hplayer;
9166 GstElement *rg_vol_element = NULL;
9170 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9172 player->sound.rg_enable = enabled;
9174 /* just hold rgvolume enable value if pipeline is not ready */
9175 if (!player->pipeline || !player->pipeline->audiobin) {
9176 LOGD("pipeline is not ready. holding rgvolume enable value");
9177 return MM_ERROR_NONE;
9180 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9182 if (!rg_vol_element) {
9183 LOGD("rgvolume element is not created");
9184 return MM_ERROR_PLAYER_INTERNAL;
9188 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9190 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9194 return MM_ERROR_NONE;
9198 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9200 mmplayer_t *player = (mmplayer_t *)hplayer;
9201 GstElement *rg_vol_element = NULL;
9202 gboolean enable = FALSE;
9206 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9207 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9209 /* just hold enable_rg value if pipeline is not ready */
9210 if (!player->pipeline || !player->pipeline->audiobin) {
9211 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9212 *enabled = player->sound.rg_enable;
9213 return MM_ERROR_NONE;
9216 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9218 if (!rg_vol_element) {
9219 LOGD("rgvolume element is not created");
9220 return MM_ERROR_PLAYER_INTERNAL;
9223 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9224 *enabled = (bool)enable;
9228 return MM_ERROR_NONE;
9232 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9234 mmplayer_t *player = (mmplayer_t *)hplayer;
9235 MMHandleType attrs = 0;
9237 int ret = MM_ERROR_NONE;
9241 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9243 attrs = MMPLAYER_GET_ATTRS(player);
9244 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9246 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9248 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9249 return MM_ERROR_PLAYER_INTERNAL;
9252 player->video_roi.scale_x = scale_x;
9253 player->video_roi.scale_y = scale_y;
9254 player->video_roi.scale_width = scale_width;
9255 player->video_roi.scale_height = scale_height;
9257 /* check video sinkbin is created */
9258 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9259 return MM_ERROR_NONE;
9261 if (!gst_video_overlay_set_video_roi_area(
9262 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9263 scale_x, scale_y, scale_width, scale_height))
9264 ret = MM_ERROR_PLAYER_INTERNAL;
9266 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9267 scale_x, scale_y, scale_width, scale_height);
9275 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9277 mmplayer_t *player = (mmplayer_t *)hplayer;
9278 int ret = MM_ERROR_NONE;
9282 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9283 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9285 *scale_x = player->video_roi.scale_x;
9286 *scale_y = player->video_roi.scale_y;
9287 *scale_width = player->video_roi.scale_width;
9288 *scale_height = player->video_roi.scale_height;
9290 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9291 *scale_x, *scale_y, *scale_width, *scale_height);
9297 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9299 mmplayer_t *player = (mmplayer_t *)hplayer;
9303 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9305 player->client_pid = pid;
9307 LOGD("client pid[%d] %p", pid, player);
9311 return MM_ERROR_NONE;
9315 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9317 mmplayer_t *player = (mmplayer_t *)hplayer;
9318 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9319 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9323 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9324 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9327 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9329 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9331 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9332 return MM_ERROR_NONE;
9334 /* in case of audio codec default type is HW */
9336 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9337 if (player->ini.support_audio_effect)
9338 return MM_ERROR_NONE;
9339 elem_id = MMPLAYER_A_FILTER;
9341 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9342 if (player->ini.support_replaygain_control)
9343 return MM_ERROR_NONE;
9344 elem_id = MMPLAYER_A_RGVOL;
9346 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9347 if (player->ini.support_pitch_control)
9348 return MM_ERROR_NONE;
9349 elem_id = MMPLAYER_A_PITCH;
9351 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9352 if (player->ini.support_audio_effect)
9353 return MM_ERROR_NONE;
9355 /* default case handling is not required */
9358 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9359 LOGW("audio control option [%d] is not available", opt);
9362 /* setting pcm exporting option is allowed before READY state */
9363 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9364 return MM_ERROR_PLAYER_INVALID_STATE;
9366 /* check whether the audio filter exist or not after READY state,
9367 because the sw codec could be added during auto-plugging in some cases */
9368 if (!player->pipeline ||
9369 !player->pipeline->audiobin ||
9370 !player->pipeline->audiobin[elem_id].gst) {
9371 LOGW("there is no audio elem [%d]", elem_id);
9376 LOGD("audio control opt %d, available %d", opt, *available);
9380 return MM_ERROR_NONE;
9384 __mmplayer_update_duration_value(mmplayer_t *player)
9386 gboolean ret = FALSE;
9387 gint64 dur_nsec = 0;
9388 LOGD("try to update duration");
9390 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9391 player->duration = dur_nsec;
9392 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9396 if (player->duration < 0) {
9397 LOGW("duration is Non-Initialized !!!");
9398 player->duration = 0;
9401 /* update streaming service type */
9402 player->streaming_type = _mmplayer_get_stream_service_type(player);
9404 /* check duration is OK */
9405 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9406 /* FIXIT : find another way to get duration here. */
9407 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9413 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9415 /* update audio params
9416 NOTE : We need original audio params and it can be only obtained from src pad of audio
9417 decoder. Below code only valid when we are not using 'resampler' just before
9418 'audioconverter'. */
9419 GstCaps *caps_a = NULL;
9421 gint samplerate = 0, channels = 0;
9422 GstStructure *p = NULL;
9423 GstElement *aconv = NULL;
9425 LOGD("try to update audio attrs");
9427 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9429 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9430 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9431 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9432 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9434 LOGE("there is no audio converter");
9438 pad = gst_element_get_static_pad(aconv, "sink");
9441 LOGW("failed to get pad from audio converter");
9445 caps_a = gst_pad_get_current_caps(pad);
9447 LOGW("not ready to get audio caps");
9448 gst_object_unref(pad);
9452 p = gst_caps_get_structure(caps_a, 0);
9453 gst_structure_get_int(p, "rate", &samplerate);
9454 gst_structure_get_int(p, "channels", &channels);
9456 mm_player_set_attribute((MMHandleType)player, NULL,
9457 "content_audio_samplerate", samplerate,
9458 "content_audio_channels", channels, NULL);
9460 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9462 gst_caps_unref(caps_a);
9463 gst_object_unref(pad);
9469 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9471 LOGD("try to update video attrs");
9473 GstCaps *caps_v = NULL;
9477 GstStructure *p = NULL;
9479 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9480 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9482 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9484 LOGD("no videosink sink pad");
9488 caps_v = gst_pad_get_current_caps(pad);
9489 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9490 if (!caps_v && player->v_stream_caps) {
9491 caps_v = player->v_stream_caps;
9492 gst_caps_ref(caps_v);
9496 LOGD("no negotiated caps from videosink");
9497 gst_object_unref(pad);
9501 p = gst_caps_get_structure(caps_v, 0);
9502 gst_structure_get_int(p, "width", &width);
9503 gst_structure_get_int(p, "height", &height);
9505 mm_player_set_attribute((MMHandleType)player, NULL,
9506 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9508 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9510 SECURE_LOGD("width : %d height : %d", width, height);
9512 gst_caps_unref(caps_v);
9513 gst_object_unref(pad);
9516 mm_player_set_attribute((MMHandleType)player, NULL,
9517 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9518 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9525 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9527 gboolean ret = FALSE;
9528 guint64 data_size = 0;
9532 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9533 if (!player->duration)
9536 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9537 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9538 if (stat(path, &sb) == 0)
9539 data_size = (guint64)sb.st_size;
9541 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9542 data_size = player->http_content_size;
9545 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9548 guint64 bitrate = 0;
9549 guint64 msec_dur = 0;
9551 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9553 bitrate = data_size * 8 * 1000 / msec_dur;
9554 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9555 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9556 mm_player_set_attribute((MMHandleType)player, NULL,
9557 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9560 LOGD("player duration is less than 0");
9564 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9565 if (player->total_bitrate) {
9566 mm_player_set_attribute((MMHandleType)player, NULL,
9567 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9576 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9578 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9579 data->uri_type = uri_type;
9583 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9585 int ret = MM_ERROR_PLAYER_INVALID_URI;
9587 char *buffer = NULL;
9588 char *seperator = strchr(path, ',');
9589 char ext[100] = {0,}, size[100] = {0,};
9592 if ((buffer = strstr(path, "ext="))) {
9593 buffer += strlen("ext=");
9595 if (strlen(buffer)) {
9596 strncpy(ext, buffer, 99);
9598 if ((seperator = strchr(ext, ','))
9599 || (seperator = strchr(ext, ' '))
9600 || (seperator = strchr(ext, '\0'))) {
9601 seperator[0] = '\0';
9606 if ((buffer = strstr(path, "size="))) {
9607 buffer += strlen("size=");
9609 if (strlen(buffer) > 0) {
9610 strncpy(size, buffer, 99);
9612 if ((seperator = strchr(size, ','))
9613 || (seperator = strchr(size, ' '))
9614 || (seperator = strchr(size, '\0'))) {
9615 seperator[0] = '\0';
9618 mem_size = atoi(size);
9623 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9625 if (mem_size && param) {
9626 if (data->input_mem.buf)
9627 free(data->input_mem.buf);
9628 data->input_mem.buf = malloc(mem_size);
9630 if (data->input_mem.buf) {
9631 memcpy(data->input_mem.buf, param, mem_size);
9632 data->input_mem.len = mem_size;
9633 ret = MM_ERROR_NONE;
9635 LOGE("failed to alloc mem %d", mem_size);
9636 ret = MM_ERROR_PLAYER_INTERNAL;
9639 data->input_mem.offset = 0;
9640 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9647 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9649 gchar *location = NULL;
9652 int ret = MM_ERROR_NONE;
9654 if ((path = strstr(uri, "file://"))) {
9655 location = g_filename_from_uri(uri, NULL, &err);
9656 if (!location || (err != NULL)) {
9657 LOGE("Invalid URI '%s' for filesrc: %s", path,
9658 (err != NULL) ? err->message : "unknown error");
9662 MMPLAYER_FREEIF(location);
9664 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9665 return MM_ERROR_PLAYER_INVALID_URI;
9667 LOGD("path from uri: %s", location);
9670 path = (location != NULL) ? (location) : ((char *)uri);
9673 ret = _mmplayer_exist_file_path(path);
9675 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9676 if (ret == MM_ERROR_NONE) {
9677 if (_mmplayer_is_sdp_file(path)) {
9678 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9679 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9680 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9682 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9683 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9685 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9686 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9688 LOGE("invalid uri, could not play..");
9689 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9692 MMPLAYER_FREEIF(location);
9697 static mmplayer_video_decoded_data_info_t *
9698 __mmplayer_create_stream_from_pad(GstPad *pad)
9700 GstCaps *caps = NULL;
9701 GstStructure *structure = NULL;
9702 unsigned int fourcc = 0;
9703 const gchar *string_format = NULL;
9704 mmplayer_video_decoded_data_info_t *stream = NULL;
9706 MMPixelFormatType format;
9709 caps = gst_pad_get_current_caps(pad);
9711 LOGE("Caps is NULL.");
9716 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9718 structure = gst_caps_get_structure(caps, 0);
9719 gst_structure_get_int(structure, "width", &width);
9720 gst_structure_get_int(structure, "height", &height);
9721 string_format = gst_structure_get_string(structure, "format");
9724 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9725 format = _mmplayer_get_pixtype(fourcc);
9726 gst_video_info_from_caps(&info, caps);
9727 gst_caps_unref(caps);
9730 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9731 LOGE("Wrong condition!!");
9735 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9737 LOGE("failed to alloc mem for video data");
9741 stream->width = width;
9742 stream->height = height;
9743 stream->format = format;
9744 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9750 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9752 unsigned int pitch = 0;
9753 unsigned int size = 0;
9755 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9758 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9759 bo = gst_tizen_memory_get_bos(mem, index);
9761 stream->bo[index] = tbm_bo_ref(bo);
9763 LOGE("failed to get bo for index %d", index);
9766 for (index = 0; index < stream->plane_num; index++) {
9767 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9768 stream->stride[index] = pitch;
9770 stream->elevation[index] = size / pitch;
9772 stream->elevation[index] = stream->height;
9777 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9779 if (stream->format == MM_PIXEL_FORMAT_I420) {
9780 int ret = TBM_SURFACE_ERROR_NONE;
9781 tbm_surface_h surface;
9782 tbm_surface_info_s info;
9784 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9786 ret = tbm_surface_get_info(surface, &info);
9787 if (ret != TBM_SURFACE_ERROR_NONE) {
9788 tbm_surface_destroy(surface);
9792 tbm_surface_destroy(surface);
9793 stream->stride[0] = info.planes[0].stride;
9794 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9795 stream->stride[1] = info.planes[1].stride;
9796 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9797 stream->stride[2] = info.planes[2].stride;
9798 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9799 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9800 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9801 stream->stride[0] = stream->width * 4;
9802 stream->elevation[0] = stream->height;
9803 stream->bo_size = stream->stride[0] * stream->height;
9805 LOGE("Not support format %d", stream->format);
9813 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9815 tbm_bo_handle thandle;
9817 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9818 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9819 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9823 unsigned char *src = NULL;
9824 unsigned char *dest = NULL;
9825 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9827 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9829 LOGE("fail to gst_memory_map");
9833 if (!mapinfo.data) {
9834 LOGE("data pointer is wrong");
9838 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9839 if (!stream->bo[0]) {
9840 LOGE("Fail to tbm_bo_alloc!!");
9844 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9846 LOGE("thandle pointer is wrong");
9850 if (stream->format == MM_PIXEL_FORMAT_I420) {
9851 src_stride[0] = GST_ROUND_UP_4(stream->width);
9852 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9853 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9854 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9857 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9858 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9860 for (i = 0; i < 3; i++) {
9861 src = mapinfo.data + src_offset[i];
9862 dest = thandle.ptr + dest_offset[i];
9867 for (j = 0; j < stream->height >> k; j++) {
9868 memcpy(dest, src, stream->width>>k);
9869 src += src_stride[i];
9870 dest += stream->stride[i];
9873 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9874 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9876 LOGE("Not support format %d", stream->format);
9880 tbm_bo_unmap(stream->bo[0]);
9881 gst_memory_unmap(mem, &mapinfo);
9887 tbm_bo_unmap(stream->bo[0]);
9890 gst_memory_unmap(mem, &mapinfo);
9896 __mmplayer_set_pause_state(mmplayer_t *player)
9898 if (player->sent_bos)
9901 /* rtsp case, get content attrs by GstMessage */
9902 if (MMPLAYER_IS_RTSP_STREAMING(player))
9905 /* it's first time to update all content attrs. */
9906 _mmplayer_update_content_attrs(player, ATTR_ALL);
9910 __mmplayer_set_playing_state(mmplayer_t *player)
9912 gchar *audio_codec = NULL;
9914 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9915 /* initialize because auto resume is done well. */
9916 player->resumed_by_rewind = FALSE;
9917 player->playback_rate = 1.0;
9920 if (player->sent_bos)
9923 /* try to get content metadata */
9925 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9926 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9927 * legacy mmfw-player api
9929 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9931 if ((player->cmd == MMPLAYER_COMMAND_START)
9932 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9933 __mmplayer_handle_missed_plugin(player);
9936 /* check audio codec field is set or not
9937 * we can get it from typefinder or codec's caps.
9939 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9941 /* The codec format can't be sent for audio only case like amr, mid etc.
9942 * Because, parser don't make related TAG.
9943 * So, if it's not set yet, fill it with found data.
9946 if (g_strrstr(player->type, "audio/midi"))
9947 audio_codec = "MIDI";
9948 else if (g_strrstr(player->type, "audio/x-amr"))
9949 audio_codec = "AMR";
9950 else if (g_strrstr(player->type, "audio/mpeg")
9951 && !g_strrstr(player->type, "mpegversion=(int)1"))
9952 audio_codec = "AAC";
9954 audio_codec = "unknown";
9956 if (mm_player_set_attribute((MMHandleType)player, NULL,
9957 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9958 LOGE("failed to set attribute");
9960 LOGD("set audio codec type with caps");