4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related function will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
143 static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
144 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void __mmplayer_release_misc(mmplayer_t *player);
150 static void __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
160 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
161 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
162 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
163 static gpointer __mmplayer_gapless_play_thread(gpointer data);
164 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
165 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_release_dump_list(GList *dump_list);
167 static int __mmplayer_gst_realize(mmplayer_t *player);
168 static int __mmplayer_gst_unrealize(mmplayer_t *player);
169 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
170 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
173 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
174 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
175 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
176 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
177 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
178 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
179 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
180 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
181 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
182 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
183 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
184 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
188 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
189 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
190 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
192 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
193 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
194 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
195 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
197 static void __mmplayer_set_pause_state(mmplayer_t *player);
198 static void __mmplayer_set_playing_state(mmplayer_t *player);
199 /*===========================================================================================
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 rm_ret = mm_resource_manager_commit(player->resource_manager);
588 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
589 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
590 return MM_ERROR_PLAYER_INTERNAL;
594 return MM_ERROR_NONE;
597 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
599 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
601 MMPLAYER_RETURN_IF_FAIL(player);
602 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
604 mm_resource_manager_mark_all_for_release(player->resource_manager);
606 rm_ret = mm_resource_manager_commit(player->resource_manager);
607 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
608 LOGW("failed to commit of resource, ret(0x%x)", rm_ret);
610 /* de-initialize resource manager */
611 rm_ret = mm_resource_manager_destroy(player->resource_manager);
612 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
613 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
615 player->resource_manager = NULL;
617 LOGD("resource manager is destroyed");
620 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
622 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
626 if (player->hw_resource[type] == NULL) {
627 LOGD("there is no acquired [%d type] resource", type);
628 return MM_ERROR_NONE;
631 LOGD("mark for release [%d type] resource", type);
632 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
633 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
634 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
635 return MM_ERROR_PLAYER_INTERNAL;
638 player->hw_resource[type] = NULL;
640 rm_ret = mm_resource_manager_commit(player->resource_manager);
641 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
642 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
643 return MM_ERROR_PLAYER_INTERNAL;
647 return MM_ERROR_NONE;
651 __mmplayer_initialize_gapless_play(mmplayer_t *player)
657 player->smooth_streaming = FALSE;
658 player->videodec_linked = 0;
659 player->audiodec_linked = 0;
660 player->textsink_linked = 0;
661 player->is_external_subtitle_present = FALSE;
662 player->is_external_subtitle_added_now = FALSE;
663 player->not_supported_codec = MISSING_PLUGIN_NONE;
664 player->can_support_codec = FOUND_PLUGIN_NONE;
665 player->pending_seek.is_pending = false;
666 player->pending_seek.pos = 0;
667 player->msg_posted = FALSE;
668 player->has_many_types = FALSE;
669 player->no_more_pad = FALSE;
670 player->not_found_demuxer = 0;
671 player->seek_state = MMPLAYER_SEEK_NONE;
672 player->is_subtitle_force_drop = FALSE;
673 player->play_subtitle = FALSE;
674 player->adjust_subtitle_pos = 0;
676 player->total_bitrate = 0;
677 player->total_maximum_bitrate = 0;
679 _mmplayer_track_initialize(player);
680 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
682 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
683 player->bitrate[i] = 0;
684 player->maximum_bitrate[i] = 0;
687 if (player->v_stream_caps) {
688 gst_caps_unref(player->v_stream_caps);
689 player->v_stream_caps = NULL;
692 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
694 /* clean found audio decoders */
695 if (player->audio_decoders) {
696 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
697 player->audio_decoders = NULL;
700 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
705 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
707 LOGI("set pipeline reconfigure state %d", state);
708 MMPLAYER_RECONFIGURE_LOCK(player);
709 player->gapless.reconfigure = state;
710 if (!state) /* wake up the waiting job */
711 MMPLAYER_RECONFIGURE_SIGNAL(player);
712 MMPLAYER_RECONFIGURE_UNLOCK(player);
716 __mmplayer_gapless_play_thread(gpointer data)
718 mmplayer_t *player = (mmplayer_t *)data;
719 mmplayer_gst_element_t *mainbin = NULL;
721 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
723 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
724 while (!player->gapless_play_thread_exit) {
725 LOGD("gapless play thread started. waiting for signal.");
726 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
728 LOGD("reconfigure pipeline for gapless play.");
730 if (player->gapless_play_thread_exit) {
731 _mmplayer_set_reconfigure_state(player, FALSE);
732 LOGD("exiting gapless play thread");
736 mainbin = player->pipeline->mainbin;
738 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
739 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
740 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
741 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
742 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
744 /* Initialize Player values */
745 __mmplayer_initialize_gapless_play(player);
747 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
749 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
755 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
757 GSource *source = NULL;
761 source = g_main_context_find_source_by_id(context, source_id);
762 if (source != NULL) {
763 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
764 g_source_destroy(source);
771 _mmplayer_watcher_removed_notify(gpointer data)
773 mmplayer_t *player = (mmplayer_t *)data;
774 MMPLAYER_RETURN_IF_FAIL(player);
776 MMPLAYER_BUS_WATCHER_LOCK(player);
777 player->bus_watcher = 0;
778 MMPLAYER_BUS_WATCHER_SIGNAL(player);
779 MMPLAYER_BUS_WATCHER_UNLOCK(player);
783 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
785 mmplayer_t *player = (mmplayer_t *)hplayer;
788 MMPLAYER_RETURN_IF_FAIL(player);
790 /* disconnecting bus watch */
791 if (player->bus_watcher > 0) {
792 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
793 MMPLAYER_BUS_WATCHER_LOCK(player);
794 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
795 while (player->bus_watcher > 0)
796 MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time);
797 MMPLAYER_BUS_WATCHER_UNLOCK(player);
799 g_mutex_clear(&player->bus_watcher_mutex);
800 g_cond_clear(&player->bus_watcher_cond);
807 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
809 mmplayer_t *player = (mmplayer_t *)hplayer;
810 GstMessage *msg = NULL;
811 GQueue *queue = NULL;
814 MMPLAYER_RETURN_IF_FAIL(player);
816 /* destroy the gst bus msg thread */
817 if (player->bus_msg_thread) {
818 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
819 player->bus_msg_thread_exit = TRUE;
820 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
821 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
823 LOGD("gst bus msg thread exit.");
824 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
825 player->bus_msg_thread = NULL;
827 g_mutex_clear(&player->bus_msg_thread_mutex);
828 g_cond_clear(&player->bus_msg_thread_cond);
831 g_mutex_lock(&player->bus_msg_q_lock);
832 queue = player->bus_msg_q;
833 while (!g_queue_is_empty(queue)) {
834 msg = (GstMessage *)g_queue_pop_head(queue);
839 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
840 gst_message_unref(msg);
842 g_mutex_unlock(&player->bus_msg_q_lock);
848 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
850 GstElement *parent = NULL;
852 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
853 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
856 MMPLAYER_FSINK_LOCK(player);
858 /* get parent of fakesink */
859 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
861 LOGD("fakesink already removed");
865 gst_element_set_locked_state(fakesink->gst, TRUE);
867 /* setting the state to NULL never returns async
868 * so no need to wait for completion of state transition
870 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
871 LOGE("fakesink state change failure!");
872 /* FIXIT : should I return here? or try to proceed to next? */
875 /* remove fakesink from it's parent */
876 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
877 LOGE("failed to remove fakesink");
879 gst_object_unref(parent);
884 gst_object_unref(parent);
886 LOGD("state-holder removed");
888 gst_element_set_locked_state(fakesink->gst, FALSE);
890 MMPLAYER_FSINK_UNLOCK(player);
895 gst_element_set_locked_state(fakesink->gst, FALSE);
897 MMPLAYER_FSINK_UNLOCK(player);
901 static GstPadProbeReturn
902 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
904 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
905 return GST_PAD_PROBE_OK;
909 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
911 gint64 stop_running_time = 0;
912 gint64 position_running_time = 0;
916 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
917 if ((player->gapless.update_segment[idx] == TRUE) ||
918 !(player->track[idx].event_probe_id)) {
920 LOGW("[%d] skip", idx);
925 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
927 gst_segment_to_running_time(&player->gapless.segment[idx],
928 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
929 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
931 gst_segment_to_running_time(&player->gapless.segment[idx],
932 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
934 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
936 gst_segment_to_running_time(&player->gapless.segment[idx],
937 GST_FORMAT_TIME, player->duration);
940 position_running_time =
941 gst_segment_to_running_time(&player->gapless.segment[idx],
942 GST_FORMAT_TIME, player->gapless.segment[idx].position);
944 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
945 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
947 GST_TIME_ARGS(stop_running_time),
948 GST_TIME_ARGS(position_running_time),
949 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
950 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
952 position_running_time = MAX(position_running_time, stop_running_time);
953 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
954 GST_FORMAT_TIME, player->gapless.segment[idx].start);
955 position_running_time = MAX(0, position_running_time);
956 position = MAX(position, position_running_time);
960 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
961 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
962 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
964 player->gapless.start_time[stream_type] += position;
970 static GstPadProbeReturn
971 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
973 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
974 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
975 mmplayer_t *player = (mmplayer_t *)data;
976 GstCaps *caps = NULL;
977 GstStructure *str = NULL;
978 const gchar *name = NULL;
979 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
980 gboolean caps_ret = TRUE;
982 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
983 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
984 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
985 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
986 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
989 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
993 if (strstr(name, "audio")) {
994 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
995 } else if (strstr(name, "video")) {
996 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
998 /* text track is not supportable */
999 LOGE("invalid name %s", name);
1003 switch (GST_EVENT_TYPE(event)) {
1006 /* in case of gapless, drop eos event not to send it to sink */
1007 if (player->gapless.reconfigure && !player->msg_posted) {
1008 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1009 ret = GST_PAD_PROBE_DROP;
1013 case GST_EVENT_STREAM_START:
1015 __mmplayer_gst_selector_update_start_time(player, stream_type);
1018 case GST_EVENT_FLUSH_STOP:
1020 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1021 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1022 player->gapless.start_time[stream_type] = 0;
1025 case GST_EVENT_SEGMENT:
1030 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1031 gst_event_copy_segment(event, &segment);
1033 if (segment.format != GST_FORMAT_TIME)
1036 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1037 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1038 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1039 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1040 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1041 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1043 /* keep the all the segment ev to cover the seeking */
1044 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1045 player->gapless.update_segment[stream_type] = TRUE;
1047 if (!player->gapless.running)
1050 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1052 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1054 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1055 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1056 gst_event_unref(event);
1057 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1063 gdouble proportion = 0.0;
1064 GstClockTimeDiff diff = 0;
1065 GstClockTime timestamp = 0;
1066 gint64 running_time_diff = -1;
1067 GstQOSType type = 0;
1068 GstEvent *tmpev = NULL;
1070 running_time_diff = player->gapless.segment[stream_type].base;
1072 if (running_time_diff <= 0) /* don't need to adjust */
1075 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1076 gst_event_unref(event);
1078 if (timestamp < running_time_diff) {
1079 LOGW("QOS event from previous group");
1080 ret = GST_PAD_PROBE_DROP;
1085 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1086 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1087 stream_type, GST_TIME_ARGS(timestamp),
1088 GST_TIME_ARGS(running_time_diff),
1089 GST_TIME_ARGS(timestamp - running_time_diff));
1092 timestamp -= running_time_diff;
1094 /* That case is invalid for QoS events */
1095 if (diff < 0 && -diff > timestamp) {
1096 LOGW("QOS event from previous group");
1097 ret = GST_PAD_PROBE_DROP;
1101 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1102 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1112 gst_caps_unref(caps);
1116 /* create fakesink for audio or video path without audiobin or videobin */
1118 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1120 GstElement *pipeline = NULL;
1121 GstElement *fakesink = NULL;
1122 GstPad *sinkpad = NULL;
1125 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1127 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1130 fakesink = gst_element_factory_make("fakesink", NULL);
1131 if (fakesink == NULL) {
1132 LOGE("failed to create fakesink");
1136 /* store it as it's sink element */
1137 __mmplayer_add_sink(player, fakesink, FALSE);
1139 gst_bin_add(GST_BIN(pipeline), fakesink);
1142 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1144 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1146 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1147 LOGE("failed to link fakesink");
1148 gst_object_unref(GST_OBJECT(fakesink));
1152 if (strstr(name, "video")) {
1153 if (player->v_stream_caps) {
1154 gst_caps_unref(player->v_stream_caps);
1155 player->v_stream_caps = NULL;
1157 if (player->ini.set_dump_element_flag)
1158 __mmplayer_add_dump_buffer_probe(player, fakesink);
1161 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1162 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1166 gst_object_unref(GST_OBJECT(sinkpad));
1173 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1175 GstElement *pipeline = NULL;
1176 GstElement *concat = NULL;
1179 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1181 concat = gst_element_factory_make("concat", NULL);
1183 LOGE("failed to create concat");
1187 LOGD("Create concat [%d] element", elem_idx);
1189 player->pipeline->mainbin[elem_idx].id = elem_idx;
1190 player->pipeline->mainbin[elem_idx].gst = concat;
1192 gst_element_set_state(concat, GST_STATE_PAUSED);
1194 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1195 gst_bin_add(GST_BIN(pipeline), concat);
1202 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1204 GstElement *pipeline = NULL;
1205 GstElement *selector = NULL;
1206 GstPad *srcpad = NULL;
1209 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1211 selector = gst_element_factory_make("input-selector", NULL);
1213 LOGE("failed to create input-selector");
1216 g_object_set(selector, "sync-streams", TRUE, NULL);
1218 player->pipeline->mainbin[elem_idx].id = elem_idx;
1219 player->pipeline->mainbin[elem_idx].gst = selector;
1221 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1223 srcpad = gst_element_get_static_pad(selector, "src");
1225 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1226 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1227 __mmplayer_gst_selector_blocked, NULL, NULL);
1228 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1229 __mmplayer_gst_selector_event_probe, player, NULL);
1231 gst_element_set_state(selector, GST_STATE_PAUSED);
1233 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1234 gst_bin_add(GST_BIN(pipeline), selector);
1236 gst_object_unref(GST_OBJECT(srcpad));
1243 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1245 mmplayer_t *player = (mmplayer_t *)data;
1246 GstElement *combiner = NULL;
1247 GstCaps *caps = NULL;
1248 GstStructure *str = NULL;
1249 const gchar *name = NULL;
1250 GstPad *sinkpad = NULL;
1251 gboolean first_track = FALSE;
1252 gboolean caps_ret = TRUE;
1254 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1255 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1258 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1259 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1261 LOGD("pad-added signal handling");
1263 /* get mimetype from caps */
1264 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1268 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1270 LOGD("detected mimetype : %s", name);
1273 if (strstr(name, "video")) {
1275 gchar *caps_str = NULL;
1277 caps_str = gst_caps_to_string(caps);
1278 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1279 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1280 player->set_mode.video_zc = true;
1282 MMPLAYER_FREEIF(caps_str);
1284 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1285 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1287 LOGD("surface type : %d", stype);
1289 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1290 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1294 /* in case of exporting video frame, it requires the 360 video filter.
1295 * it will be handled in _no_more_pads(). */
1296 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1297 __mmplayer_gst_make_fakesink(player, pad, name);
1301 if (MMPLAYER_USE_DECODEBIN(player)) {
1302 LOGD("video selector is required");
1303 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1305 LOGD("video concat is required");
1306 elem_idx = MMPLAYER_M_V_CONCAT;
1308 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1309 } else if (strstr(name, "audio")) {
1310 gint samplerate = 0;
1313 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1314 if (player->build_audio_offload)
1315 player->no_more_pad = TRUE; /* remove state holder */
1316 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1320 gst_structure_get_int(str, "rate", &samplerate);
1321 gst_structure_get_int(str, "channels", &channels);
1323 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1324 __mmplayer_gst_make_fakesink(player, pad, name);
1327 if (MMPLAYER_USE_DECODEBIN(player)) {
1328 LOGD("audio selector is required");
1329 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1331 LOGD("audio concat is required");
1332 elem_idx = MMPLAYER_M_A_CONCAT;
1334 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1336 } else if (strstr(name, "text")) {
1337 if (MMPLAYER_USE_DECODEBIN(player)) {
1338 LOGD("text selector is required");
1339 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1341 LOGD("text concat is required");
1342 elem_idx = MMPLAYER_M_T_CONCAT;
1344 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1346 LOGE("invalid caps info");
1350 /* check selector and create it */
1351 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1352 if (MMPLAYER_USE_DECODEBIN(player))
1353 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1355 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1361 LOGD("Combiner element is already created.");
1365 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1367 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1369 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1370 LOGE("failed to link combiner");
1371 gst_object_unref(GST_OBJECT(combiner));
1376 if (MMPLAYER_USE_DECODEBIN(player)) {
1377 LOGD("this track will be activated");
1378 g_object_set(combiner, "active-pad", sinkpad, NULL);
1382 if (MMPLAYER_USE_DECODEBIN(player)) {
1383 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1385 /* apply the text track information */
1386 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1387 mm_player_set_attribute((MMHandleType)player, NULL,
1388 "content_text_track_num", player->track[stream_type].total_track_num,
1389 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1390 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1397 gst_caps_unref(caps);
1400 gst_object_unref(GST_OBJECT(sinkpad));
1408 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1410 GstPad *srcpad = NULL;
1413 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1415 LOGD("type %d", type);
1418 LOGD("there is no %d track", type);
1422 srcpad = gst_element_get_static_pad(combiner, "src");
1424 LOGE("failed to get srcpad from combiner");
1428 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1430 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1432 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1433 if (player->track[type].block_id) {
1434 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1435 player->track[type].block_id = 0;
1439 gst_object_unref(GST_OBJECT(srcpad));
1448 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1450 gint active_index = 0;
1453 MMPLAYER_RETURN_IF_FAIL(player);
1455 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1457 /* change track to active pad */
1458 active_index = player->track[type].active_track_index;
1459 if ((active_index != DEFAULT_TRACK) &&
1460 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1461 LOGW("failed to change %d type track to %d", type, active_index);
1462 player->track[type].active_track_index = DEFAULT_TRACK;
1466 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1467 mm_player_set_attribute((MMHandleType)player, NULL,
1468 "content_text_track_num", player->track[type].total_track_num,
1469 "current_text_track_index", player->track[type].active_track_index, NULL);
1476 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1479 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1481 if (!audio_selector) {
1482 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1484 /* in case the source is changed, output can be changed. */
1485 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1486 LOGD("remove previous audiobin if it exist");
1488 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1489 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1491 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1492 MMPLAYER_FREEIF(player->pipeline->audiobin);
1495 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1496 _mmplayer_pipeline_complete(NULL, player);
1501 /* apply the audio track information */
1502 if (MMPLAYER_USE_DECODEBIN(player))
1503 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1505 /* create audio sink path */
1506 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1507 LOGE("failed to create audio sink path");
1516 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1519 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1521 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1522 LOGD("text path is not supported");
1526 /* apply the text track information */
1527 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1529 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1530 player->has_closed_caption = TRUE;
1532 /* create text decode path */
1533 player->no_more_pad = TRUE;
1535 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1536 LOGE("failed to create text sink path");
1545 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1547 gint64 dur_bytes = 0L;
1550 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1551 player->pipeline->mainbin && player->streamer, FALSE);
1553 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1554 LOGE("fail to get duration.");
1556 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1557 * use file information was already set on Q2 when it was created. */
1558 _mm_player_streaming_set_queue2(player->streamer,
1559 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1560 TRUE, /* use_buffering */
1561 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1562 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1569 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1571 mmplayer_t *player = NULL;
1572 GstElement *video_selector = NULL;
1573 GstElement *audio_selector = NULL;
1574 GstElement *text_selector = NULL;
1577 player = (mmplayer_t *)data;
1579 LOGD("no-more-pad signal handling");
1581 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1582 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1583 LOGW("player is shutting down");
1587 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1588 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1589 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1590 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1591 LOGE("failed to set queue2 buffering");
1596 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1597 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1598 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1600 if (!video_selector && !audio_selector && !text_selector) {
1601 LOGW("there is no selector");
1602 player->no_more_pad = TRUE;
1606 /* create video path followed by video-select */
1607 if (video_selector && !audio_selector && !text_selector)
1608 player->no_more_pad = TRUE;
1610 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1613 /* create audio path followed by audio-select */
1614 if (audio_selector && !text_selector)
1615 player->no_more_pad = TRUE;
1617 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1620 /* create text path followed by text-select */
1621 __mmplayer_create_text_sink_path(player, text_selector);
1624 _mmplayer_set_reconfigure_state(player, FALSE);
1629 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1631 gboolean ret = FALSE;
1632 GstElement *pipeline = NULL;
1633 GstPad *sinkpad = NULL;
1636 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1637 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1639 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1641 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1643 LOGE("failed to get pad from sinkbin");
1649 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1650 LOGE("failed to link sinkbin for reusing");
1651 goto EXIT; /* exit either pass or fail */
1655 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1656 LOGE("failed to set state(READY) to sinkbin");
1661 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1662 LOGE("failed to add sinkbin to pipeline");
1667 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1668 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1673 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1674 LOGE("failed to set state(PAUSED) to sinkbin");
1683 gst_object_unref(GST_OBJECT(sinkpad));
1691 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1693 mmplayer_t *player = NULL;
1694 GstCaps *caps = NULL;
1695 gchar *caps_str = NULL;
1696 GstStructure *str = NULL;
1697 const gchar *name = NULL;
1698 GstElement *sinkbin = NULL;
1699 gboolean reusing = FALSE;
1700 gboolean caps_ret = TRUE;
1701 gchar *sink_pad_name = "sink";
1704 player = (mmplayer_t *)data;
1707 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1708 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1709 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1711 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1715 caps = gst_caps_ref(ref_caps);
1718 caps_str = gst_caps_to_string(caps);
1720 LOGD("detected mimetype : %s", name);
1722 if (strstr(name, "audio")) {
1723 if (player->pipeline->audiobin == NULL) {
1724 const gchar *audio_format = gst_structure_get_string(str, "format");
1726 LOGD("original audio format %s", audio_format);
1727 mm_player_set_attribute((MMHandleType)player, NULL,
1728 "content_audio_format", audio_format, strlen(audio_format), NULL);
1731 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1732 LOGE("failed to create audiobin. continuing without audio");
1736 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1737 LOGD("creating audiobin success");
1740 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1741 LOGD("reusing audiobin");
1742 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1744 } else if (strstr(name, "video")) {
1745 /* 1. zero copy is updated at _decode_pad_added()
1746 * 2. NULL surface type is handled in _decode_pad_added() */
1747 LOGD("zero copy %d", player->set_mode.video_zc);
1748 if (player->pipeline->videobin == NULL) {
1749 int surface_type = 0;
1750 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1751 LOGD("display_surface_type (%d)", surface_type);
1753 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1754 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1755 LOGE("failed to acquire video overlay resource");
1759 player->interrupted_by_resource = FALSE;
1761 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1762 LOGE("failed to create videobin. continuing without video");
1766 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1767 LOGD("creating videosink bin success");
1770 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1771 LOGD("re-using videobin");
1772 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1774 } else if (strstr(name, "text")) {
1775 if (player->pipeline->textbin == NULL) {
1776 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1777 LOGE("failed to create text sink bin. continuing without text");
1781 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1782 player->textsink_linked = 1;
1783 LOGD("creating textsink bin success");
1785 if (!player->textsink_linked) {
1786 LOGD("re-using textbin");
1788 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1789 player->textsink_linked = 1;
1791 /* linked textbin exist which means that the external subtitle path exist already */
1792 LOGW("ignoring internal subtitle since external subtitle is available");
1795 sink_pad_name = "text_sink";
1797 LOGW("unknown mime type %s, ignoring it", name);
1801 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1804 LOGD("[handle: %p] success to create and link sink bin", player);
1806 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1807 * streaming task. if the task blocked, then buffer will not flow to the next element
1808 *(autoplugging element). so this is special hack for streaming. please try to remove it
1810 /* dec stream count. we can remove fakesink if it's zero */
1811 if (player->num_dynamic_pad)
1812 player->num_dynamic_pad--;
1814 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1816 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1817 _mmplayer_pipeline_complete(NULL, player);
1821 MMPLAYER_FREEIF(caps_str);
1824 gst_caps_unref(caps);
1830 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1832 int required_angle = 0; /* Angle required for straight view */
1833 int rotation_angle = 0;
1835 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1836 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1838 /* Counter clockwise */
1839 switch (orientation) {
1844 required_angle = 270;
1847 required_angle = 180;
1850 required_angle = 90;
1854 rotation_angle = display_angle + required_angle;
1855 if (rotation_angle >= 360)
1856 rotation_angle -= 360;
1858 /* check if supported or not */
1859 if (rotation_angle % 90) {
1860 LOGD("not supported rotation angle = %d", rotation_angle);
1864 switch (rotation_angle) {
1866 *value = MM_DISPLAY_ROTATION_NONE;
1869 *value = MM_DISPLAY_ROTATION_90;
1872 *value = MM_DISPLAY_ROTATION_180;
1875 *value = MM_DISPLAY_ROTATION_270;
1879 LOGD("setting rotation property value : %d", *value);
1885 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1887 int display_rotation = 0;
1888 gchar *org_orient = NULL;
1889 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1892 LOGE("cannot get content attribute");
1893 return MM_ERROR_PLAYER_INTERNAL;
1896 if (display_angle) {
1897 /* update user rotation */
1898 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1900 /* Counter clockwise */
1901 switch (display_rotation) {
1902 case MM_DISPLAY_ROTATION_NONE:
1905 case MM_DISPLAY_ROTATION_90:
1906 *display_angle = 90;
1908 case MM_DISPLAY_ROTATION_180:
1909 *display_angle = 180;
1911 case MM_DISPLAY_ROTATION_270:
1912 *display_angle = 270;
1915 LOGW("wrong angle type : %d", display_rotation);
1918 LOGD("check user angle: %d", *display_angle);
1922 /* Counter clockwise */
1923 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1926 if (!strcmp(org_orient, "rotate-90"))
1928 else if (!strcmp(org_orient, "rotate-180"))
1930 else if (!strcmp(org_orient, "rotate-270"))
1933 LOGD("original rotation is %s", org_orient);
1935 LOGD("content_video_orientation get fail");
1938 LOGD("check orientation: %d", *orientation);
1941 return MM_ERROR_NONE;
1944 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1946 int rotation_value = 0;
1947 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1948 int display_angle = 0;
1951 /* check video sinkbin is created */
1952 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1955 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1957 /* get rotation value to set */
1958 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1959 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1960 LOGD("set video param : rotate %d", rotation_value);
1963 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1965 MMHandleType attrs = 0;
1969 /* check video sinkbin is created */
1970 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1973 attrs = MMPLAYER_GET_ATTRS(player);
1974 MMPLAYER_RETURN_IF_FAIL(attrs);
1976 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1977 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1978 LOGD("set video param : visible %d", visible);
1981 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1983 MMHandleType attrs = 0;
1984 int display_method = 0;
1987 /* check video sinkbin is created */
1988 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1991 attrs = MMPLAYER_GET_ATTRS(player);
1992 MMPLAYER_RETURN_IF_FAIL(attrs);
1994 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1995 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1996 LOGD("set video param : method %d", display_method);
1999 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2001 MMHandleType attrs = 0;
2005 /* check video sinkbin is created */
2006 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2009 attrs = MMPLAYER_GET_ATTRS(player);
2010 MMPLAYER_RETURN_IF_FAIL(attrs);
2012 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2013 MMPLAYER_RETURN_IF_FAIL(handle);
2015 gst_video_overlay_set_video_roi_area(
2016 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2017 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2018 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2019 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2022 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2024 MMHandleType attrs = 0;
2029 int win_roi_width = 0;
2030 int win_roi_height = 0;
2033 /* check video sinkbin is created */
2034 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2037 attrs = MMPLAYER_GET_ATTRS(player);
2038 MMPLAYER_RETURN_IF_FAIL(attrs);
2040 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2041 MMPLAYER_RETURN_IF_FAIL(handle);
2043 /* It should be set after setting window */
2044 mm_attrs_multiple_get(attrs, NULL,
2045 "display_win_roi_x", &win_roi_x,
2046 "display_win_roi_y", &win_roi_y,
2047 "display_win_roi_width", &win_roi_width,
2048 "display_win_roi_height", &win_roi_height, NULL);
2050 /* After setting window handle, set display roi area */
2051 gst_video_overlay_set_display_roi_area(
2052 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2053 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2054 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2055 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2058 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2060 MMHandleType attrs = 0;
2063 /* check video sinkbin is created */
2064 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2067 attrs = MMPLAYER_GET_ATTRS(player);
2068 MMPLAYER_RETURN_IF_FAIL(attrs);
2070 /* common case if using overlay surface */
2071 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2072 MMPLAYER_RETURN_IF_FAIL(handle);
2074 /* default is using wl_surface_id */
2075 LOGD("set video param : wl_surface_id %d", handle);
2076 gst_video_overlay_set_wl_window_wl_surface_id(
2077 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2082 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2084 gboolean update_all_param = FALSE;
2088 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2089 LOGW("videosink is not ready yet");
2090 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2093 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2094 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2095 return MM_ERROR_PLAYER_INTERNAL;
2098 LOGD("param_name : %s", param_name);
2099 if (!g_strcmp0(param_name, "update_all_param"))
2100 update_all_param = TRUE;
2102 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2103 __mmplayer_video_param_set_display_overlay(player);
2104 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2105 __mmplayer_video_param_set_display_method(player);
2106 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2107 __mmplayer_video_param_set_display_visible(player);
2108 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2109 __mmplayer_video_param_set_display_rotation(player);
2110 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2111 __mmplayer_video_param_set_roi_area(player);
2112 if (update_all_param)
2113 __mmplayer_video_param_set_video_roi_area(player);
2117 return MM_ERROR_NONE;
2121 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2123 gboolean disable_overlay = FALSE;
2124 mmplayer_t *player = (mmplayer_t *)hplayer;
2127 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2128 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2129 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2130 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2132 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2133 LOGW("Display control is not supported");
2134 return MM_ERROR_PLAYER_INTERNAL;
2137 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2139 if (audio_only == (bool)disable_overlay) {
2140 LOGE("It's the same with current setting: (%d)", audio_only);
2141 return MM_ERROR_NONE;
2145 LOGE("disable overlay");
2146 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2148 /* release overlay resource */
2149 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2150 LOGE("failed to release overlay resource");
2154 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2155 LOGE("failed to acquire video overlay resource");
2158 player->interrupted_by_resource = FALSE;
2160 LOGD("enable overlay");
2161 __mmplayer_video_param_set_display_overlay(player);
2162 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2167 return MM_ERROR_NONE;
2171 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2173 mmplayer_t *player = (mmplayer_t *)hplayer;
2174 gboolean disable_overlay = FALSE;
2178 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2179 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2180 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2181 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2182 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2184 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2185 LOGW("Display control is not supported");
2186 return MM_ERROR_PLAYER_INTERNAL;
2189 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2191 *paudio_only = (bool)disable_overlay;
2193 LOGD("audio_only : %d", *paudio_only);
2197 return MM_ERROR_NONE;
2201 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2203 GList *bucket = element_bucket;
2204 mmplayer_gst_element_t *element = NULL;
2205 mmplayer_gst_element_t *prv_element = NULL;
2206 GstElement *tee_element = NULL;
2207 gint successful_link_count = 0;
2211 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2213 prv_element = (mmplayer_gst_element_t *)bucket->data;
2214 bucket = bucket->next;
2216 for (; bucket; bucket = bucket->next) {
2217 element = (mmplayer_gst_element_t *)bucket->data;
2219 if (element && element->gst) {
2220 if (prv_element && prv_element->gst) {
2221 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2223 prv_element->gst = tee_element;
2225 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2226 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2227 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2231 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2232 LOGD("linking [%s] to [%s] success",
2233 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2234 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2235 successful_link_count++;
2236 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2237 LOGD("keep audio-tee element for next audio pipeline branch");
2238 tee_element = prv_element->gst;
2241 LOGD("linking [%s] to [%s] failed",
2242 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2243 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2249 prv_element = element;
2254 return successful_link_count;
2258 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2260 GList *bucket = element_bucket;
2261 mmplayer_gst_element_t *element = NULL;
2262 int successful_add_count = 0;
2266 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2267 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2269 for (; bucket; bucket = bucket->next) {
2270 element = (mmplayer_gst_element_t *)bucket->data;
2272 if (element && element->gst) {
2273 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2274 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2275 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2276 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2279 successful_add_count++;
2285 return successful_add_count;
2289 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2291 mmplayer_t *player = (mmplayer_t *)data;
2292 GstCaps *caps = NULL;
2293 GstStructure *str = NULL;
2295 gboolean caps_ret = TRUE;
2299 MMPLAYER_RETURN_IF_FAIL(pad);
2300 MMPLAYER_RETURN_IF_FAIL(unused);
2301 MMPLAYER_RETURN_IF_FAIL(data);
2303 caps = gst_pad_get_current_caps(pad);
2307 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2311 LOGD("name = %s", name);
2313 if (strstr(name, "audio")) {
2314 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2316 if (player->audio_stream_changed_cb) {
2317 LOGE("call the audio stream changed cb");
2318 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2320 } else if (strstr(name, "video")) {
2321 if ((name = gst_structure_get_string(str, "format")))
2322 player->set_mode.video_zc = name[0] == 'S';
2324 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2325 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2327 LOGW("invalid caps info");
2332 gst_caps_unref(caps);
2340 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2345 MMPLAYER_RETURN_IF_FAIL(player);
2347 if (player->audio_stream_buff_list) {
2348 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2349 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2352 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2353 __mmplayer_audio_stream_send_data(player, tmp);
2355 MMPLAYER_FREEIF(tmp->pcm_data);
2356 MMPLAYER_FREEIF(tmp);
2359 g_list_free(player->audio_stream_buff_list);
2360 player->audio_stream_buff_list = NULL;
2367 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2369 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2372 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2374 audio_stream.bitrate = a_buffer->bitrate;
2375 audio_stream.channel = a_buffer->channel;
2376 audio_stream.channel_mask = a_buffer->channel_mask;
2377 audio_stream.data_size = a_buffer->data_size;
2378 audio_stream.data = a_buffer->pcm_data;
2379 audio_stream.pcm_format = a_buffer->pcm_format;
2381 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2383 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2389 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2391 mmplayer_t *player = (mmplayer_t *)data;
2392 const gchar *pcm_format = NULL;
2395 guint64 channel_mask = 0;
2396 void *a_data = NULL;
2398 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2399 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2403 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2405 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2406 a_data = mapinfo.data;
2407 a_size = mapinfo.size;
2409 GstCaps *caps = gst_pad_get_current_caps(pad);
2410 GstStructure *structure = gst_caps_get_structure(caps, 0);
2412 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2414 pcm_format = gst_structure_get_string(structure, "format");
2415 gst_structure_get_int(structure, "rate", &rate);
2416 gst_structure_get_int(structure, "channels", &channel);
2417 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2418 gst_caps_unref(GST_CAPS(caps));
2420 /* In case of the sync is false, use buffer list. *
2421 * The num of buffer list depends on the num of audio channels */
2422 if (player->audio_stream_buff_list) {
2423 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2424 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2426 if (channel_mask == tmp->channel_mask) {
2428 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2430 if (tmp->data_size + a_size < tmp->buff_size) {
2431 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2432 tmp->data_size += a_size;
2434 /* send data to client */
2435 __mmplayer_audio_stream_send_data(player, tmp);
2437 if (a_size > tmp->buff_size) {
2438 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2439 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2440 if (tmp->pcm_data == NULL) {
2441 LOGE("failed to realloc data.");
2444 tmp->buff_size = a_size;
2446 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2447 memcpy(tmp->pcm_data, a_data, a_size);
2448 tmp->data_size = a_size;
2453 LOGE("data is empty in list.");
2459 /* create new audio stream data for newly found audio channel */
2460 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2461 if (a_buffer == NULL) {
2462 LOGE("failed to alloc data.");
2465 a_buffer->bitrate = rate;
2466 a_buffer->channel = channel;
2467 a_buffer->channel_mask = channel_mask;
2468 a_buffer->data_size = a_size;
2469 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2471 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2472 /* If sync is FALSE, use buffer list to reduce the IPC. */
2473 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2474 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2475 if (a_buffer->pcm_data == NULL) {
2476 LOGE("failed to alloc data.");
2477 MMPLAYER_FREEIF(a_buffer);
2480 memcpy(a_buffer->pcm_data, a_data, a_size);
2482 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2484 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2486 /* If sync is TRUE, send data directly. */
2487 a_buffer->pcm_data = a_data;
2488 __mmplayer_audio_stream_send_data(player, a_buffer);
2489 MMPLAYER_FREEIF(a_buffer);
2493 gst_buffer_unmap(buffer, &mapinfo);
2498 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2500 mmplayer_t *player = (mmplayer_t *)data;
2501 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2502 GstPad *sinkpad = NULL;
2503 GstElement *queue = NULL, *sink = NULL;
2506 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2508 queue = gst_element_factory_make("queue", NULL);
2509 if (queue == NULL) {
2510 LOGD("fail make queue");
2514 sink = gst_element_factory_make("fakesink", NULL);
2516 LOGD("fail make fakesink");
2520 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2522 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2523 LOGW("failed to link queue & sink");
2527 sinkpad = gst_element_get_static_pad(queue, "sink");
2529 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2530 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2534 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2536 gst_object_unref(sinkpad);
2537 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2538 g_object_set(sink, "sync", TRUE, NULL);
2539 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2541 /* keep the first sink reference only */
2542 if (!audiobin[MMPLAYER_A_SINK].gst) {
2543 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2544 audiobin[MMPLAYER_A_SINK].gst = sink;
2548 _mmplayer_add_signal_connection(player,
2550 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2552 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2555 __mmplayer_add_sink(player, sink, FALSE);
2557 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2558 LOGE("failed to sync state");
2562 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2563 LOGE("failed to sync state");
2571 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2573 gst_object_unref(GST_OBJECT(queue));
2577 gst_object_unref(GST_OBJECT(sink));
2581 gst_object_unref(GST_OBJECT(sinkpad));
2589 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2591 mmplayer_t *player = (mmplayer_t *)data;
2594 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2596 player->no_more_pad = TRUE;
2597 _mmplayer_pipeline_complete(NULL, player);
2604 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2606 #define MAX_PROPS_LEN 128
2607 mmplayer_gst_element_t *audiobin = NULL;
2608 gint latency_mode = 0;
2609 gchar *stream_type = NULL;
2610 gchar *latency = NULL;
2612 gchar stream_props[MAX_PROPS_LEN] = {0,};
2613 GstStructure *props = NULL;
2616 * It should be set after player creation through attribute.
2617 * But, it can not be changed during playing.
2620 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2622 audiobin = player->pipeline->audiobin;
2624 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2625 if (player->sound.mute) {
2626 LOGD("mute enabled");
2627 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2630 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2631 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2634 snprintf(stream_props, sizeof(stream_props) - 1,
2635 "props,application.process.id.origin=%d", player->client_pid);
2637 snprintf(stream_props, sizeof(stream_props) - 1,
2638 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2639 stream_type, stream_id, player->client_pid);
2641 props = gst_structure_from_string(stream_props, NULL);
2642 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2643 LOGI("props result[%s].", stream_props);
2644 gst_structure_free(props);
2646 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2648 switch (latency_mode) {
2649 case AUDIO_LATENCY_MODE_LOW:
2650 latency = g_strdup("low");
2652 case AUDIO_LATENCY_MODE_MID:
2653 latency = g_strdup("mid");
2655 case AUDIO_LATENCY_MODE_HIGH:
2656 latency = g_strdup("high");
2659 latency = g_strdup("mid");
2663 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2665 LOGD("audiosink property - latency=%s", latency);
2667 MMPLAYER_FREEIF(latency);
2673 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2675 mmplayer_gst_element_t *audiobin = NULL;
2678 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2679 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2681 audiobin = player->pipeline->audiobin;
2683 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2684 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2685 LOGE("failed to create media stream info");
2686 return MM_ERROR_PLAYER_INTERNAL;
2689 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2691 if (player->video360_yaw_radians <= M_PI &&
2692 player->video360_yaw_radians >= -M_PI &&
2693 player->video360_pitch_radians <= M_PI_2 &&
2694 player->video360_pitch_radians >= -M_PI_2) {
2695 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2696 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2697 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2698 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2699 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2700 "source-orientation-y", player->video360_metadata.init_view_heading,
2701 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2705 return MM_ERROR_NONE;
2709 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2711 mmplayer_gst_element_t *audiobin = NULL;
2712 GstPad *sink_pad = NULL;
2713 GstCaps *acaps = NULL;
2715 int pitch_control = 0;
2716 double pitch_value = 1.0;
2719 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2720 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2722 audiobin = player->pipeline->audiobin;
2724 LOGD("make element for normal audio playback");
2726 /* audio bin structure for playback. {} means optional.
2727 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2729 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2730 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2733 /* for pitch control */
2734 mm_attrs_multiple_get(player->attrs, NULL,
2735 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2736 MM_PLAYER_PITCH_VALUE, &pitch_value,
2739 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2740 if (pitch_control && (player->videodec_linked == 0)) {
2741 GstElementFactory *factory;
2743 factory = gst_element_factory_find("pitch");
2745 gst_object_unref(factory);
2748 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2751 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2752 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2754 LOGW("there is no pitch element");
2759 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2761 /* replaygain volume */
2762 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2763 if (player->sound.rg_enable)
2764 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2766 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2769 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2771 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2772 /* currently, only openalsink uses volume element */
2773 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2774 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2776 if (player->sound.mute) {
2777 LOGD("mute enabled");
2778 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2782 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2784 /* audio effect element. if audio effect is enabled */
2785 if ((strcmp(player->ini.audioeffect_element, ""))
2787 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2788 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2790 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2792 if ((!player->bypass_audio_effect)
2793 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2794 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2795 if (!_mmplayer_audio_effect_custom_apply(player))
2796 LOGI("apply audio effect(custom) setting success");
2800 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2801 && (player->set_mode.rich_audio)) {
2802 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2806 /* create audio sink */
2807 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2808 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2809 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2811 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2812 if (player->is_360_feature_enabled &&
2813 player->is_content_spherical &&
2815 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2816 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2817 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2819 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2821 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2823 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2824 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2825 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2826 gst_caps_unref(acaps);
2828 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2830 player->is_openal_plugin_used = TRUE;
2832 if (player->is_360_feature_enabled && player->is_content_spherical)
2833 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2834 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2837 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2838 (player->videodec_linked && player->ini.use_system_clock)) {
2839 LOGD("system clock will be used.");
2840 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2843 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2844 __mmplayer_gst_set_pulsesink_property(player);
2845 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2846 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2851 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2852 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2854 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2855 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2856 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2857 gst_object_unref(GST_OBJECT(sink_pad));
2859 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2862 return MM_ERROR_NONE;
2864 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2866 return MM_ERROR_PLAYER_INTERNAL;
2870 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2872 mmplayer_gst_element_t *audiobin = NULL;
2873 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2875 gchar *dst_format = NULL;
2877 int dst_samplerate = 0;
2878 int dst_channels = 0;
2879 GstCaps *caps = NULL;
2880 char *caps_str = NULL;
2883 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2884 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2886 audiobin = player->pipeline->audiobin;
2888 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2890 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2892 [case 1] extract interleave audio pcm without playback
2893 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2894 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2896 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2898 [case 2] deinterleave for each channel without playback
2899 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2900 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2902 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2903 - fakesink (sync or not)
2906 [case 3] [case 1(sync only)] + playback
2907 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2909 * src - ... - tee - queue1 - playback path
2910 - queue2 - [case1 pipeline with sync]
2912 [case 4] [case 2(sync only)] + playback
2913 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2915 * src - ... - tee - queue1 - playback path
2916 - queue2 - [case2 pipeline with sync]
2920 /* 1. create tee and playback path
2921 'tee' should be added at first to copy the decoded stream
2923 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2924 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2925 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2927 /* tee - path 1 : for playback path */
2928 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2929 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2931 /* tee - path 2 : for extract path */
2932 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2933 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2936 /* if there is tee, 'tee - path 2' is linked here */
2938 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2941 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2943 /* 2. decide the extract pcm format */
2944 mm_attrs_multiple_get(player->attrs, NULL,
2945 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2946 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2947 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2950 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2951 dst_format, dst_len, dst_samplerate, dst_channels);
2953 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2954 mm_attrs_multiple_get(player->attrs, NULL,
2955 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2956 "content_audio_samplerate", &dst_samplerate,
2957 "content_audio_channels", &dst_channels,
2960 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2961 dst_format, dst_len, dst_samplerate, dst_channels);
2963 /* If there is no enough information, set it to platform default value. */
2964 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2965 LOGD("set platform default format");
2966 dst_format = DEFAULT_PCM_OUT_FORMAT;
2968 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2969 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2972 /* 3. create capsfilter */
2973 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2974 caps = gst_caps_new_simple("audio/x-raw",
2975 "format", G_TYPE_STRING, dst_format,
2976 "rate", G_TYPE_INT, dst_samplerate,
2977 "channels", G_TYPE_INT, dst_channels,
2980 caps_str = gst_caps_to_string(caps);
2981 LOGD("new caps : %s", caps_str);
2983 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2986 gst_caps_unref(caps);
2987 MMPLAYER_FREEIF(caps_str);
2989 /* 4-1. create deinterleave to extract pcm for each channel */
2990 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2991 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2992 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2994 /* audiosink will be added after getting signal for each channel */
2995 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2996 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2997 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2998 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2999 player->no_more_pad = FALSE;
3001 /* 4-2. create fakesink to extract interlevaed pcm */
3002 LOGD("add audio fakesink for interleaved audio");
3003 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3004 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3005 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3006 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3008 _mmplayer_add_signal_connection(player,
3009 G_OBJECT(audiobin[extract_sink_id].gst),
3010 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3012 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3015 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3019 return MM_ERROR_NONE;
3021 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3023 return MM_ERROR_PLAYER_INTERNAL;
3027 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3029 int ret = MM_ERROR_NONE;
3030 mmplayer_gst_element_t *audiobin = NULL;
3031 GList *element_bucket = NULL;
3034 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3035 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3037 audiobin = player->pipeline->audiobin;
3039 if (player->build_audio_offload) { /* skip all the audio filters */
3040 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3042 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3043 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3044 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3046 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3050 /* FIXME: need to mention the supportable condition at API reference */
3051 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3052 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3054 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3056 if (ret != MM_ERROR_NONE)
3059 LOGD("success to make audio bin element");
3060 *bucket = element_bucket;
3063 return MM_ERROR_NONE;
3066 LOGE("failed to make audio bin element");
3067 g_list_free(element_bucket);
3071 return MM_ERROR_PLAYER_INTERNAL;
3075 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3077 mmplayer_gst_element_t *first_element = NULL;
3078 mmplayer_gst_element_t *audiobin = NULL;
3080 GstPad *ghostpad = NULL;
3081 GList *element_bucket = NULL;
3085 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3088 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3090 LOGE("failed to allocate memory for audiobin");
3091 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3095 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3096 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3097 if (!audiobin[MMPLAYER_A_BIN].gst) {
3098 LOGE("failed to create audiobin");
3103 player->pipeline->audiobin = audiobin;
3105 /* create audio filters and audiosink */
3106 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3109 /* adding created elements to bin */
3110 LOGD("adding created elements to bin");
3111 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3114 /* linking elements in the bucket by added order. */
3115 LOGD("Linking elements in the bucket by added order.");
3116 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3119 /* get first element's sinkpad for creating ghostpad */
3120 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3121 if (!first_element) {
3122 LOGE("failed to get first elem");
3126 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3128 LOGE("failed to get pad from first element of audiobin");
3132 ghostpad = gst_ghost_pad_new("sink", pad);
3134 LOGE("failed to create ghostpad");
3138 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3139 LOGE("failed to add ghostpad to audiobin");
3143 gst_object_unref(pad);
3145 g_list_free(element_bucket);
3148 return MM_ERROR_NONE;
3151 LOGD("ERROR : releasing audiobin");
3154 gst_object_unref(GST_OBJECT(pad));
3157 gst_object_unref(GST_OBJECT(ghostpad));
3160 g_list_free(element_bucket);
3162 /* release element which are not added to bin */
3163 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3164 /* NOTE : skip bin */
3165 if (audiobin[i].gst) {
3166 GstObject *parent = NULL;
3167 parent = gst_element_get_parent(audiobin[i].gst);
3170 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3171 audiobin[i].gst = NULL;
3173 gst_object_unref(GST_OBJECT(parent));
3177 /* release audiobin with it's children */
3178 if (audiobin[MMPLAYER_A_BIN].gst)
3179 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3181 MMPLAYER_FREEIF(audiobin);
3183 player->pipeline->audiobin = NULL;
3185 return MM_ERROR_PLAYER_INTERNAL;
3189 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3191 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3195 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3197 int ret = MM_ERROR_NONE;
3199 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3200 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3202 MMPLAYER_VIDEO_BO_LOCK(player);
3204 if (player->video_bo_list) {
3205 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3206 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3207 if (tmp && tmp->bo == bo) {
3209 LOGD("release bo %p", bo);
3210 tbm_bo_unref(tmp->bo);
3211 MMPLAYER_VIDEO_BO_UNLOCK(player);
3212 MMPLAYER_VIDEO_BO_SIGNAL(player);
3217 /* hw codec is running or the list was reset for DRC. */
3218 LOGW("there is no bo list.");
3220 MMPLAYER_VIDEO_BO_UNLOCK(player);
3222 LOGW("failed to find bo %p", bo);
3226 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3232 tbm_bo_unref(tmp->bo);
3237 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3240 MMPLAYER_RETURN_IF_FAIL(player);
3242 MMPLAYER_VIDEO_BO_LOCK(player);
3243 if (player->video_bo_list) {
3244 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3245 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3246 player->video_bo_list = NULL;
3248 player->video_bo_size = 0;
3249 MMPLAYER_VIDEO_BO_UNLOCK(player);
3256 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3259 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3260 gboolean ret = TRUE;
3262 /* check DRC, if it is, destroy the prev bo list to create again */
3263 if (player->video_bo_size != size) {
3264 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3265 __mmplayer_video_stream_destroy_bo_list(player);
3266 player->video_bo_size = size;
3269 MMPLAYER_VIDEO_BO_LOCK(player);
3271 if ((!player->video_bo_list) ||
3272 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3274 /* create bo list */
3276 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3278 if (player->video_bo_list) {
3279 /* if bo list did not created all, try it again. */
3280 idx = g_list_length(player->video_bo_list);
3281 LOGD("bo list exist(len: %d)", idx);
3284 for (; idx < player->ini.num_of_video_bo; idx++) {
3285 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3287 LOGE("Fail to alloc bo_info.");
3290 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3292 LOGE("Fail to tbm_bo_alloc.");
3293 MMPLAYER_FREEIF(bo_info);
3296 bo_info->used = FALSE;
3297 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3300 /* update video num buffers */
3301 LOGD("video_num_buffers : %d", idx);
3302 mm_player_set_attribute((MMHandleType)player, NULL,
3303 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3304 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3308 MMPLAYER_VIDEO_BO_UNLOCK(player);
3314 /* get bo from list*/
3315 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3316 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3317 if (tmp && (tmp->used == FALSE)) {
3318 LOGD("found bo %p to use", tmp->bo);
3320 MMPLAYER_VIDEO_BO_UNLOCK(player);
3321 return tbm_bo_ref(tmp->bo);
3325 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3326 MMPLAYER_VIDEO_BO_UNLOCK(player);
3330 if (player->ini.video_bo_timeout <= 0) {
3331 MMPLAYER_VIDEO_BO_WAIT(player);
3333 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3334 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3341 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3343 mmplayer_t *player = (mmplayer_t *)data;
3345 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3347 /* send prerolled pkt */
3348 player->video_stream_prerolled = false;
3350 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3352 /* not to send prerolled pkt again */
3353 player->video_stream_prerolled = true;
3357 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3359 mmplayer_t *player = (mmplayer_t *)data;
3360 mmplayer_video_decoded_data_info_t *stream = NULL;
3361 GstMemory *mem = NULL;
3364 MMPLAYER_RETURN_IF_FAIL(player);
3365 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3367 if (player->video_stream_prerolled) {
3368 player->video_stream_prerolled = false;
3369 LOGD("skip the prerolled pkt not to send it again");
3373 /* clear stream data structure */
3374 stream = __mmplayer_create_stream_from_pad(pad);
3376 LOGE("failed to alloc stream");
3380 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3382 /* set size and timestamp */
3383 mem = gst_buffer_peek_memory(buffer, 0);
3384 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3385 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3387 /* check zero-copy */
3388 if (player->set_mode.video_zc &&
3389 player->set_mode.video_export &&
3390 gst_is_tizen_memory(mem)) {
3391 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3392 stream->internal_buffer = gst_buffer_ref(buffer);
3393 } else { /* sw codec */
3394 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3397 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3401 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3402 LOGE("failed to send video decoded data.");
3409 LOGE("release video stream resource.");
3410 if (gst_is_tizen_memory(mem)) {
3412 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3414 tbm_bo_unref(stream->bo[i]);
3417 /* unref gst buffer */
3418 if (stream->internal_buffer)
3419 gst_buffer_unref(stream->internal_buffer);
3422 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3424 MMPLAYER_FREEIF(stream);
3429 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3431 mmplayer_gst_element_t *videobin = NULL;
3434 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3436 videobin = player->pipeline->videobin;
3438 /* Set spatial media metadata and/or user settings to the element.
3440 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3441 "projection-type", player->video360_metadata.projection_type, NULL);
3443 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3444 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3446 if (player->video360_metadata.full_pano_width_pixels &&
3447 player->video360_metadata.full_pano_height_pixels &&
3448 player->video360_metadata.cropped_area_image_width &&
3449 player->video360_metadata.cropped_area_image_height) {
3450 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3451 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3452 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3453 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3454 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3455 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3456 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3460 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3461 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3462 "horizontal-fov", player->video360_horizontal_fov,
3463 "vertical-fov", player->video360_vertical_fov, NULL);
3466 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3467 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3468 "zoom", 1.0f / player->video360_zoom, NULL);
3471 if (player->video360_yaw_radians <= M_PI &&
3472 player->video360_yaw_radians >= -M_PI &&
3473 player->video360_pitch_radians <= M_PI_2 &&
3474 player->video360_pitch_radians >= -M_PI_2) {
3475 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3476 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3477 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3478 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3479 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3480 "pose-yaw", player->video360_metadata.init_view_heading,
3481 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3484 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3485 "passthrough", !player->is_video360_enabled, NULL);
3492 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3494 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3495 GList *element_bucket = NULL;
3498 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3500 /* create video360 filter */
3501 if (player->is_360_feature_enabled && player->is_content_spherical) {
3502 LOGD("create video360 element");
3503 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3504 __mmplayer_gst_set_video360_property(player);
3508 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3509 LOGD("skip creating the videoconv and rotator");
3510 return MM_ERROR_NONE;
3513 /* in case of sw codec & overlay surface type, except 360 playback.
3514 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3515 LOGD("create video converter: %s", video_csc);
3516 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3519 *bucket = element_bucket;
3521 return MM_ERROR_NONE;
3523 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3524 g_list_free(element_bucket);
3528 return MM_ERROR_PLAYER_INTERNAL;
3532 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3534 gchar *factory_name = NULL;
3536 switch (surface_type) {
3537 case MM_DISPLAY_SURFACE_OVERLAY:
3538 if (strlen(player->ini.videosink_element_overlay) > 0)
3539 factory_name = player->ini.videosink_element_overlay;
3541 case MM_DISPLAY_SURFACE_REMOTE:
3542 case MM_DISPLAY_SURFACE_NULL:
3543 if (strlen(player->ini.videosink_element_fake) > 0)
3544 factory_name = player->ini.videosink_element_fake;
3547 LOGE("unidentified surface type");
3551 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3552 return factory_name;
3556 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3558 gchar *factory_name = NULL;
3559 mmplayer_gst_element_t *videobin = NULL;
3564 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3566 videobin = player->pipeline->videobin;
3567 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3569 attrs = MMPLAYER_GET_ATTRS(player);
3571 LOGE("cannot get content attribute");
3572 return MM_ERROR_PLAYER_INTERNAL;
3575 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3576 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3577 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3578 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3579 "use-tbm", use_tbm, NULL);
3582 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3583 return MM_ERROR_PLAYER_INTERNAL;
3585 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3588 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3589 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3592 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3594 LOGD("disable last-sample");
3595 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3598 if (player->set_mode.video_export) {
3600 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3601 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3602 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3604 _mmplayer_add_signal_connection(player,
3605 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3606 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3608 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3611 _mmplayer_add_signal_connection(player,
3612 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3613 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3615 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3619 if (videobin[MMPLAYER_V_SINK].gst) {
3620 GstPad *sink_pad = NULL;
3621 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3623 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3624 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3625 gst_object_unref(GST_OBJECT(sink_pad));
3627 LOGE("failed to get sink pad from videosink");
3631 return MM_ERROR_NONE;
3636 * - video overlay surface(arm/x86) : tizenwlsink
3639 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3642 GList *element_bucket = NULL;
3643 mmplayer_gst_element_t *first_element = NULL;
3644 mmplayer_gst_element_t *videobin = NULL;
3645 gchar *videosink_factory_name = NULL;
3648 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3651 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3653 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3655 player->pipeline->videobin = videobin;
3658 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3659 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3660 if (!videobin[MMPLAYER_V_BIN].gst) {
3661 LOGE("failed to create videobin");
3665 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3668 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3669 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3671 /* additional setting for sink plug-in */
3672 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3673 LOGE("failed to set video property");
3677 /* store it as it's sink element */
3678 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3680 /* adding created elements to bin */
3681 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3682 LOGE("failed to add elements");
3686 /* Linking elements in the bucket by added order */
3687 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3688 LOGE("failed to link elements");
3692 /* get first element's sinkpad for creating ghostpad */
3693 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3694 if (!first_element) {
3695 LOGE("failed to get first element from bucket");
3699 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3701 LOGE("failed to get pad from first element");
3705 /* create ghostpad */
3706 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3707 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3708 LOGE("failed to add ghostpad to videobin");
3711 gst_object_unref(pad);
3713 /* done. free allocated variables */
3714 g_list_free(element_bucket);
3718 return MM_ERROR_NONE;
3721 LOGE("ERROR : releasing videobin");
3722 g_list_free(element_bucket);
3725 gst_object_unref(GST_OBJECT(pad));
3727 /* release videobin with it's children */
3728 if (videobin[MMPLAYER_V_BIN].gst)
3729 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3731 MMPLAYER_FREEIF(videobin);
3732 player->pipeline->videobin = NULL;
3734 return MM_ERROR_PLAYER_INTERNAL;
3738 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3740 GList *element_bucket = NULL;
3741 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3743 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3744 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3745 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3746 "signal-handoffs", FALSE,
3749 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3750 _mmplayer_add_signal_connection(player,
3751 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3752 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3754 G_CALLBACK(__mmplayer_update_subtitle),
3757 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3758 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3760 if (!player->play_subtitle) {
3761 LOGD("add textbin sink as sink element of whole pipeline.");
3762 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3765 /* adding created elements to bin */
3766 LOGD("adding created elements to bin");
3767 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3768 LOGE("failed to add elements");
3772 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3773 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3774 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3776 /* linking elements in the bucket by added order. */
3777 LOGD("Linking elements in the bucket by added order.");
3778 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3779 LOGE("failed to link elements");
3783 /* done. free allocated variables */
3784 g_list_free(element_bucket);
3786 if (textbin[MMPLAYER_T_QUEUE].gst) {
3788 GstPad *ghostpad = NULL;
3790 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3792 LOGE("failed to get sink pad of text queue");
3796 ghostpad = gst_ghost_pad_new("text_sink", pad);
3797 gst_object_unref(pad);
3800 LOGE("failed to create ghostpad of textbin");
3804 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3805 LOGE("failed to add ghostpad to textbin");
3806 gst_object_unref(ghostpad);
3811 return MM_ERROR_NONE;
3814 g_list_free(element_bucket);
3816 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3817 LOGE("remove textbin sink from sink list");
3818 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3821 /* release element at __mmplayer_gst_create_text_sink_bin */
3822 return MM_ERROR_PLAYER_INTERNAL;
3826 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3828 mmplayer_gst_element_t *textbin = NULL;
3829 GList *element_bucket = NULL;
3830 int surface_type = 0;
3835 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3838 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3840 LOGE("failed to allocate memory for textbin");
3841 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3845 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3846 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3847 if (!textbin[MMPLAYER_T_BIN].gst) {
3848 LOGE("failed to create textbin");
3853 player->pipeline->textbin = textbin;
3856 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3857 LOGD("surface type for subtitle : %d", surface_type);
3858 switch (surface_type) {
3859 case MM_DISPLAY_SURFACE_OVERLAY:
3860 case MM_DISPLAY_SURFACE_NULL:
3861 case MM_DISPLAY_SURFACE_REMOTE:
3862 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3863 LOGE("failed to make plain text elements");
3874 return MM_ERROR_NONE;
3878 LOGD("ERROR : releasing textbin");
3880 g_list_free(element_bucket);
3882 /* release signal */
3883 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3885 /* release element which are not added to bin */
3886 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3887 /* NOTE : skip bin */
3888 if (textbin[i].gst) {
3889 GstObject *parent = NULL;
3890 parent = gst_element_get_parent(textbin[i].gst);
3893 gst_object_unref(GST_OBJECT(textbin[i].gst));
3894 textbin[i].gst = NULL;
3896 gst_object_unref(GST_OBJECT(parent));
3901 /* release textbin with it's children */
3902 if (textbin[MMPLAYER_T_BIN].gst)
3903 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3905 MMPLAYER_FREEIF(textbin);
3906 player->pipeline->textbin = NULL;
3909 return MM_ERROR_PLAYER_INTERNAL;
3913 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3915 mmplayer_gst_element_t *mainbin = NULL;
3916 mmplayer_gst_element_t *textbin = NULL;
3917 MMHandleType attrs = 0;
3918 GstElement *subsrc = NULL;
3919 GstElement *subparse = NULL;
3920 gchar *subtitle_uri = NULL;
3921 const gchar *charset = NULL;
3927 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3929 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3931 mainbin = player->pipeline->mainbin;
3933 attrs = MMPLAYER_GET_ATTRS(player);
3935 LOGE("cannot get content attribute");
3936 return MM_ERROR_PLAYER_INTERNAL;
3939 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3940 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3941 LOGE("subtitle uri is not proper filepath.");
3942 return MM_ERROR_PLAYER_INVALID_URI;
3945 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3946 LOGE("failed to get storage info of subtitle path");
3947 return MM_ERROR_PLAYER_INVALID_URI;
3950 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3952 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3953 player->subtitle_language_list = NULL;
3954 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3956 /* create the subtitle source */
3957 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3959 LOGE("failed to create filesrc element");
3962 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3964 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3965 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3967 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3968 LOGW("failed to add queue");
3969 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3970 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3971 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3976 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3978 LOGE("failed to create subparse element");
3982 charset = _mmplayer_get_charset(subtitle_uri);
3984 LOGD("detected charset is %s", charset);
3985 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3988 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3989 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3991 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3992 LOGW("failed to add subparse");
3993 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3994 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3995 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3999 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4000 LOGW("failed to link subsrc and subparse");
4004 player->play_subtitle = TRUE;
4005 player->adjust_subtitle_pos = 0;
4007 LOGD("play subtitle using subtitle file");
4009 if (player->pipeline->textbin == NULL) {
4010 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4011 LOGE("failed to create text sink bin. continuing without text");
4015 textbin = player->pipeline->textbin;
4017 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4018 LOGW("failed to add textbin");
4020 /* release signal */
4021 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4023 /* release textbin with it's children */
4024 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4025 MMPLAYER_FREEIF(player->pipeline->textbin);
4026 player->pipeline->textbin = textbin = NULL;
4030 LOGD("link text input selector and textbin ghost pad");
4032 player->textsink_linked = 1;
4033 player->external_text_idx = 0;
4034 LOGI("textsink is linked");
4036 textbin = player->pipeline->textbin;
4037 LOGD("text bin has been created. reuse it.");
4038 player->external_text_idx = 1;
4041 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4042 LOGW("failed to link subparse and textbin");
4046 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4048 LOGE("failed to get sink pad from textsink to probe data");
4052 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4053 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4055 gst_object_unref(pad);
4058 /* create dot. for debugging */
4059 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4062 return MM_ERROR_NONE;
4065 /* release text pipeline resource */
4066 player->textsink_linked = 0;
4068 /* release signal */
4069 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4071 if (player->pipeline->textbin) {
4072 LOGE("remove textbin");
4074 /* release textbin with it's children */
4075 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4076 MMPLAYER_FREEIF(player->pipeline->textbin);
4077 player->pipeline->textbin = NULL;
4081 /* release subtitle elem */
4082 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4083 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4085 return MM_ERROR_PLAYER_INTERNAL;
4089 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4091 mmplayer_t *player = (mmplayer_t *)data;
4092 MMMessageParamType msg = {0, };
4093 GstClockTime duration = 0;
4094 gpointer text = NULL;
4095 guint text_size = 0;
4096 gboolean ret = TRUE;
4097 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4101 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4102 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4104 if (player->is_subtitle_force_drop) {
4105 LOGW("subtitle is dropped forcedly.");
4109 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4110 text = mapinfo.data;
4111 text_size = mapinfo.size;
4113 if (player->set_mode.subtitle_off) {
4114 LOGD("subtitle is OFF.");
4118 if (!text || (text_size == 0)) {
4119 LOGD("There is no subtitle to be displayed.");
4123 msg.data = (void *)text;
4125 duration = GST_BUFFER_DURATION(buffer);
4127 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4128 if (player->duration > GST_BUFFER_PTS(buffer))
4129 duration = player->duration - GST_BUFFER_PTS(buffer);
4132 LOGI("subtitle duration is invalid, subtitle duration change "
4133 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4135 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4137 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4139 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4140 gst_buffer_unmap(buffer, &mapinfo);
4147 static GstPadProbeReturn
4148 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4150 mmplayer_t *player = (mmplayer_t *)u_data;
4151 GstClockTime cur_timestamp = 0;
4152 gint64 adjusted_timestamp = 0;
4153 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4155 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4157 if (player->set_mode.subtitle_off) {
4158 LOGD("subtitle is OFF.");
4162 if (player->adjust_subtitle_pos == 0) {
4163 LOGD("nothing to do");
4167 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4168 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4170 if (adjusted_timestamp < 0) {
4171 LOGD("adjusted_timestamp under zero");
4176 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4177 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4178 GST_TIME_ARGS(cur_timestamp),
4179 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4181 return GST_PAD_PROBE_OK;
4185 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4189 /* check player and subtitlebin are created */
4190 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4191 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4193 if (position == 0) {
4194 LOGD("nothing to do");
4196 return MM_ERROR_NONE;
4199 /* check current position */
4200 player->adjust_subtitle_pos = position;
4202 LOGD("save adjust_subtitle_pos in player");
4206 return MM_ERROR_NONE;
4210 * This function is to create audio or video pipeline for playing.
4212 * @param player [in] handle of player
4214 * @return This function returns zero on success.
4219 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4221 int ret = MM_ERROR_NONE;
4222 mmplayer_gst_element_t *mainbin = NULL;
4223 MMHandleType attrs = 0;
4226 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4228 /* get profile attribute */
4229 attrs = MMPLAYER_GET_ATTRS(player);
4231 LOGE("failed to get content attribute");
4235 /* create pipeline handles */
4236 if (player->pipeline) {
4237 LOGE("pipeline should be released before create new one");
4241 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4243 /* create mainbin */
4244 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4245 if (mainbin == NULL)
4248 /* create pipeline */
4249 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4250 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4251 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4252 LOGE("failed to create pipeline");
4257 player->pipeline->mainbin = mainbin;
4259 /* create the source and decoder elements */
4260 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4261 ret = _mmplayer_gst_build_es_pipeline(player);
4263 if (MMPLAYER_USE_DECODEBIN(player))
4264 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4266 ret = _mmplayer_gst_build_pipeline_with_src(player);
4269 if (ret != MM_ERROR_NONE) {
4270 LOGE("failed to create some elements");
4274 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4275 if (__mmplayer_check_subtitle(player)
4276 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4277 LOGE("failed to create text pipeline");
4280 ret = _mmplayer_gst_add_bus_watch(player);
4281 if (ret != MM_ERROR_NONE) {
4282 LOGE("failed to add bus watch");
4287 return MM_ERROR_NONE;
4290 _mmplayer_bus_watcher_remove(player);
4291 __mmplayer_gst_destroy_pipeline(player);
4292 return MM_ERROR_PLAYER_INTERNAL;
4296 __mmplayer_reset_gapless_state(mmplayer_t *player)
4299 MMPLAYER_RETURN_IF_FAIL(player
4301 && player->pipeline->audiobin
4302 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4304 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4311 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4314 int ret = MM_ERROR_NONE;
4318 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4320 /* cleanup stuffs */
4321 MMPLAYER_FREEIF(player->type);
4322 player->no_more_pad = FALSE;
4323 player->num_dynamic_pad = 0;
4325 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4326 player->subtitle_language_list = NULL;
4327 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4329 MMPLAYER_RECONFIGURE_LOCK(player);
4330 __mmplayer_reset_gapless_state(player);
4331 MMPLAYER_RECONFIGURE_UNLOCK(player);
4333 if (player->streamer) {
4334 _mm_player_streaming_initialize(player->streamer, FALSE);
4335 _mm_player_streaming_destroy(player->streamer);
4336 player->streamer = NULL;
4339 /* cleanup unlinked mime type */
4340 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4341 MMPLAYER_FREEIF(player->unlinked_video_mime);
4342 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4344 /* cleanup running stuffs */
4345 _mmplayer_cancel_eos_timer(player);
4347 /* cleanup gst stuffs */
4348 if (player->pipeline) {
4349 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4350 GstTagList *tag_list = player->pipeline->tag_list;
4352 /* first we need to disconnect all signal hander */
4353 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4356 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4357 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4358 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4359 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4360 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4361 gst_object_unref(bus);
4363 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4364 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4365 if (ret != MM_ERROR_NONE) {
4366 LOGE("fail to change state to NULL");
4367 return MM_ERROR_PLAYER_INTERNAL;
4370 LOGW("succeeded in changing state to NULL");
4372 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4375 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4376 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4378 MMPLAYER_FREEIF(audiobin);
4379 MMPLAYER_FREEIF(videobin);
4380 MMPLAYER_FREEIF(textbin);
4381 MMPLAYER_FREEIF(mainbin);
4385 gst_tag_list_unref(tag_list);
4387 MMPLAYER_FREEIF(player->pipeline);
4389 MMPLAYER_FREEIF(player->album_art);
4391 if (player->type_caps) {
4392 gst_caps_unref(player->type_caps);
4393 player->type_caps = NULL;
4396 if (player->v_stream_caps) {
4397 gst_caps_unref(player->v_stream_caps);
4398 player->v_stream_caps = NULL;
4401 if (player->a_stream_caps) {
4402 gst_caps_unref(player->a_stream_caps);
4403 player->a_stream_caps = NULL;
4406 if (player->s_stream_caps) {
4407 gst_caps_unref(player->s_stream_caps);
4408 player->s_stream_caps = NULL;
4410 _mmplayer_track_destroy(player);
4412 if (player->sink_elements)
4413 g_list_free(player->sink_elements);
4414 player->sink_elements = NULL;
4416 if (player->bufmgr) {
4417 tbm_bufmgr_deinit(player->bufmgr);
4418 player->bufmgr = NULL;
4421 LOGW("finished destroy pipeline");
4429 __mmplayer_gst_realize(mmplayer_t *player)
4432 int ret = MM_ERROR_NONE;
4436 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4438 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4440 ret = __mmplayer_gst_create_pipeline(player);
4442 LOGE("failed to create pipeline");
4446 /* set pipeline state to READY */
4447 /* NOTE : state change to READY must be performed sync. */
4448 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4449 ret = _mmplayer_gst_set_state(player,
4450 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4452 if (ret != MM_ERROR_NONE) {
4453 /* return error if failed to set state */
4454 LOGE("failed to set READY state");
4458 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4460 /* create dot before error-return. for debugging */
4461 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4469 __mmplayer_gst_unrealize(mmplayer_t *player)
4471 int ret = MM_ERROR_NONE;
4475 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4477 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4478 MMPLAYER_PRINT_STATE(player);
4480 /* release miscellaneous information */
4481 __mmplayer_release_misc(player);
4483 /* destroy pipeline */
4484 ret = __mmplayer_gst_destroy_pipeline(player);
4485 if (ret != MM_ERROR_NONE) {
4486 LOGE("failed to destroy pipeline");
4490 /* release miscellaneous information.
4491 these info needs to be released after pipeline is destroyed. */
4492 __mmplayer_release_misc_post(player);
4494 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4502 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4507 LOGW("set_message_callback is called with invalid player handle");
4508 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4511 player->msg_cb = callback;
4512 player->msg_cb_param = user_param;
4514 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4518 return MM_ERROR_NONE;
4522 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4524 int ret = MM_ERROR_NONE;
4529 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4530 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4531 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4533 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4535 if (strstr(uri, "es_buff://")) {
4536 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4537 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4538 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4539 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4541 tmp = g_ascii_strdown(uri, strlen(uri));
4542 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4543 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4545 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4547 } else if (strstr(uri, "mms://")) {
4548 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4549 } else if ((path = strstr(uri, "mem://"))) {
4550 ret = __mmplayer_set_mem_uri(data, path, param);
4552 ret = __mmplayer_set_file_uri(data, uri);
4555 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4556 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4557 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4558 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4560 /* dump parse result */
4561 SECURE_LOGW("incoming uri : %s", uri);
4562 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4563 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4571 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4574 mmplayer_t *player = NULL;
4575 MMMessageParamType msg = {0, };
4577 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4582 LOGE("user_data is null");
4586 player = (mmplayer_t *)user_data;
4588 if (!player->pipeline || !player->attrs) {
4589 LOGW("not initialized");
4593 LOGD("cmd lock player, cmd state : %d", player->cmd);
4594 MMPLAYER_CMD_LOCK(player);
4595 LOGD("cmd locked player");
4597 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4598 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4599 LOGW("player already destroyed");
4600 MMPLAYER_CMD_UNLOCK(player);
4604 player->interrupted_by_resource = TRUE;
4606 /* get last play position */
4607 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4608 msg.union_type = MM_MSG_UNION_TIME;
4609 msg.time.elapsed = pos;
4610 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4612 LOGW("failed to get play position.");
4615 LOGD("video resource conflict so, resource will be freed by unrealizing");
4616 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4617 LOGE("failed to unrealize");
4619 MMPLAYER_CMD_UNLOCK(player);
4621 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4622 player->hw_resource[res_idx] = NULL;
4626 return TRUE; /* release all the resources */
4630 __mmplayer_initialize_video_roi(mmplayer_t *player)
4632 player->video_roi.scale_x = 0.0;
4633 player->video_roi.scale_y = 0.0;
4634 player->video_roi.scale_width = 1.0;
4635 player->video_roi.scale_height = 1.0;
4639 _mmplayer_create_player(MMHandleType handle)
4641 int ret = MM_ERROR_PLAYER_INTERNAL;
4642 bool enabled = false;
4644 mmplayer_t *player = MM_PLAYER_CAST(handle);
4648 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4650 /* initialize player state */
4651 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4652 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4653 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4654 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4656 /* check current state */
4657 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4659 /* construct attributes */
4660 player->attrs = _mmplayer_construct_attribute(handle);
4662 if (!player->attrs) {
4663 LOGE("Failed to construct attributes");
4667 /* initialize gstreamer with configured parameter */
4668 if (!__mmplayer_init_gstreamer(player)) {
4669 LOGE("Initializing gstreamer failed");
4670 _mmplayer_deconstruct_attribute(handle);
4674 /* create lock. note that g_tread_init() has already called in gst_init() */
4675 g_mutex_init(&player->fsink_lock);
4677 /* create update tag lock */
4678 g_mutex_init(&player->update_tag_lock);
4680 /* create gapless play mutex */
4681 g_mutex_init(&player->gapless_play_thread_mutex);
4683 /* create gapless play cond */
4684 g_cond_init(&player->gapless_play_thread_cond);
4686 /* create gapless play thread */
4687 player->gapless_play_thread =
4688 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4689 if (!player->gapless_play_thread) {
4690 LOGE("failed to create gapless play thread");
4691 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4692 g_mutex_clear(&player->gapless_play_thread_mutex);
4693 g_cond_clear(&player->gapless_play_thread_cond);
4697 player->bus_msg_q = g_queue_new();
4698 if (!player->bus_msg_q) {
4699 LOGE("failed to create queue for bus_msg");
4700 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4704 ret = _mmplayer_initialize_video_capture(player);
4705 if (ret != MM_ERROR_NONE) {
4706 LOGE("failed to initialize video capture");
4710 /* initialize resource manager */
4711 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4712 __resource_release_cb, player, &player->resource_manager)
4713 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4714 LOGE("failed to create resource manager");
4715 ret = MM_ERROR_PLAYER_INTERNAL;
4719 /* create video bo lock and cond */
4720 g_mutex_init(&player->video_bo_mutex);
4721 g_cond_init(&player->video_bo_cond);
4723 /* create subtitle info lock and cond */
4724 g_mutex_init(&player->subtitle_info_mutex);
4725 g_cond_init(&player->subtitle_info_cond);
4727 player->streaming_type = STREAMING_SERVICE_NONE;
4729 /* give default value of audio effect setting */
4730 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4731 player->sound.rg_enable = false;
4732 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4734 player->play_subtitle = FALSE;
4735 player->has_closed_caption = FALSE;
4736 player->pending_resume = FALSE;
4737 if (player->ini.dump_element_keyword[0][0] == '\0')
4738 player->ini.set_dump_element_flag = FALSE;
4740 player->ini.set_dump_element_flag = TRUE;
4742 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4743 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4744 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4746 /* Set video360 settings to their defaults for just-created player.
4749 player->is_360_feature_enabled = FALSE;
4750 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4751 LOGI("spherical feature info: %d", enabled);
4753 player->is_360_feature_enabled = TRUE;
4755 LOGE("failed to get spherical feature info");
4758 player->is_content_spherical = FALSE;
4759 player->is_video360_enabled = TRUE;
4760 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4761 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4762 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4763 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4764 player->video360_zoom = 1.0f;
4765 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4766 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4768 __mmplayer_initialize_video_roi(player);
4770 /* set player state to null */
4771 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4772 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4776 return MM_ERROR_NONE;
4780 g_mutex_clear(&player->fsink_lock);
4781 /* free update tag lock */
4782 g_mutex_clear(&player->update_tag_lock);
4783 g_queue_free(player->bus_msg_q);
4784 player->bus_msg_q = NULL;
4785 /* free gapless play thread */
4786 if (player->gapless_play_thread) {
4787 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4788 player->gapless_play_thread_exit = TRUE;
4789 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4790 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4792 g_thread_join(player->gapless_play_thread);
4793 player->gapless_play_thread = NULL;
4795 g_mutex_clear(&player->gapless_play_thread_mutex);
4796 g_cond_clear(&player->gapless_play_thread_cond);
4799 /* release attributes */
4800 _mmplayer_deconstruct_attribute(handle);
4808 __mmplayer_init_gstreamer(mmplayer_t *player)
4810 static gboolean initialized = FALSE;
4811 static const int max_argc = 50;
4813 gchar **argv = NULL;
4814 gchar **argv2 = NULL;
4820 LOGD("gstreamer already initialized.");
4825 argc = malloc(sizeof(int));
4826 argv = malloc(sizeof(gchar *) * max_argc);
4827 argv2 = malloc(sizeof(gchar *) * max_argc);
4829 if (!argc || !argv || !argv2)
4832 memset(argv, 0, sizeof(gchar *) * max_argc);
4833 memset(argv2, 0, sizeof(gchar *) * max_argc);
4837 argv[0] = g_strdup("mmplayer");
4840 for (i = 0; i < 5; i++) {
4841 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4842 if (strlen(player->ini.gst_param[i]) > 0) {
4843 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4848 /* we would not do fork for scanning plugins */
4849 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4852 /* check disable registry scan */
4853 if (player->ini.skip_rescan) {
4854 argv[*argc] = g_strdup("--gst-disable-registry-update");
4858 /* check disable segtrap */
4859 if (player->ini.disable_segtrap) {
4860 argv[*argc] = g_strdup("--gst-disable-segtrap");
4864 LOGD("initializing gstreamer with following parameter");
4865 LOGD("argc : %d", *argc);
4868 for (i = 0; i < arg_count; i++) {
4870 LOGD("argv[%d] : %s", i, argv2[i]);
4873 /* initializing gstreamer */
4874 if (!gst_init_check(argc, &argv, &err)) {
4875 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4882 for (i = 0; i < arg_count; i++) {
4884 LOGD("release - argv[%d] : %s", i, argv2[i]);
4886 MMPLAYER_FREEIF(argv2[i]);
4889 MMPLAYER_FREEIF(argv);
4890 MMPLAYER_FREEIF(argv2);
4891 MMPLAYER_FREEIF(argc);
4901 for (i = 0; i < arg_count; i++) {
4902 LOGD("free[%d] : %s", i, argv2[i]);
4903 MMPLAYER_FREEIF(argv2[i]);
4906 MMPLAYER_FREEIF(argv);
4907 MMPLAYER_FREEIF(argv2);
4908 MMPLAYER_FREEIF(argc);
4914 __mmplayer_check_async_state_transition(mmplayer_t *player)
4916 GstState element_state = GST_STATE_VOID_PENDING;
4917 GstState element_pending_state = GST_STATE_VOID_PENDING;
4918 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4919 GstElement *element = NULL;
4920 gboolean async = FALSE;
4922 /* check player handle */
4923 MMPLAYER_RETURN_IF_FAIL(player &&
4925 player->pipeline->mainbin &&
4926 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4929 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4931 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4932 LOGD("don't need to check the pipeline state");
4936 MMPLAYER_PRINT_STATE(player);
4938 /* wait for state transition */
4939 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4940 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4942 if (ret == GST_STATE_CHANGE_FAILURE) {
4943 LOGE(" [%s] state : %s pending : %s",
4944 GST_ELEMENT_NAME(element),
4945 gst_element_state_get_name(element_state),
4946 gst_element_state_get_name(element_pending_state));
4948 /* dump state of all element */
4949 _mmplayer_dump_pipeline_state(player);
4954 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4959 _mmplayer_destroy(MMHandleType handle)
4961 mmplayer_t *player = MM_PLAYER_CAST(handle);
4965 /* check player handle */
4966 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4968 /* destroy can called at anytime */
4969 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4971 /* check async state transition */
4972 __mmplayer_check_async_state_transition(player);
4974 /* release gapless play thread */
4975 if (player->gapless_play_thread) {
4976 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4977 player->gapless_play_thread_exit = TRUE;
4978 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4979 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4981 LOGD("waiting for gapless play thread exit");
4982 g_thread_join(player->gapless_play_thread);
4983 g_mutex_clear(&player->gapless_play_thread_mutex);
4984 g_cond_clear(&player->gapless_play_thread_cond);
4985 LOGD("gapless play thread released");
4988 _mmplayer_release_video_capture(player);
4990 /* release miscellaneous information */
4991 __mmplayer_release_misc(player);
4993 /* release pipeline */
4994 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
4995 LOGE("failed to destroy pipeline");
4996 return MM_ERROR_PLAYER_INTERNAL;
4999 __mmplayer_destroy_hw_resource(player);
5001 g_queue_free(player->bus_msg_q);
5003 /* release subtitle info lock and cond */
5004 g_mutex_clear(&player->subtitle_info_mutex);
5005 g_cond_clear(&player->subtitle_info_cond);
5007 __mmplayer_release_dump_list(player->dump_list);
5009 /* release miscellaneous information.
5010 these info needs to be released after pipeline is destroyed. */
5011 __mmplayer_release_misc_post(player);
5013 /* release attributes */
5014 _mmplayer_deconstruct_attribute(handle);
5016 if (player->uri_info.uri_list) {
5017 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5018 player->uri_info.uri_list = NULL;
5022 g_mutex_clear(&player->fsink_lock);
5025 g_mutex_clear(&player->update_tag_lock);
5027 /* release video bo lock and cond */
5028 g_mutex_clear(&player->video_bo_mutex);
5029 g_cond_clear(&player->video_bo_cond);
5033 return MM_ERROR_NONE;
5037 _mmplayer_realize(MMHandleType hplayer)
5039 mmplayer_t *player = (mmplayer_t *)hplayer;
5040 int ret = MM_ERROR_NONE;
5043 MMHandleType attrs = 0;
5047 /* check player handle */
5048 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5050 /* check current state */
5051 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5053 attrs = MMPLAYER_GET_ATTRS(player);
5055 LOGE("fail to get attributes.");
5056 return MM_ERROR_PLAYER_INTERNAL;
5058 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5059 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5061 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5062 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5064 if (ret != MM_ERROR_NONE) {
5065 LOGE("failed to parse profile");
5070 if (uri && (strstr(uri, "es_buff://"))) {
5071 if (strstr(uri, "es_buff://push_mode"))
5072 player->es_player_push_mode = TRUE;
5074 player->es_player_push_mode = FALSE;
5077 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5078 LOGW("mms protocol is not supported format.");
5079 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5082 if (MMPLAYER_IS_STREAMING(player))
5083 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5085 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5087 player->smooth_streaming = FALSE;
5088 player->videodec_linked = 0;
5089 player->audiodec_linked = 0;
5090 player->textsink_linked = 0;
5091 player->is_external_subtitle_present = FALSE;
5092 player->is_external_subtitle_added_now = FALSE;
5093 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5094 player->video360_metadata.is_spherical = -1;
5095 player->is_openal_plugin_used = FALSE;
5096 player->subtitle_language_list = NULL;
5097 player->is_subtitle_force_drop = FALSE;
5099 _mmplayer_track_initialize(player);
5100 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5102 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5103 gint prebuffer_ms = 0, rebuffer_ms = 0;
5105 player->streamer = _mm_player_streaming_create();
5106 _mm_player_streaming_initialize(player->streamer, TRUE);
5108 mm_attrs_multiple_get(player->attrs, NULL,
5109 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5110 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5112 if (prebuffer_ms > 0) {
5113 prebuffer_ms = MAX(prebuffer_ms, 1000);
5114 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5117 if (rebuffer_ms > 0) {
5118 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5119 rebuffer_ms = MAX(rebuffer_ms, 1000);
5120 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5123 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5124 player->streamer->buffering_req.rebuffer_time);
5127 /* realize pipeline */
5128 ret = __mmplayer_gst_realize(player);
5129 if (ret != MM_ERROR_NONE)
5130 LOGE("fail to realize the player.");
5132 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5140 _mmplayer_unrealize(MMHandleType hplayer)
5142 mmplayer_t *player = (mmplayer_t *)hplayer;
5143 int ret = MM_ERROR_NONE;
5144 int rm_ret = MM_ERROR_NONE;
5145 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5149 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5151 MMPLAYER_CMD_UNLOCK(player);
5152 _mmplayer_bus_watcher_remove(player);
5153 /* destroy the gst bus msg thread which is created during realize.
5154 this funct have to be called before getting cmd lock. */
5155 _mmplayer_bus_msg_thread_destroy(player);
5156 MMPLAYER_CMD_LOCK(player);
5158 /* check current state */
5159 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5161 /* check async state transition */
5162 __mmplayer_check_async_state_transition(player);
5164 /* unrealize pipeline */
5165 ret = __mmplayer_gst_unrealize(player);
5167 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5168 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5169 if (rm_ret != MM_ERROR_NONE)
5170 LOGE("failed to release [%d] resources", res_idx);
5173 player->interrupted_by_resource = FALSE;
5180 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5182 mmplayer_t *player = (mmplayer_t *)hplayer;
5184 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5186 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5190 _mmplayer_get_state(MMHandleType hplayer, int *state)
5192 mmplayer_t *player = (mmplayer_t *)hplayer;
5194 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5196 *state = MMPLAYER_CURRENT_STATE(player);
5198 return MM_ERROR_NONE;
5202 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5204 GstElement *vol_element = NULL;
5205 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5208 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5209 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5211 /* check pipeline handle */
5212 if (!player->pipeline || !player->pipeline->audiobin) {
5213 LOGD("'%s' will be applied when audiobin is created", prop_name);
5215 /* NOTE : stored value will be used in create_audiobin
5216 * returning MM_ERROR_NONE here makes application to able to
5217 * set audio volume or mute at anytime.
5219 return MM_ERROR_NONE;
5222 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5223 volume_elem_id = MMPLAYER_A_SINK;
5225 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5227 LOGE("failed to get vol element %d", volume_elem_id);
5228 return MM_ERROR_PLAYER_INTERNAL;
5231 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5233 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5234 LOGE("there is no '%s' property", prop_name);
5235 return MM_ERROR_PLAYER_INTERNAL;
5238 if (!strcmp(prop_name, "volume")) {
5239 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5240 } else if (!strcmp(prop_name, "mute")) {
5241 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5243 LOGE("invalid property %s", prop_name);
5244 return MM_ERROR_PLAYER_INTERNAL;
5247 return MM_ERROR_NONE;
5251 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5253 int ret = MM_ERROR_NONE;
5254 mmplayer_t *player = (mmplayer_t *)hplayer;
5257 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5259 LOGD("volume = %f", volume);
5261 /* invalid factor range or not */
5262 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5263 LOGE("Invalid volume value");
5264 return MM_ERROR_INVALID_ARGUMENT;
5267 player->sound.volume = volume;
5269 ret = __mmplayer_gst_set_volume_property(player, "volume");
5276 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5278 mmplayer_t *player = (mmplayer_t *)hplayer;
5282 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5283 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5285 *volume = player->sound.volume;
5287 LOGD("current vol = %f", *volume);
5290 return MM_ERROR_NONE;
5294 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5296 int ret = MM_ERROR_NONE;
5297 mmplayer_t *player = (mmplayer_t *)hplayer;
5300 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5302 LOGD("mute = %d", mute);
5304 player->sound.mute = mute;
5306 ret = __mmplayer_gst_set_volume_property(player, "mute");
5313 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5315 mmplayer_t *player = (mmplayer_t *)hplayer;
5319 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5320 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5322 *mute = player->sound.mute;
5324 LOGD("current mute = %d", *mute);
5328 return MM_ERROR_NONE;
5332 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5334 mmplayer_t *player = (mmplayer_t *)hplayer;
5338 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5340 player->audio_stream_changed_cb = callback;
5341 player->audio_stream_changed_cb_user_param = user_param;
5342 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5346 return MM_ERROR_NONE;
5350 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5352 mmplayer_t *player = (mmplayer_t *)hplayer;
5356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5358 player->audio_decoded_cb = callback;
5359 player->audio_decoded_cb_user_param = user_param;
5360 player->audio_extract_opt = opt;
5361 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5365 return MM_ERROR_NONE;
5369 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5371 mmplayer_t *player = (mmplayer_t *)hplayer;
5375 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5377 if (callback && !player->bufmgr)
5378 player->bufmgr = tbm_bufmgr_init(-1);
5380 player->set_mode.video_export = (callback) ? true : false;
5381 player->video_decoded_cb = callback;
5382 player->video_decoded_cb_user_param = user_param;
5384 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5388 return MM_ERROR_NONE;
5392 _mmplayer_start(MMHandleType hplayer)
5394 mmplayer_t *player = (mmplayer_t *)hplayer;
5395 gint ret = MM_ERROR_NONE;
5399 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5401 /* check current state */
5402 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5404 /* start pipeline */
5405 ret = _mmplayer_gst_start(player);
5406 if (ret != MM_ERROR_NONE)
5407 LOGE("failed to start player.");
5409 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5410 LOGD("force playing start even during buffering");
5411 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5419 /* NOTE: post "not supported codec message" to application
5420 * when one codec is not found during AUTOPLUGGING in MSL.
5421 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5422 * And, if any codec is not found, don't send message here.
5423 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5426 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5428 MMMessageParamType msg_param;
5429 memset(&msg_param, 0, sizeof(MMMessageParamType));
5430 gboolean post_msg_direct = FALSE;
5434 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5436 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5437 player->not_supported_codec, player->can_support_codec);
5439 if (player->not_found_demuxer) {
5440 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5441 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5443 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5444 MMPLAYER_FREEIF(msg_param.data);
5446 return MM_ERROR_NONE;
5449 if (player->not_supported_codec) {
5450 if (player->can_support_codec) {
5451 // There is one codec to play
5452 post_msg_direct = TRUE;
5454 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5455 post_msg_direct = TRUE;
5458 if (post_msg_direct) {
5459 MMMessageParamType msg_param;
5460 memset(&msg_param, 0, sizeof(MMMessageParamType));
5462 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5463 LOGW("not found AUDIO codec, posting error code to application.");
5465 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5466 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5467 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5468 LOGW("not found VIDEO codec, posting error code to application.");
5470 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5471 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5474 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5476 MMPLAYER_FREEIF(msg_param.data);
5478 return MM_ERROR_NONE;
5480 // no any supported codec case
5481 LOGW("not found any codec, posting error code to application.");
5483 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5484 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5485 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5487 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5488 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5491 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5493 MMPLAYER_FREEIF(msg_param.data);
5499 return MM_ERROR_NONE;
5502 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5504 GstState element_state = GST_STATE_VOID_PENDING;
5505 GstState element_pending_state = GST_STATE_VOID_PENDING;
5506 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5507 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5509 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5511 MMPLAYER_RECONFIGURE_LOCK(player);
5512 if (!player->gapless.reconfigure) {
5513 MMPLAYER_RECONFIGURE_UNLOCK(player);
5517 LOGI("reconfigure is under process");
5518 MMPLAYER_RECONFIGURE_WAIT(player);
5519 MMPLAYER_RECONFIGURE_UNLOCK(player);
5520 LOGI("reconfigure is completed.");
5522 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5523 &element_state, &element_pending_state, timeout * GST_SECOND);
5524 if (result == GST_STATE_CHANGE_FAILURE)
5525 LOGW("failed to get pipeline state in %d sec", timeout);
5530 /* NOTE : it should be able to call 'stop' anytime*/
5532 _mmplayer_stop(MMHandleType hplayer)
5534 mmplayer_t *player = (mmplayer_t *)hplayer;
5535 int ret = MM_ERROR_NONE;
5539 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5541 /* check current state */
5542 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5544 /* need to wait till the rebuilding pipeline is completed */
5545 __mmplayer_check_pipeline_reconfigure_state(player);
5546 MMPLAYER_RECONFIGURE_LOCK(player);
5547 __mmplayer_reset_gapless_state(player);
5548 MMPLAYER_RECONFIGURE_UNLOCK(player);
5550 /* NOTE : application should not wait for EOS after calling STOP */
5551 _mmplayer_cancel_eos_timer(player);
5554 player->seek_state = MMPLAYER_SEEK_NONE;
5557 ret = _mmplayer_gst_stop(player);
5559 if (ret != MM_ERROR_NONE)
5560 LOGE("failed to stop player.");
5568 _mmplayer_pause(MMHandleType hplayer)
5570 mmplayer_t *player = (mmplayer_t *)hplayer;
5571 gint64 pos_nsec = 0;
5572 gboolean async = FALSE;
5573 gint ret = MM_ERROR_NONE;
5577 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5579 /* check current state */
5580 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5582 /* check pipeline reconfigure state */
5583 __mmplayer_check_pipeline_reconfigure_state(player);
5585 switch (MMPLAYER_CURRENT_STATE(player)) {
5586 case MM_PLAYER_STATE_READY:
5588 /* check prepare async or not.
5589 * In the case of streaming playback, it's recommended to avoid blocking wait.
5591 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5592 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5594 /* Changing back sync of rtspsrc to async */
5595 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5596 LOGD("async prepare working mode for rtsp");
5602 case MM_PLAYER_STATE_PLAYING:
5604 /* NOTE : store current point to overcome some bad operation
5605 *(returning zero when getting current position in paused state) of some
5608 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5609 LOGW("getting current position failed in paused");
5611 player->last_position = pos_nsec;
5613 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5614 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5615 This causes problem is position calculation during normal pause resume scenarios also.
5616 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5617 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5618 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5619 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5625 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5626 LOGD("doing async pause in case of ms buff src");
5630 /* pause pipeline */
5631 ret = _mmplayer_gst_pause(player, async);
5632 if (ret != MM_ERROR_NONE) {
5633 LOGE("failed to pause player. ret : 0x%x", ret);
5634 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5638 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5639 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5640 LOGE("failed to update display_rotation");
5644 return MM_ERROR_NONE;
5647 /* in case of streaming, pause could take long time.*/
5649 _mmplayer_abort_pause(MMHandleType hplayer)
5651 mmplayer_t *player = (mmplayer_t *)hplayer;
5652 int ret = MM_ERROR_NONE;
5656 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5658 player->pipeline->mainbin,
5659 MM_ERROR_PLAYER_NOT_INITIALIZED);
5661 LOGD("set the pipeline state to READY");
5663 /* set state to READY */
5664 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5665 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5666 if (ret != MM_ERROR_NONE) {
5667 LOGE("fail to change state to READY");
5668 return MM_ERROR_PLAYER_INTERNAL;
5671 LOGD("succeeded in changing state to READY");
5676 _mmplayer_resume(MMHandleType hplayer)
5678 mmplayer_t *player = (mmplayer_t *)hplayer;
5679 int ret = MM_ERROR_NONE;
5680 gboolean async = FALSE;
5684 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5686 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5687 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5688 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5692 /* Changing back sync mode rtspsrc to async */
5693 LOGD("async resume for rtsp case");
5697 /* check current state */
5698 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5700 ret = _mmplayer_gst_resume(player, async);
5701 if (ret != MM_ERROR_NONE)
5702 LOGE("failed to resume player.");
5704 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5705 LOGD("force resume even during buffering");
5706 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5715 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5717 mmplayer_t *player = (mmplayer_t *)hplayer;
5718 gint64 pos_nsec = 0;
5719 int ret = MM_ERROR_NONE;
5721 signed long long start = 0, stop = 0;
5722 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5725 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5726 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5728 /* The sound of video is not supported under 0.0 and over 2.0. */
5729 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5730 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5733 _mmplayer_set_mute(hplayer, mute);
5735 if (player->playback_rate == rate)
5736 return MM_ERROR_NONE;
5738 /* If the position is reached at start potion during fast backward, EOS is posted.
5739 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5741 player->playback_rate = rate;
5743 current_state = MMPLAYER_CURRENT_STATE(player);
5745 if (current_state != MM_PLAYER_STATE_PAUSED)
5746 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5748 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5750 if ((current_state == MM_PLAYER_STATE_PAUSED)
5751 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5752 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5753 pos_nsec = player->last_position;
5758 stop = GST_CLOCK_TIME_NONE;
5760 start = GST_CLOCK_TIME_NONE;
5764 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5765 player->playback_rate,
5767 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5768 GST_SEEK_TYPE_SET, start,
5769 GST_SEEK_TYPE_SET, stop)) {
5770 LOGE("failed to set speed playback");
5771 return MM_ERROR_PLAYER_SEEK;
5774 LOGD("succeeded to set speed playback as %0.1f", rate);
5778 return MM_ERROR_NONE;;
5782 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5784 mmplayer_t *player = (mmplayer_t *)hplayer;
5785 int ret = MM_ERROR_NONE;
5789 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5791 /* check pipeline reconfigure state */
5792 __mmplayer_check_pipeline_reconfigure_state(player);
5794 ret = _mmplayer_gst_set_position(player, position, FALSE);
5802 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5804 mmplayer_t *player = (mmplayer_t *)hplayer;
5805 int ret = MM_ERROR_NONE;
5807 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5808 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5810 if (g_strrstr(player->type, "video/mpegts"))
5811 __mmplayer_update_duration_value(player);
5813 *duration = player->duration;
5818 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5820 mmplayer_t *player = (mmplayer_t *)hplayer;
5821 int ret = MM_ERROR_NONE;
5823 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5825 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5831 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5833 mmplayer_t *player = (mmplayer_t *)hplayer;
5834 int ret = MM_ERROR_NONE;
5838 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5840 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5848 __mmplayer_is_midi_type(gchar *str_caps)
5850 if ((g_strrstr(str_caps, "audio/midi")) ||
5851 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5852 (g_strrstr(str_caps, "application/x-smaf")) ||
5853 (g_strrstr(str_caps, "audio/x-imelody")) ||
5854 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5855 (g_strrstr(str_caps, "audio/xmf")) ||
5856 (g_strrstr(str_caps, "audio/mxmf"))) {
5865 __mmplayer_is_only_mp3_type(gchar *str_caps)
5867 if (g_strrstr(str_caps, "application/x-id3") ||
5868 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5874 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5876 GstStructure *caps_structure = NULL;
5877 gint samplerate = 0;
5881 MMPLAYER_RETURN_IF_FAIL(player && caps);
5883 caps_structure = gst_caps_get_structure(caps, 0);
5885 /* set stream information */
5886 gst_structure_get_int(caps_structure, "rate", &samplerate);
5887 gst_structure_get_int(caps_structure, "channels", &channels);
5889 mm_player_set_attribute((MMHandleType)player, NULL,
5890 "content_audio_samplerate", samplerate,
5891 "content_audio_channels", channels, NULL);
5893 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5897 __mmplayer_update_content_type_info(mmplayer_t *player)
5900 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5902 if (__mmplayer_is_midi_type(player->type)) {
5903 player->bypass_audio_effect = TRUE;
5907 if (!player->streamer) {
5908 LOGD("no need to check streaming type");
5912 if (g_strrstr(player->type, "application/x-hls")) {
5913 /* If it can't know exact type when it parses uri because of redirection case,
5914 * it will be fixed by typefinder or when doing autoplugging.
5916 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5917 player->streamer->is_adaptive_streaming = TRUE;
5918 } else if (g_strrstr(player->type, "application/dash+xml")) {
5919 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5920 player->streamer->is_adaptive_streaming = TRUE;
5923 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5924 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5925 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5927 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5928 if (player->streamer->is_adaptive_streaming)
5929 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5931 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5935 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5940 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5941 GstCaps *caps, gpointer data)
5943 mmplayer_t *player = (mmplayer_t *)data;
5947 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5949 /* store type string */
5950 if (player->type_caps) {
5951 gst_caps_unref(player->type_caps);
5952 player->type_caps = NULL;
5955 player->type_caps = gst_caps_copy(caps);
5956 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5958 MMPLAYER_FREEIF(player->type);
5959 player->type = gst_caps_to_string(caps);
5961 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5962 player, player->type, probability, gst_caps_get_size(caps));
5964 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5965 (g_strrstr(player->type, "audio/x-raw-int"))) {
5966 LOGE("not support media format");
5968 if (player->msg_posted == FALSE) {
5969 MMMessageParamType msg_param;
5970 memset(&msg_param, 0, sizeof(MMMessageParamType));
5972 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5973 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5975 /* don't post more if one was sent already */
5976 player->msg_posted = TRUE;
5981 __mmplayer_update_content_type_info(player);
5983 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5986 pad = gst_element_get_static_pad(tf, "src");
5988 LOGE("fail to get typefind src pad.");
5992 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5993 gboolean async = FALSE;
5994 LOGE("failed to autoplug %s", player->type);
5996 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5998 if (async && player->msg_posted == FALSE)
5999 __mmplayer_handle_missed_plugin(player);
6001 gst_object_unref(GST_OBJECT(pad));
6008 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6010 GstElement *decodebin = NULL;
6014 /* create decodebin */
6015 decodebin = gst_element_factory_make("decodebin", NULL);
6018 LOGE("fail to create decodebin");
6022 /* raw pad handling signal */
6023 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6024 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6026 /* no-more-pad pad handling signal */
6027 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6028 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6030 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6031 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6033 /* This signal is emitted when a pad for which there is no further possible
6034 decoding is added to the decodebin.*/
6035 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6036 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6038 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6039 before looking for any elements that can handle that stream.*/
6040 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6041 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6043 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6044 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6045 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6047 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6048 before looking for any elements that can handle that stream.*/
6049 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6050 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6052 /* This signal is emitted once decodebin has finished decoding all the data.*/
6053 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6054 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6056 /* This signal is emitted when a element is added to the bin.*/
6057 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6058 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6065 __mmplayer_gst_make_queue2(mmplayer_t *player)
6067 GstElement *queue2 = NULL;
6068 gint64 dur_bytes = 0L;
6069 mmplayer_gst_element_t *mainbin = NULL;
6070 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6073 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6075 mainbin = player->pipeline->mainbin;
6077 queue2 = gst_element_factory_make("queue2", "queue2");
6079 LOGE("failed to create buffering queue element");
6083 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6084 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6086 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6088 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6089 * skip the pull mode(file or ring buffering) setting. */
6090 if (dur_bytes > 0) {
6091 if (!g_strrstr(player->type, "video/mpegts")) {
6092 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6093 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6099 _mm_player_streaming_set_queue2(player->streamer,
6103 (guint64)dur_bytes); /* no meaning at the moment */
6109 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6111 mmplayer_gst_element_t *mainbin = NULL;
6112 GstElement *decodebin = NULL;
6113 GstElement *queue2 = NULL;
6114 GstPad *sinkpad = NULL;
6115 GstPad *qsrcpad = NULL;
6118 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6120 mainbin = player->pipeline->mainbin;
6122 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6124 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6125 LOGW("need to check: muxed buffer is not null");
6128 queue2 = __mmplayer_gst_make_queue2(player);
6130 LOGE("failed to make queue2");
6134 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6135 LOGE("failed to add buffering queue");
6139 sinkpad = gst_element_get_static_pad(queue2, "sink");
6140 qsrcpad = gst_element_get_static_pad(queue2, "src");
6142 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6143 LOGE("failed to link [%s:%s]-[%s:%s]",
6144 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6148 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6149 LOGE("failed to sync queue2 state with parent");
6153 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6154 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6158 gst_object_unref(GST_OBJECT(sinkpad));
6162 /* create decodebin */
6163 decodebin = _mmplayer_gst_make_decodebin(player);
6165 LOGE("failed to make decodebin");
6169 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6170 LOGE("failed to add decodebin");
6174 /* to force caps on the decodebin element and avoid reparsing stuff by
6175 * typefind. It also avoids a deadlock in the way typefind activates pads in
6176 * the state change */
6177 g_object_set(decodebin, "sink-caps", caps, NULL);
6179 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6181 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6182 LOGE("failed to link [%s:%s]-[%s:%s]",
6183 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6187 gst_object_unref(GST_OBJECT(sinkpad));
6189 gst_object_unref(GST_OBJECT(qsrcpad));
6192 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6193 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6195 /* set decodebin property about buffer in streaming playback. *
6196 * in case of HLS/DASH, it does not need to have big buffer *
6197 * because it is kind of adaptive streaming. */
6198 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6199 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6200 gint high_percent = 0;
6202 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6203 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6205 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6207 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6209 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6210 "high-percent", high_percent,
6211 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6212 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6213 "max-size-buffers", 0, NULL); // disable or automatic
6216 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6217 LOGE("failed to sync decodebin state with parent");
6228 gst_object_unref(GST_OBJECT(sinkpad));
6231 gst_object_unref(GST_OBJECT(qsrcpad));
6234 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6235 * You need to explicitly set elements to the NULL state before
6236 * dropping the final reference, to allow them to clean up.
6238 gst_element_set_state(queue2, GST_STATE_NULL);
6240 /* And, it still has a parent "player".
6241 * You need to let the parent manage the object instead of unreffing the object directly.
6243 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6244 gst_object_unref(queue2);
6249 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6250 * You need to explicitly set elements to the NULL state before
6251 * dropping the final reference, to allow them to clean up.
6253 gst_element_set_state(decodebin, GST_STATE_NULL);
6255 /* And, it still has a parent "player".
6256 * You need to let the parent manage the object instead of unreffing the object directly.
6259 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6260 gst_object_unref(decodebin);
6268 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6272 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6273 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6275 LOGD("class : %s, mime : %s", factory_class, mime);
6277 /* add missing plugin */
6278 /* NOTE : msl should check missing plugin for image mime type.
6279 * Some motion jpeg clips can have playable audio track.
6280 * So, msl have to play audio after displaying popup written video format not supported.
6282 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6283 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6284 LOGD("not found demuxer");
6285 player->not_found_demuxer = TRUE;
6286 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6292 if (!g_strrstr(factory_class, "Demuxer")) {
6293 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6294 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6295 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6297 /* check that clip have multi tracks or not */
6298 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6299 LOGD("video plugin is already linked");
6301 LOGW("add VIDEO to missing plugin");
6302 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6303 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6305 } else if (g_str_has_prefix(mime, "audio")) {
6306 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6307 LOGD("audio plugin is already linked");
6309 LOGW("add AUDIO to missing plugin");
6310 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6311 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6319 return MM_ERROR_NONE;
6323 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6325 mmplayer_t *player = (mmplayer_t *)data;
6329 MMPLAYER_RETURN_IF_FAIL(player);
6331 /* remove fakesink. */
6332 if (!_mmplayer_gst_remove_fakesink(player,
6333 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6334 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6335 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6336 * source element are not same. To overcome this situation, this function will called
6337 * several places and several times. Therefore, this is not an error case.
6342 LOGD("[handle: %p] pipeline has completely constructed", player);
6344 if ((player->msg_posted == FALSE) &&
6345 (player->cmd >= MMPLAYER_COMMAND_START))
6346 __mmplayer_handle_missed_plugin(player);
6348 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6352 __mmplayer_check_profile(void)
6355 static int profile_tv = -1;
6357 if (__builtin_expect(profile_tv != -1, 1))
6360 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6361 switch (*profileName) {
6376 __mmplayer_get_next_uri(mmplayer_t *player)
6378 mmplayer_parse_profile_t profile;
6380 guint num_of_list = 0;
6383 num_of_list = g_list_length(player->uri_info.uri_list);
6384 uri_idx = player->uri_info.uri_idx;
6386 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6387 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6388 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6390 LOGW("next uri does not exist");
6394 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6395 LOGE("failed to parse profile");
6399 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6400 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6401 LOGW("uri type is not supported(%d)", profile.uri_type);
6405 LOGD("success to find next uri %d", uri_idx);
6409 if (!uri || uri_idx == num_of_list) {
6410 LOGE("failed to find next uri");
6414 player->uri_info.uri_idx = uri_idx;
6415 if (mm_player_set_attribute((MMHandleType)player, NULL,
6416 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6417 LOGE("failed to set attribute");
6421 SECURE_LOGD("next playback uri: %s", uri);
6426 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6428 #define REPEAT_COUNT_INFINITE -1
6429 #define REPEAT_COUNT_MIN 2
6430 #define ORIGINAL_URI_ONLY 1
6432 MMHandleType attrs = 0;
6436 guint num_of_uri = 0;
6437 int profile_tv = -1;
6441 LOGD("checking for gapless play option");
6443 if (player->build_audio_offload) {
6444 LOGE("offload path is not supportable.");
6448 if (player->pipeline->textbin) {
6449 LOGE("subtitle path is enabled. gapless play is not supported.");
6453 attrs = MMPLAYER_GET_ATTRS(player);
6455 LOGE("fail to get attributes.");
6459 mm_attrs_multiple_get(player->attrs, NULL,
6460 "content_video_found", &video,
6461 "profile_play_count", &count,
6462 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6464 /* gapless playback is not supported in case of video at TV profile. */
6465 profile_tv = __mmplayer_check_profile();
6466 if (profile_tv && video) {
6467 LOGW("not support video gapless playback");
6471 /* check repeat count in case of audio */
6473 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6474 LOGW("gapless is disabled");
6478 num_of_uri = g_list_length(player->uri_info.uri_list);
6480 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6482 if (num_of_uri == ORIGINAL_URI_ONLY) {
6483 /* audio looping path */
6484 if (count >= REPEAT_COUNT_MIN) {
6485 /* decrease play count */
6486 /* we succeeded to rewind. update play count and then wait for next EOS */
6488 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6489 } else if (count != REPEAT_COUNT_INFINITE) {
6490 LOGD("there is no next uri and no repeat");
6493 LOGD("looping cnt %d", count);
6495 /* gapless playback path */
6496 if (!__mmplayer_get_next_uri(player)) {
6497 LOGE("failed to get next uri");
6504 LOGE("unable to play gapless path. EOS will be posted soon");
6509 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6511 GstPad *sinkpad = g_value_get_object (item);
6512 GstElement *element = GST_ELEMENT(user_data);
6513 if (!sinkpad || !element) {
6514 LOGE("invalid parameter");
6518 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6519 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6523 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6525 mmplayer_gst_element_t *sinkbin = NULL;
6526 main_element_id_e concatId = MMPLAYER_M_NUM;
6527 main_element_id_e sinkId = MMPLAYER_M_NUM;
6528 gboolean send_notice = FALSE;
6529 GstElement *element;
6533 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6535 LOGD("type %d", type);
6538 case MM_PLAYER_TRACK_TYPE_AUDIO:
6539 concatId = MMPLAYER_M_A_CONCAT;
6540 sinkId = MMPLAYER_A_BIN;
6541 sinkbin = player->pipeline->audiobin;
6543 case MM_PLAYER_TRACK_TYPE_VIDEO:
6544 concatId = MMPLAYER_M_V_CONCAT;
6545 sinkId = MMPLAYER_V_BIN;
6546 sinkbin = player->pipeline->videobin;
6549 case MM_PLAYER_TRACK_TYPE_TEXT:
6550 concatId = MMPLAYER_M_T_CONCAT;
6551 sinkId = MMPLAYER_T_BIN;
6552 sinkbin = player->pipeline->textbin;
6555 LOGE("requested type is not supportable");
6560 element = player->pipeline->mainbin[concatId].gst;
6564 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6565 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6566 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6567 if (srcpad && sinkpad) {
6568 /* after getting drained signal there is no data flows, so no need to do pad_block */
6569 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6570 gst_pad_unlink(srcpad, sinkpad);
6572 /* send custom event to sink pad to handle it at video sink */
6574 LOGD("send custom event to sinkpad");
6575 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6576 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6577 gst_pad_send_event(sinkpad, event);
6580 gst_object_unref(srcpad);
6581 gst_object_unref(sinkpad);
6584 LOGD("release concat request pad");
6585 /* release and unref requests pad from the selector */
6586 iter = gst_element_iterate_sink_pads(element);
6587 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6588 gst_iterator_resync(iter);
6589 gst_iterator_free(iter);
6595 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6597 mmplayer_track_t *selector = &player->track[type];
6598 mmplayer_gst_element_t *sinkbin = NULL;
6599 main_element_id_e selectorId = MMPLAYER_M_NUM;
6600 main_element_id_e sinkId = MMPLAYER_M_NUM;
6601 GstPad *srcpad = NULL;
6602 GstPad *sinkpad = NULL;
6603 gboolean send_notice = FALSE;
6606 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6608 LOGD("type %d", type);
6611 case MM_PLAYER_TRACK_TYPE_AUDIO:
6612 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6613 sinkId = MMPLAYER_A_BIN;
6614 sinkbin = player->pipeline->audiobin;
6616 case MM_PLAYER_TRACK_TYPE_VIDEO:
6617 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6618 sinkId = MMPLAYER_V_BIN;
6619 sinkbin = player->pipeline->videobin;
6622 case MM_PLAYER_TRACK_TYPE_TEXT:
6623 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6624 sinkId = MMPLAYER_T_BIN;
6625 sinkbin = player->pipeline->textbin;
6628 LOGE("requested type is not supportable");
6633 if (player->pipeline->mainbin[selectorId].gst) {
6636 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6638 if (selector->event_probe_id != 0)
6639 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6640 selector->event_probe_id = 0;
6642 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6643 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6645 if (srcpad && sinkpad) {
6646 /* after getting drained signal there is no data flows, so no need to do pad_block */
6647 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6648 gst_pad_unlink(srcpad, sinkpad);
6650 /* send custom event to sink pad to handle it at video sink */
6652 LOGD("send custom event to sinkpad");
6653 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6654 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6655 gst_pad_send_event(sinkpad, event);
6659 gst_object_unref(sinkpad);
6662 gst_object_unref(srcpad);
6665 LOGD("selector release");
6667 /* release and unref requests pad from the selector */
6668 for (n = 0; n < selector->streams->len; n++) {
6669 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6670 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6673 g_ptr_array_set_size(selector->streams, 0);
6675 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6676 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6678 player->pipeline->mainbin[selectorId].gst = NULL;
6686 __mmplayer_deactivate_old_path(mmplayer_t *player)
6689 MMPLAYER_RETURN_IF_FAIL(player);
6691 if (MMPLAYER_USE_DECODEBIN(player)) {
6692 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6693 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6694 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6695 LOGE("deactivate selector error");
6699 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6700 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6701 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6702 LOGE("deactivate concat error");
6707 _mmplayer_track_destroy(player);
6708 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6710 if (player->streamer) {
6711 _mm_player_streaming_initialize(player->streamer, FALSE);
6712 _mm_player_streaming_destroy(player->streamer);
6713 player->streamer = NULL;
6716 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6722 if (!player->msg_posted) {
6723 MMMessageParamType msg = {0,};
6726 msg.code = MM_ERROR_PLAYER_INTERNAL;
6727 LOGE("gapless_uri_play> deactivate error");
6729 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6730 player->msg_posted = TRUE;
6736 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6738 int result = MM_ERROR_NONE;
6739 mmplayer_t *player = (mmplayer_t *)hplayer;
6742 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6743 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6745 if (mm_player_set_attribute(hplayer, NULL,
6746 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6747 LOGE("failed to set attribute");
6748 result = MM_ERROR_PLAYER_INTERNAL;
6750 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6751 LOGE("failed to add the original uri in the uri list.");
6759 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6761 mmplayer_t *player = (mmplayer_t *)hplayer;
6762 guint num_of_list = 0;
6766 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6767 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6769 if (player->pipeline && player->pipeline->textbin) {
6770 LOGE("subtitle path is enabled.");
6771 return MM_ERROR_PLAYER_INVALID_STATE;
6774 num_of_list = g_list_length(player->uri_info.uri_list);
6776 if (is_first_path) {
6777 if (num_of_list == 0) {
6778 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6779 SECURE_LOGD("add original path : %s", uri);
6781 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6782 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6784 SECURE_LOGD("change original path : %s", uri);
6787 MMHandleType attrs = 0;
6788 attrs = MMPLAYER_GET_ATTRS(player);
6790 if (num_of_list == 0) {
6791 char *original_uri = NULL;
6794 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6796 if (!original_uri) {
6797 LOGE("there is no original uri.");
6798 return MM_ERROR_PLAYER_INVALID_STATE;
6801 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6802 player->uri_info.uri_idx = 0;
6804 SECURE_LOGD("add original path at first : %s", original_uri);
6808 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6809 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6813 return MM_ERROR_NONE;
6817 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6819 mmplayer_t *player = (mmplayer_t *)hplayer;
6820 char *next_uri = NULL;
6821 guint num_of_list = 0;
6824 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6826 num_of_list = g_list_length(player->uri_info.uri_list);
6828 if (num_of_list > 0) {
6829 gint uri_idx = player->uri_info.uri_idx;
6831 if (uri_idx < num_of_list - 1)
6836 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6837 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6839 *uri = g_strdup(next_uri);
6843 return MM_ERROR_NONE;
6847 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6848 GstCaps *caps, gpointer data)
6850 mmplayer_t *player = (mmplayer_t *)data;
6851 const gchar *klass = NULL;
6852 const gchar *mime = NULL;
6853 gchar *caps_str = NULL;
6855 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6856 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6857 caps_str = gst_caps_to_string(caps);
6859 LOGW("unknown type of caps : %s from %s",
6860 caps_str, GST_ELEMENT_NAME(elem));
6862 MMPLAYER_FREEIF(caps_str);
6864 /* There is no available codec. */
6865 __mmplayer_check_not_supported_codec(player, klass, mime);
6869 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6870 GstCaps *caps, gpointer data)
6872 mmplayer_t *player = (mmplayer_t *)data;
6873 const char *mime = NULL;
6874 gboolean ret = TRUE;
6876 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6877 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6879 if (g_str_has_prefix(mime, "audio")) {
6880 GstStructure *caps_structure = NULL;
6881 gint samplerate = 0;
6883 gchar *caps_str = NULL;
6885 caps_structure = gst_caps_get_structure(caps, 0);
6886 gst_structure_get_int(caps_structure, "rate", &samplerate);
6887 gst_structure_get_int(caps_structure, "channels", &channels);
6889 if ((channels > 0 && samplerate == 0)) {
6890 LOGD("exclude audio...");
6894 caps_str = gst_caps_to_string(caps);
6895 /* set it directly because not sent by TAG */
6896 if (g_strrstr(caps_str, "mobile-xmf"))
6897 mm_player_set_attribute((MMHandleType)player, NULL,
6898 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6900 MMPLAYER_FREEIF(caps_str);
6901 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6902 LOGD("already video linked");
6905 LOGD("found new stream");
6912 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6914 gboolean ret = FALSE;
6915 GDBusConnection *conn = NULL;
6917 GVariant *result = NULL;
6918 const gchar *dbus_device_type = NULL;
6919 const gchar *dbus_ret = NULL;
6922 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6924 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6929 result = g_dbus_connection_call_sync(conn,
6930 "org.pulseaudio.Server",
6931 "/org/pulseaudio/StreamManager",
6932 "org.pulseaudio.StreamManager",
6933 "GetCurrentMediaRoutingPath",
6934 g_variant_new("(s)", "out"),
6935 G_VARIANT_TYPE("(ss)"),
6936 G_DBUS_CALL_FLAGS_NONE,
6940 if (!result || err) {
6941 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6946 /* device type is listed in stream-map.json at mmfw-sysconf */
6947 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6949 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6950 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6953 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6954 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6955 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6956 LOGD("audio offload is supportable");
6962 LOGD("audio offload is not supportable");
6965 g_variant_unref(result);
6967 g_object_unref(conn);
6972 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6974 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6975 gint64 position = 0;
6977 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6978 player->pipeline && player->pipeline->mainbin);
6980 MMPLAYER_CMD_LOCK(player);
6981 current_state = MMPLAYER_CURRENT_STATE(player);
6983 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6984 LOGW("getting current position failed in paused");
6986 _mmplayer_unrealize((MMHandleType)player);
6987 _mmplayer_realize((MMHandleType)player);
6989 _mmplayer_set_position((MMHandleType)player, position);
6991 /* async not to be blocked in streaming case */
6992 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
6994 _mmplayer_pause((MMHandleType)player);
6996 if (current_state == MM_PLAYER_STATE_PLAYING)
6997 _mmplayer_start((MMHandleType)player);
6998 MMPLAYER_CMD_UNLOCK(player);
7000 LOGD("rebuilding audio pipeline is completed.");
7003 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7005 mmplayer_t *player = (mmplayer_t *)user_data;
7006 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7007 gboolean is_supportable = FALSE;
7009 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7010 LOGW("failed to get device type");
7012 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7014 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7015 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7016 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7017 LOGD("ignore this dev connected info");
7021 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7022 if (player->build_audio_offload == is_supportable) {
7023 LOGD("keep current pipeline without re-building");
7027 /* rebuild pipeline */
7028 LOGD("re-build pipeline - offload: %d", is_supportable);
7029 player->build_audio_offload = FALSE;
7030 __mmplayer_rebuild_audio_pipeline(player);
7036 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7038 unsigned int id = 0;
7040 if (player->audio_device_cb_id != 0) {
7041 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7045 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7046 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7047 LOGD("added device connected cb (%u)", id);
7048 player->audio_device_cb_id = id;
7050 LOGW("failed to add device connected cb");
7057 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7059 mmplayer_t *player = (mmplayer_t *)hplayer;
7062 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7063 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7065 *activated = player->build_audio_offload;
7067 LOGD("offload activated : %d", (int)*activated);
7070 return MM_ERROR_NONE;
7074 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7077 this function need to be updated according to the supported media format
7078 @see player->ini.audio_offload_media_format */
7080 if (__mmplayer_is_only_mp3_type(player->type)) {
7081 LOGD("offload supportable media format type");
7089 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7091 gboolean ret = FALSE;
7092 GstElementFactory *factory = NULL;
7095 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7097 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7098 if (!__mmplayer_is_offload_supported_type(player))
7101 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7102 LOGD("there is no audio offload sink");
7106 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7107 LOGW("there is no audio device type to support offload");
7111 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7113 LOGW("there is no installed audio offload sink element");
7116 gst_object_unref(factory);
7118 if (_mmplayer_acquire_hw_resource(player,
7119 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7120 LOGE("failed to acquire audio offload decoder resource");
7124 if (!__mmplayer_add_audio_device_connected_cb(player))
7127 if (!__mmplayer_is_audio_offload_device_type(player))
7130 LOGD("audio offload can be built");
7135 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7141 static GstAutoplugSelectResult
7142 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7144 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7145 int audio_offload = 0;
7147 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7148 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7150 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7151 LOGD("expose audio path to build offload output path");
7152 player->build_audio_offload = TRUE;
7153 /* update codec info */
7154 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7155 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7156 player->audiodec_linked = 1;
7158 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7162 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7163 And need to consider the multi-track audio content.
7164 There is no HW audio decoder in public. */
7166 /* set stream information */
7167 if (!player->audiodec_linked)
7168 _mmplayer_set_audio_attrs(player, caps);
7170 /* update codec info */
7171 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7172 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7173 player->audiodec_linked = 1;
7175 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7177 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7178 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7180 /* mark video decoder for acquire */
7181 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7182 LOGW("video decoder resource is already acquired, skip it.");
7183 ret = GST_AUTOPLUG_SELECT_SKIP;
7187 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7188 LOGE("failed to acquire video decoder resource");
7189 ret = GST_AUTOPLUG_SELECT_SKIP;
7192 player->interrupted_by_resource = FALSE;
7195 /* update codec info */
7196 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7197 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7198 player->videodec_linked = 1;
7206 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7207 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7209 #define DEFAULT_IDX 0xFFFF
7210 #define MIN_FACTORY_NUM 2
7211 mmplayer_t *player = (mmplayer_t *)data;
7212 GValueArray *new_factories = NULL;
7213 GValue val = { 0, };
7214 GstElementFactory *factory = NULL;
7215 const gchar *klass = NULL;
7216 gchar *factory_name = NULL;
7217 guint hw_dec_idx = DEFAULT_IDX;
7218 guint first_sw_dec_idx = DEFAULT_IDX;
7219 guint last_sw_dec_idx = DEFAULT_IDX;
7220 guint new_pos = DEFAULT_IDX;
7221 guint rm_pos = DEFAULT_IDX;
7222 int audio_codec_type;
7223 int video_codec_type;
7224 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7226 if (factories->n_values < MIN_FACTORY_NUM)
7229 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7230 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7233 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7235 for (int i = 0 ; i < factories->n_values ; i++) {
7236 gchar *hw_dec_info = NULL;
7237 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7239 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7241 LOGW("failed to get factory object");
7244 klass = gst_element_factory_get_klass(factory);
7245 factory_name = GST_OBJECT_NAME(factory);
7248 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7250 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7251 if (!player->need_audio_dec_sorting) {
7252 LOGD("sorting is not required");
7255 codec_type = audio_codec_type;
7256 hw_dec_info = player->ini.audiocodec_element_hw;
7257 sw_dec_info = player->ini.audiocodec_element_sw;
7258 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7259 if (!player->need_video_dec_sorting) {
7260 LOGD("sorting is not required");
7263 codec_type = video_codec_type;
7264 hw_dec_info = player->ini.videocodec_element_hw;
7265 sw_dec_info = player->ini.videocodec_element_sw;
7270 if (g_strrstr(factory_name, hw_dec_info)) {
7273 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7274 if (strstr(factory_name, sw_dec_info[j])) {
7275 last_sw_dec_idx = i;
7276 if (first_sw_dec_idx == DEFAULT_IDX) {
7277 first_sw_dec_idx = i;
7282 if (first_sw_dec_idx == DEFAULT_IDX)
7283 LOGW("unknown codec %s", factory_name);
7287 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7290 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7291 if (hw_dec_idx < first_sw_dec_idx)
7293 new_pos = first_sw_dec_idx;
7294 rm_pos = hw_dec_idx + 1;
7295 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7296 if (last_sw_dec_idx < hw_dec_idx)
7298 new_pos = last_sw_dec_idx + 1;
7299 rm_pos = hw_dec_idx;
7304 /* change position - insert H/W decoder according to the new position */
7305 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7307 LOGW("failed to get factory object");
7310 new_factories = g_value_array_copy(factories);
7311 g_value_init (&val, G_TYPE_OBJECT);
7312 g_value_set_object (&val, factory);
7313 g_value_array_insert(new_factories, new_pos, &val);
7314 g_value_unset (&val);
7315 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7317 for (int i = 0 ; i < new_factories->n_values ; i++) {
7318 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7320 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7321 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7323 LOGE("[Re-arranged] failed to get factory object");
7326 return new_factories;
7330 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7331 GstCaps *caps, GstElementFactory *factory, gpointer data)
7333 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7334 mmplayer_t *player = (mmplayer_t *)data;
7336 gchar *factory_name = NULL;
7337 gchar *caps_str = NULL;
7338 const gchar *klass = NULL;
7341 factory_name = GST_OBJECT_NAME(factory);
7342 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7343 caps_str = gst_caps_to_string(caps);
7345 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7347 /* store type string */
7348 if (player->type == NULL) {
7349 player->type = gst_caps_to_string(caps);
7350 __mmplayer_update_content_type_info(player);
7353 /* filtering exclude keyword */
7354 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7355 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7356 LOGW("skipping [%s] by exclude keyword [%s]",
7357 factory_name, player->ini.exclude_element_keyword[idx]);
7359 result = GST_AUTOPLUG_SELECT_SKIP;
7364 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7365 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7366 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7367 factory_name, player->ini.unsupported_codec_keyword[idx]);
7368 result = GST_AUTOPLUG_SELECT_SKIP;
7373 /* exclude webm format */
7374 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7375 * because webm format is not supportable.
7376 * If webm is disabled in "autoplug-continue", there is no state change
7377 * failure or error because the decodebin will expose the pad directly.
7378 * It make MSL invoke _prepare_async_callback.
7379 * So, we need to disable webm format in "autoplug-select" */
7380 if (caps_str && strstr(caps_str, "webm")) {
7381 LOGW("webm is not supported");
7382 result = GST_AUTOPLUG_SELECT_SKIP;
7386 /* check factory class for filtering */
7387 /* NOTE : msl don't need to use image plugins.
7388 * So, those plugins should be skipped for error handling.
7390 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7391 LOGD("skipping [%s] by not required", factory_name);
7392 result = GST_AUTOPLUG_SELECT_SKIP;
7396 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7397 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7398 // TO CHECK : subtitle if needed, add subparse exception.
7399 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7400 result = GST_AUTOPLUG_SELECT_SKIP;
7404 if (g_strrstr(factory_name, "mpegpsdemux")) {
7405 LOGD("skipping PS container - not support");
7406 result = GST_AUTOPLUG_SELECT_SKIP;
7410 if (g_strrstr(factory_name, "mssdemux"))
7411 player->smooth_streaming = TRUE;
7413 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7414 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7417 GstStructure *str = NULL;
7418 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7420 /* don't make video because of not required */
7421 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7422 (!player->set_mode.video_export)) {
7423 LOGD("no need video decoding, expose pad");
7424 result = GST_AUTOPLUG_SELECT_EXPOSE;
7428 /* get w/h for omx state-tune */
7429 /* FIXME: deprecated? */
7430 str = gst_caps_get_structure(caps, 0);
7431 gst_structure_get_int(str, "width", &width);
7434 if (player->v_stream_caps) {
7435 gst_caps_unref(player->v_stream_caps);
7436 player->v_stream_caps = NULL;
7439 player->v_stream_caps = gst_caps_copy(caps);
7440 LOGD("take caps for video state tune");
7441 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7445 if (g_strrstr(klass, "Codec/Decoder")) {
7446 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7447 if (result != GST_AUTOPLUG_SELECT_TRY) {
7448 LOGW("skip add decoder");
7454 MMPLAYER_FREEIF(caps_str);
7460 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7463 //mmplayer_t *player = (mmplayer_t *)data;
7464 GstCaps *caps = NULL;
7466 LOGD("[Decodebin2] pad-removed signal");
7468 caps = gst_pad_query_caps(new_pad, NULL);
7470 LOGW("query caps is NULL");
7474 gchar *caps_str = NULL;
7475 caps_str = gst_caps_to_string(caps);
7477 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7479 MMPLAYER_FREEIF(caps_str);
7480 gst_caps_unref(caps);
7484 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7486 mmplayer_t *player = (mmplayer_t *)data;
7489 MMPLAYER_RETURN_IF_FAIL(player);
7491 LOGD("got about to finish signal");
7493 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7494 LOGW("Fail to get cmd lock");
7498 if (!__mmplayer_verify_gapless_play_path(player)) {
7499 LOGD("decoding is finished.");
7500 MMPLAYER_CMD_UNLOCK(player);
7504 _mmplayer_set_reconfigure_state(player, TRUE);
7505 MMPLAYER_CMD_UNLOCK(player);
7507 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL);
7508 __mmplayer_deactivate_old_path(player);
7514 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7516 mmplayer_t *player = (mmplayer_t *)data;
7517 GstIterator *iter = NULL;
7518 GValue item = { 0, };
7520 gboolean done = FALSE;
7521 gboolean is_all_drained = TRUE;
7524 MMPLAYER_RETURN_IF_FAIL(player);
7526 LOGD("got drained signal");
7528 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7529 LOGW("Fail to get cmd lock");
7533 if (!__mmplayer_verify_gapless_play_path(player)) {
7534 LOGD("decoding is finished.");
7535 MMPLAYER_CMD_UNLOCK(player);
7539 _mmplayer_set_reconfigure_state(player, TRUE);
7540 MMPLAYER_CMD_UNLOCK(player);
7542 /* check decodebin src pads whether they received EOS or not */
7543 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7546 switch (gst_iterator_next(iter, &item)) {
7547 case GST_ITERATOR_OK:
7548 pad = g_value_get_object(&item);
7549 if (pad && !GST_PAD_IS_EOS(pad)) {
7550 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7551 is_all_drained = FALSE;
7554 g_value_reset(&item);
7556 case GST_ITERATOR_RESYNC:
7557 gst_iterator_resync(iter);
7559 case GST_ITERATOR_ERROR:
7560 case GST_ITERATOR_DONE:
7565 g_value_unset(&item);
7566 gst_iterator_free(iter);
7568 if (!is_all_drained) {
7569 LOGD("Wait util the all pads get EOS.");
7574 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7575 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7577 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7578 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7579 __mmplayer_deactivate_old_path(player);
7585 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7587 mmplayer_t *player = (mmplayer_t *)data;
7588 const gchar *klass = NULL;
7589 gchar *factory_name = NULL;
7591 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7592 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7594 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7596 if (__mmplayer_add_dump_buffer_probe(player, element))
7597 LOGD("add buffer probe");
7599 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7600 gchar *selected = NULL;
7601 selected = g_strdup(GST_ELEMENT_NAME(element));
7602 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7604 /* update codec info */
7605 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7606 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7607 player->audiodec_linked = 1;
7608 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7609 /* update codec info */
7610 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7611 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7612 player->videodec_linked = 1;
7615 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7616 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7617 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7619 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7620 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7622 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7623 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7624 "max-video-width", player->adaptive_info.limit.width,
7625 "max-video-height", player->adaptive_info.limit.height, NULL);
7627 } else if (g_strrstr(klass, "Demuxer")) {
7629 LOGD("plugged element is demuxer. take it");
7631 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7632 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7635 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7636 int surface_type = 0;
7638 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7641 // to support trust-zone only
7642 if (g_strrstr(factory_name, "asfdemux")) {
7643 LOGD("set file-location %s", player->profile.uri);
7644 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7645 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7646 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7647 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7648 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7649 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7650 (__mmplayer_is_only_mp3_type(player->type))) {
7651 LOGD("[mpegaudioparse] set streaming pull mode.");
7652 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7654 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7655 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7658 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7659 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7660 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7662 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7663 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7665 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7666 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7667 (MMPLAYER_IS_DASH_STREAMING(player))) {
7668 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7669 _mm_player_streaming_set_multiqueue(player->streamer, element);
7670 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7679 __mmplayer_release_misc(mmplayer_t *player)
7682 bool cur_mode = player->set_mode.rich_audio;
7685 MMPLAYER_RETURN_IF_FAIL(player);
7687 player->sent_bos = FALSE;
7688 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7690 player->seek_state = MMPLAYER_SEEK_NONE;
7692 player->total_bitrate = 0;
7693 player->total_maximum_bitrate = 0;
7695 player->not_found_demuxer = 0;
7697 player->last_position = 0;
7698 player->duration = 0;
7699 player->http_content_size = 0;
7700 player->not_supported_codec = MISSING_PLUGIN_NONE;
7701 player->can_support_codec = FOUND_PLUGIN_NONE;
7702 player->pending_seek.is_pending = false;
7703 player->pending_seek.pos = 0;
7704 player->msg_posted = FALSE;
7705 player->has_many_types = FALSE;
7706 player->is_subtitle_force_drop = FALSE;
7707 player->play_subtitle = FALSE;
7708 player->adjust_subtitle_pos = 0;
7709 player->has_closed_caption = FALSE;
7710 player->set_mode.video_export = false;
7711 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7712 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7714 player->set_mode.rich_audio = cur_mode;
7716 if (player->audio_device_cb_id > 0 &&
7717 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7718 LOGW("failed to remove audio device_connected_callback");
7719 player->audio_device_cb_id = 0;
7721 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7722 player->bitrate[i] = 0;
7723 player->maximum_bitrate[i] = 0;
7726 /* free memory related to audio effect */
7727 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7729 if (player->adaptive_info.var_list) {
7730 g_list_free_full(player->adaptive_info.var_list, g_free);
7731 player->adaptive_info.var_list = NULL;
7734 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7735 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7736 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7738 /* Reset video360 settings to their defaults in case if the pipeline is to be
7741 player->video360_metadata.is_spherical = -1;
7742 player->is_openal_plugin_used = FALSE;
7744 player->is_content_spherical = FALSE;
7745 player->is_video360_enabled = TRUE;
7746 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7747 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7748 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7749 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7750 player->video360_zoom = 1.0f;
7751 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7752 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7754 player->sound.rg_enable = false;
7756 __mmplayer_initialize_video_roi(player);
7761 __mmplayer_release_misc_post(mmplayer_t *player)
7763 char *original_uri = NULL;
7766 /* player->pipeline is already released before. */
7767 MMPLAYER_RETURN_IF_FAIL(player);
7769 player->video_decoded_cb = NULL;
7770 player->video_decoded_cb_user_param = NULL;
7771 player->video_stream_prerolled = false;
7773 player->audio_decoded_cb = NULL;
7774 player->audio_decoded_cb_user_param = NULL;
7775 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7777 player->audio_stream_changed_cb = NULL;
7778 player->audio_stream_changed_cb_user_param = NULL;
7780 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7782 /* clean found audio decoders */
7783 if (player->audio_decoders) {
7784 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7785 player->audio_decoders = NULL;
7788 /* clean the uri list except original uri */
7789 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7791 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7792 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7793 g_list_free_full(tmp, (GDestroyNotify)g_free);
7796 LOGW("failed to get original uri info");
7798 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7799 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7803 /* clear the audio stream buffer list */
7804 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7806 /* clear the video stream bo list */
7807 __mmplayer_video_stream_destroy_bo_list(player);
7808 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7810 if (player->profile.input_mem.buf) {
7811 free(player->profile.input_mem.buf);
7812 player->profile.input_mem.buf = NULL;
7814 player->profile.input_mem.len = 0;
7815 player->profile.input_mem.offset = 0;
7817 player->uri_info.uri_idx = 0;
7822 __mmplayer_check_subtitle(mmplayer_t *player)
7824 MMHandleType attrs = 0;
7825 char *subtitle_uri = NULL;
7829 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7831 /* get subtitle attribute */
7832 attrs = MMPLAYER_GET_ATTRS(player);
7836 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7837 if (!subtitle_uri || !strlen(subtitle_uri))
7840 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7841 player->is_external_subtitle_present = TRUE;
7849 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7851 MMPLAYER_RETURN_IF_FAIL(player);
7853 if (player->eos_timer) {
7854 LOGD("cancel eos timer");
7855 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7856 player->eos_timer = 0;
7863 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7867 MMPLAYER_RETURN_IF_FAIL(player);
7868 MMPLAYER_RETURN_IF_FAIL(sink);
7871 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7873 player->sink_elements = g_list_append(player->sink_elements, sink);
7879 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7883 MMPLAYER_RETURN_IF_FAIL(player);
7884 MMPLAYER_RETURN_IF_FAIL(sink);
7886 player->sink_elements = g_list_remove(player->sink_elements, sink);
7892 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7893 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7895 mmplayer_signal_item_t *item = NULL;
7898 MMPLAYER_RETURN_IF_FAIL(player);
7900 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7901 LOGE("invalid signal type [%d]", type);
7905 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7907 LOGE("cannot connect signal [%s]", signal);
7912 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7913 player->signals[type] = g_list_append(player->signals[type], item);
7919 /* NOTE : be careful with calling this api. please refer to below glib comment
7920 * glib comment : Note that there is a bug in GObject that makes this function much
7921 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7922 * will no longer be called, but, the signal handler is not currently disconnected.
7923 * If the instance is itself being freed at the same time than this doesn't matter,
7924 * since the signal will automatically be removed, but if instance persists,
7925 * then the signal handler will leak. You should not remove the signal yourself
7926 * because in a future versions of GObject, the handler will automatically be
7929 * It's possible to work around this problem in a way that will continue to work
7930 * with future versions of GObject by checking that the signal handler is still
7931 * connected before disconnected it:
7933 * if (g_signal_handler_is_connected(instance, id))
7934 * g_signal_handler_disconnect(instance, id);
7937 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7939 GList *sig_list = NULL;
7940 mmplayer_signal_item_t *item = NULL;
7944 MMPLAYER_RETURN_IF_FAIL(player);
7946 LOGD("release signals type : %d", type);
7948 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7949 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7950 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7951 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7952 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7953 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7957 sig_list = player->signals[type];
7959 for (; sig_list; sig_list = sig_list->next) {
7960 item = sig_list->data;
7962 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7963 if (g_signal_handler_is_connected(item->obj, item->sig))
7964 g_signal_handler_disconnect(item->obj, item->sig);
7967 MMPLAYER_FREEIF(item);
7970 g_list_free(player->signals[type]);
7971 player->signals[type] = NULL;
7979 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7981 mmplayer_t *player = 0;
7982 int prev_display_surface_type = 0;
7986 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7988 player = MM_PLAYER_CAST(handle);
7990 /* check video sinkbin is created */
7991 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7992 LOGW("Videosink is already created");
7993 return MM_ERROR_NONE;
7996 LOGD("videosink element is not yet ready");
7998 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
7999 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8001 return MM_ERROR_INVALID_ARGUMENT;
8004 /* load previous attributes */
8005 if (player->attrs) {
8006 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8007 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8008 if (prev_display_surface_type == surface_type) {
8009 LOGD("incoming display surface type is same as previous one, do nothing..");
8011 return MM_ERROR_NONE;
8014 LOGE("failed to load attributes");
8016 return MM_ERROR_PLAYER_INTERNAL;
8019 /* videobin is not created yet, so we just set attributes related to display surface */
8020 LOGD("store display attribute for given surface type(%d)", surface_type);
8021 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8022 "display_overlay", wl_surface_id, NULL);
8025 return MM_ERROR_NONE;
8028 /* Note : if silent is true, then subtitle would not be displayed. :*/
8030 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8032 mmplayer_t *player = (mmplayer_t *)hplayer;
8036 /* check player handle */
8037 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8039 player->set_mode.subtitle_off = silent;
8041 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8045 return MM_ERROR_NONE;
8049 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8051 mmplayer_gst_element_t *mainbin = NULL;
8052 mmplayer_gst_element_t *textbin = NULL;
8053 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8054 GstState current_state = GST_STATE_VOID_PENDING;
8055 GstState element_state = GST_STATE_VOID_PENDING;
8056 GstState element_pending_state = GST_STATE_VOID_PENDING;
8058 GstEvent *event = NULL;
8059 int result = MM_ERROR_NONE;
8061 GstClock *curr_clock = NULL;
8062 GstClockTime base_time, start_time, curr_time;
8067 /* check player handle */
8068 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8070 player->pipeline->mainbin &&
8071 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8073 mainbin = player->pipeline->mainbin;
8074 textbin = player->pipeline->textbin;
8076 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8078 // sync clock with current pipeline
8079 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8080 curr_time = gst_clock_get_time(curr_clock);
8082 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8083 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8085 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8086 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8088 if (current_state > GST_STATE_READY) {
8089 // sync state with current pipeline
8090 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8091 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8092 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8094 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8095 if (GST_STATE_CHANGE_FAILURE == ret) {
8096 LOGE("fail to state change.");
8097 result = MM_ERROR_PLAYER_INTERNAL;
8101 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8102 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8105 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8106 gst_object_unref(curr_clock);
8109 // seek to current position
8110 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8111 result = MM_ERROR_PLAYER_INVALID_STATE;
8112 LOGE("gst_element_query_position failed, invalid state");
8116 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8117 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);
8119 _mmplayer_gst_send_event_to_sink(player, event);
8121 result = MM_ERROR_PLAYER_INTERNAL;
8122 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8126 /* sync state with current pipeline */
8127 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8128 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8129 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8131 return MM_ERROR_NONE;
8134 /* release text pipeline resource */
8135 player->textsink_linked = 0;
8137 /* release signal */
8138 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8140 /* release textbin with it's children */
8141 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8142 MMPLAYER_FREEIF(player->pipeline->textbin);
8143 player->pipeline->textbin = NULL;
8145 /* release subtitle elem */
8146 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8147 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8153 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8155 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8156 GstState current_state = GST_STATE_VOID_PENDING;
8158 MMHandleType attrs = 0;
8159 mmplayer_gst_element_t *mainbin = NULL;
8160 mmplayer_gst_element_t *textbin = NULL;
8162 gchar *subtitle_uri = NULL;
8163 int result = MM_ERROR_NONE;
8164 const gchar *charset = NULL;
8168 /* check player handle */
8169 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8171 player->pipeline->mainbin &&
8172 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8173 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8175 mainbin = player->pipeline->mainbin;
8176 textbin = player->pipeline->textbin;
8178 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8179 if (current_state < GST_STATE_READY) {
8180 result = MM_ERROR_PLAYER_INVALID_STATE;
8181 LOGE("Pipeline is not in proper state");
8185 attrs = MMPLAYER_GET_ATTRS(player);
8187 LOGE("cannot get content attribute");
8188 result = MM_ERROR_PLAYER_INTERNAL;
8192 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8193 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8194 LOGE("subtitle uri is not proper filepath");
8195 result = MM_ERROR_PLAYER_INVALID_URI;
8199 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8200 LOGE("failed to get storage info of subtitle path");
8201 result = MM_ERROR_PLAYER_INVALID_URI;
8205 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8206 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8208 if (!strcmp(filepath, subtitle_uri)) {
8209 LOGD("subtitle path is not changed");
8212 if (mm_player_set_attribute((MMHandleType)player, NULL,
8213 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8214 LOGE("failed to set attribute");
8219 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8220 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8221 player->subtitle_language_list = NULL;
8222 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8224 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8225 if (ret != GST_STATE_CHANGE_SUCCESS) {
8226 LOGE("failed to change state of textbin to READY");
8227 result = MM_ERROR_PLAYER_INTERNAL;
8231 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8232 if (ret != GST_STATE_CHANGE_SUCCESS) {
8233 LOGE("failed to change state of subparse to READY");
8234 result = MM_ERROR_PLAYER_INTERNAL;
8238 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8239 if (ret != GST_STATE_CHANGE_SUCCESS) {
8240 LOGE("failed to change state of filesrc to READY");
8241 result = MM_ERROR_PLAYER_INTERNAL;
8245 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8247 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8249 charset = _mmplayer_get_charset(filepath);
8251 LOGD("detected charset is %s", charset);
8252 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8255 result = _mmplayer_sync_subtitle_pipeline(player);
8262 /* API to switch between external subtitles */
8264 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8266 int result = MM_ERROR_NONE;
8267 mmplayer_t *player = (mmplayer_t *)hplayer;
8272 /* check player handle */
8273 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8275 /* filepath can be null in idle state */
8277 /* check file path */
8278 if ((path = strstr(filepath, "file://")))
8279 result = _mmplayer_exist_file_path(path + 7);
8281 result = _mmplayer_exist_file_path(filepath);
8283 if (result != MM_ERROR_NONE) {
8284 LOGE("invalid subtitle path 0x%X", result);
8285 return result; /* file not found or permission denied */
8289 if (!player->pipeline) {
8291 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8292 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8293 LOGE("failed to set attribute");
8294 return MM_ERROR_PLAYER_INTERNAL;
8297 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8298 /* check filepath */
8299 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8301 if (!__mmplayer_check_subtitle(player)) {
8302 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8303 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8304 LOGE("failed to set attribute");
8305 return MM_ERROR_PLAYER_INTERNAL;
8308 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8309 LOGE("fail to create text pipeline");
8310 return MM_ERROR_PLAYER_INTERNAL;
8313 result = _mmplayer_sync_subtitle_pipeline(player);
8315 result = __mmplayer_change_external_subtitle_language(player, filepath);
8318 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8319 player->is_external_subtitle_added_now = TRUE;
8321 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8322 if (!player->subtitle_language_list) {
8323 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8324 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8325 LOGW("subtitle language list is not updated yet");
8327 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8335 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8337 guint active_idx = 0;
8338 GstStream *stream = NULL;
8339 GList *streams = NULL;
8340 GstEvent *ev = NULL;
8341 GstCaps *caps = NULL;
8343 LOGD("Switching Streams... type: %d, index: %d", type, index);
8345 player->track[type].active_track_index = index;
8347 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8348 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8349 if (player->track[i].total_track_num > 0) {
8350 active_idx = player->track[i].active_track_index;
8351 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8352 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8353 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8355 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8356 caps = gst_stream_get_caps(stream);
8358 _mmplayer_set_audio_attrs(player, caps);
8359 gst_caps_unref(caps);
8365 ev = gst_event_new_select_streams(streams);
8366 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8367 g_list_free(streams);
8369 return MM_ERROR_NONE;
8373 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8375 int result = MM_ERROR_NONE;
8376 gchar *change_pad_name = NULL;
8377 GstPad *sinkpad = NULL;
8378 mmplayer_gst_element_t *mainbin = NULL;
8379 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8380 GstCaps *caps = NULL;
8381 gint total_track_num = 0;
8385 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8386 MM_ERROR_PLAYER_NOT_INITIALIZED);
8388 LOGD("Change Track(%d) to %d", type, index);
8390 mainbin = player->pipeline->mainbin;
8392 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8393 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8394 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8395 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8397 /* Changing Video Track is not supported. */
8398 LOGE("Track Type Error");
8402 if (mainbin[elem_idx].gst == NULL) {
8403 result = MM_ERROR_PLAYER_NO_OP;
8404 LOGD("Req track doesn't exist");
8408 total_track_num = player->track[type].total_track_num;
8409 if (total_track_num <= 0) {
8410 result = MM_ERROR_PLAYER_NO_OP;
8411 LOGD("Language list is not available");
8415 if ((index < 0) || (index >= total_track_num)) {
8416 result = MM_ERROR_INVALID_ARGUMENT;
8417 LOGD("Not a proper index : %d", index);
8421 /*To get the new pad from the selector*/
8422 change_pad_name = g_strdup_printf("sink_%u", index);
8423 if (change_pad_name == NULL) {
8424 result = MM_ERROR_PLAYER_INTERNAL;
8425 LOGD("Pad does not exists");
8429 LOGD("new active pad name: %s", change_pad_name);
8431 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8432 if (sinkpad == NULL) {
8433 LOGD("sinkpad is NULL");
8434 result = MM_ERROR_PLAYER_INTERNAL;
8438 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8439 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8441 caps = gst_pad_get_current_caps(sinkpad);
8442 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8445 gst_object_unref(sinkpad);
8447 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8448 _mmplayer_set_audio_attrs(player, caps);
8451 gst_caps_unref(caps);
8454 MMPLAYER_FREEIF(change_pad_name);
8459 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8461 int result = MM_ERROR_NONE;
8462 mmplayer_t *player = NULL;
8463 mmplayer_gst_element_t *mainbin = NULL;
8465 gint current_active_index = 0;
8467 GstState current_state = GST_STATE_VOID_PENDING;
8472 player = (mmplayer_t *)hplayer;
8473 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8475 if (!player->pipeline) {
8476 LOGE("Track %d pre setting -> %d", type, index);
8478 player->track[type].active_track_index = index;
8482 mainbin = player->pipeline->mainbin;
8484 current_active_index = player->track[type].active_track_index;
8486 /*If index is same as running index no need to change the pad*/
8487 if (current_active_index == index)
8490 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8491 result = MM_ERROR_PLAYER_INVALID_STATE;
8495 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8496 if (current_state < GST_STATE_PAUSED) {
8497 result = MM_ERROR_PLAYER_INVALID_STATE;
8498 LOGW("Pipeline not in proper state");
8502 if (MMPLAYER_USE_DECODEBIN(player))
8503 result = __mmplayer_change_selector_pad(player, type, index);
8505 result = __mmplayer_switch_stream(player, type, index);
8507 if (result != MM_ERROR_NONE) {
8508 LOGE("failed to change track");
8512 player->track[type].active_track_index = index;
8514 if (MMPLAYER_USE_DECODEBIN(player)) {
8515 GstEvent *event = NULL;
8516 if (current_state == GST_STATE_PLAYING) {
8517 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8518 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8519 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8521 _mmplayer_gst_send_event_to_sink(player, event);
8523 result = MM_ERROR_PLAYER_INTERNAL;
8534 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8536 mmplayer_t *player = (mmplayer_t *)hplayer;
8540 /* check player handle */
8541 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8543 *silent = player->set_mode.subtitle_off;
8545 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8549 return MM_ERROR_NONE;
8553 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8555 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8556 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8558 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8559 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8563 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8564 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8565 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8566 mmplayer_dump_t *dump_s;
8567 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8568 if (dump_s == NULL) {
8569 LOGE("malloc fail");
8573 dump_s->dump_element_file = NULL;
8574 dump_s->dump_pad = NULL;
8575 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8577 if (dump_s->dump_pad) {
8578 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8579 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]);
8580 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8581 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);
8582 /* add list for removed buffer probe and close FILE */
8583 player->dump_list = g_list_append(player->dump_list, dump_s);
8584 LOGD("%s sink pad added buffer probe for dump", factory_name);
8587 MMPLAYER_FREEIF(dump_s);
8588 LOGE("failed to get %s sink pad added", factory_name);
8595 static GstPadProbeReturn
8596 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8598 FILE *dump_data = (FILE *)u_data;
8600 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8601 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8603 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8605 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8607 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8609 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8611 gst_buffer_unmap(buffer, &probe_info);
8613 return GST_PAD_PROBE_OK;
8617 __mmplayer_release_dump_list(GList *dump_list)
8619 GList *d_list = dump_list;
8624 for (; d_list; d_list = g_list_next(d_list)) {
8625 mmplayer_dump_t *dump_s = d_list->data;
8626 if (dump_s->dump_pad) {
8627 if (dump_s->probe_handle_id)
8628 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8629 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8631 if (dump_s->dump_element_file) {
8632 fclose(dump_s->dump_element_file);
8633 dump_s->dump_element_file = NULL;
8635 MMPLAYER_FREEIF(dump_s);
8637 g_list_free(dump_list);
8642 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8644 mmplayer_t *player = (mmplayer_t *)hplayer;
8648 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8649 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8651 *exist = (bool)player->has_closed_caption;
8655 return MM_ERROR_NONE;
8659 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8664 LOGD("unref internal gst buffer %p", buffer);
8666 gst_buffer_unref((GstBuffer *)buffer);
8673 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8675 mmplayer_t *player = (mmplayer_t *)hplayer;
8679 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8680 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8682 if (MMPLAYER_IS_STREAMING(player))
8683 *timeout = (int)player->ini.live_state_change_timeout;
8685 *timeout = (int)player->ini.localplayback_state_change_timeout;
8687 LOGD("timeout = %d", *timeout);
8690 return MM_ERROR_NONE;
8694 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8698 MMPLAYER_RETURN_IF_FAIL(player);
8700 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8702 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8703 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8704 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8705 player->storage_info[i].id = -1;
8706 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8708 if (path_type != MMPLAYER_PATH_MAX)
8717 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8719 int ret = MM_ERROR_NONE;
8720 mmplayer_t *player = (mmplayer_t *)hplayer;
8721 MMMessageParamType msg_param = {0, };
8724 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8726 LOGW("state changed storage %d:%d", id, state);
8728 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8729 return MM_ERROR_NONE;
8731 /* FIXME: text path should be handled separately. */
8732 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8733 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8734 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8735 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8736 LOGW("external storage is removed");
8738 if (player->msg_posted == FALSE) {
8739 memset(&msg_param, 0, sizeof(MMMessageParamType));
8740 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8741 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8742 player->msg_posted = TRUE;
8745 /* unrealize the player */
8746 ret = _mmplayer_unrealize(hplayer);
8747 if (ret != MM_ERROR_NONE)
8748 LOGE("failed to unrealize");
8756 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8758 int ret = MM_ERROR_NONE;
8759 mmplayer_t *player = (mmplayer_t *)hplayer;
8760 int idx = 0, total = 0;
8761 gchar *result = NULL, *tmp = NULL;
8764 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8765 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8767 total = *num = g_list_length(player->adaptive_info.var_list);
8769 LOGW("There is no stream variant info.");
8773 result = g_strdup("");
8774 for (idx = 0 ; idx < total ; idx++) {
8775 stream_variant_t *v_data = NULL;
8776 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8779 gchar data[64] = {0};
8780 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8782 tmp = g_strconcat(result, data, NULL);
8786 LOGW("There is no variant data in %d", idx);
8791 *var_info = (char *)result;
8793 LOGD("variant info %d:%s", *num, *var_info);
8799 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8801 int ret = MM_ERROR_NONE;
8802 mmplayer_t *player = (mmplayer_t *)hplayer;
8805 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8807 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8809 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8810 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8811 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8813 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8814 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8815 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8816 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8818 /* FIXME: seek to current position for applying new variant limitation */
8827 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8829 int ret = MM_ERROR_NONE;
8830 mmplayer_t *player = (mmplayer_t *)hplayer;
8833 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8834 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8836 *bandwidth = player->adaptive_info.limit.bandwidth;
8837 *width = player->adaptive_info.limit.width;
8838 *height = player->adaptive_info.limit.height;
8840 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8847 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8849 int ret = MM_ERROR_NONE;
8850 mmplayer_t *player = (mmplayer_t *)hplayer;
8853 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8854 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8855 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8857 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8859 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8860 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8861 else /* live case */
8862 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8864 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8871 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8873 #define IDX_FIRST_SW_CODEC 0
8874 mmplayer_t *player = (mmplayer_t *)hplayer;
8875 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8876 const char *attr_name = NULL;
8877 const char *default_type = NULL;
8878 const char *element_hw = NULL;
8879 const char *element_sw = NULL;
8882 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8884 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8886 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8887 switch (stream_type) {
8888 case MM_PLAYER_STREAM_TYPE_AUDIO:
8889 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8890 default_type = player->ini.audiocodec_default_type;
8891 element_hw = player->ini.audiocodec_element_hw;
8892 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8894 case MM_PLAYER_STREAM_TYPE_VIDEO:
8895 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8896 default_type = player->ini.videocodec_default_type;
8897 element_hw = player->ini.videocodec_element_hw;
8898 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8901 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8902 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8906 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8908 if (!strcmp(default_type, "sw"))
8909 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8911 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8913 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8914 codec_type = default_codec_type;
8916 /* to support codec selection, codec info have to be added in ini file.
8917 in case of hw codec is selected, filter elements should be applied
8918 depending on the hw capabilities. */
8919 if (codec_type != default_codec_type) {
8920 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
8921 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
8922 LOGE("There is no codec for type %d", codec_type);
8923 return MM_ERROR_PLAYER_NO_OP;
8926 LOGD("sorting is required");
8927 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
8928 player->need_audio_dec_sorting = TRUE;
8930 player->need_video_dec_sorting = TRUE;
8933 LOGD("update %s codec_type to %d", attr_name, codec_type);
8934 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8937 return MM_ERROR_NONE;
8941 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8943 mmplayer_t *player = (mmplayer_t *)hplayer;
8944 GstElement *rg_vol_element = NULL;
8948 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8950 player->sound.rg_enable = enabled;
8952 /* just hold rgvolume enable value if pipeline is not ready */
8953 if (!player->pipeline || !player->pipeline->audiobin) {
8954 LOGD("pipeline is not ready. holding rgvolume enable value");
8955 return MM_ERROR_NONE;
8958 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8960 if (!rg_vol_element) {
8961 LOGD("rgvolume element is not created");
8962 return MM_ERROR_PLAYER_INTERNAL;
8966 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8968 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8972 return MM_ERROR_NONE;
8976 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8978 mmplayer_t *player = (mmplayer_t *)hplayer;
8979 GstElement *rg_vol_element = NULL;
8980 gboolean enable = FALSE;
8984 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8985 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8987 /* just hold enable_rg value if pipeline is not ready */
8988 if (!player->pipeline || !player->pipeline->audiobin) {
8989 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8990 *enabled = player->sound.rg_enable;
8991 return MM_ERROR_NONE;
8994 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8996 if (!rg_vol_element) {
8997 LOGD("rgvolume element is not created");
8998 return MM_ERROR_PLAYER_INTERNAL;
9001 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9002 *enabled = (bool)enable;
9006 return MM_ERROR_NONE;
9010 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9012 mmplayer_t *player = (mmplayer_t *)hplayer;
9013 MMHandleType attrs = 0;
9015 int ret = MM_ERROR_NONE;
9019 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9021 attrs = MMPLAYER_GET_ATTRS(player);
9022 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9024 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9026 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9027 return MM_ERROR_PLAYER_INTERNAL;
9030 player->video_roi.scale_x = scale_x;
9031 player->video_roi.scale_y = scale_y;
9032 player->video_roi.scale_width = scale_width;
9033 player->video_roi.scale_height = scale_height;
9035 /* check video sinkbin is created */
9036 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9037 return MM_ERROR_NONE;
9039 if (!gst_video_overlay_set_video_roi_area(
9040 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9041 scale_x, scale_y, scale_width, scale_height))
9042 ret = MM_ERROR_PLAYER_INTERNAL;
9044 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9045 scale_x, scale_y, scale_width, scale_height);
9053 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9055 mmplayer_t *player = (mmplayer_t *)hplayer;
9056 int ret = MM_ERROR_NONE;
9060 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9061 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9063 *scale_x = player->video_roi.scale_x;
9064 *scale_y = player->video_roi.scale_y;
9065 *scale_width = player->video_roi.scale_width;
9066 *scale_height = player->video_roi.scale_height;
9068 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9069 *scale_x, *scale_y, *scale_width, *scale_height);
9075 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9077 mmplayer_t *player = (mmplayer_t *)hplayer;
9081 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9083 player->client_pid = pid;
9085 LOGD("client pid[%d] %p", pid, player);
9089 return MM_ERROR_NONE;
9093 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9095 mmplayer_t *player = (mmplayer_t *)hplayer;
9096 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9097 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9101 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9102 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9105 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9107 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9109 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9110 return MM_ERROR_NONE;
9112 /* in case of audio codec default type is HW */
9114 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9115 if (player->ini.support_audio_effect)
9116 return MM_ERROR_NONE;
9117 elem_id = MMPLAYER_A_FILTER;
9119 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9120 if (player->ini.support_replaygain_control)
9121 return MM_ERROR_NONE;
9122 elem_id = MMPLAYER_A_RGVOL;
9124 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9125 if (player->ini.support_pitch_control)
9126 return MM_ERROR_NONE;
9127 elem_id = MMPLAYER_A_PITCH;
9129 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9130 if (player->ini.support_audio_effect)
9131 return MM_ERROR_NONE;
9133 /* default case handling is not required */
9136 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9137 LOGW("audio control option [%d] is not available", opt);
9140 /* setting pcm exporting option is allowed before READY state */
9141 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9142 return MM_ERROR_PLAYER_INVALID_STATE;
9144 /* check whether the audio filter exist or not after READY state,
9145 because the sw codec could be added during auto-plugging in some cases */
9146 if (!player->pipeline ||
9147 !player->pipeline->audiobin ||
9148 !player->pipeline->audiobin[elem_id].gst) {
9149 LOGW("there is no audio elem [%d]", elem_id);
9154 LOGD("audio control opt %d, available %d", opt, *available);
9158 return MM_ERROR_NONE;
9162 __mmplayer_update_duration_value(mmplayer_t *player)
9164 gboolean ret = FALSE;
9165 gint64 dur_nsec = 0;
9166 LOGD("try to update duration");
9168 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9169 player->duration = dur_nsec;
9170 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9174 if (player->duration < 0) {
9175 LOGW("duration is Non-Initialized !!!");
9176 player->duration = 0;
9179 /* update streaming service type */
9180 player->streaming_type = _mmplayer_get_stream_service_type(player);
9182 /* check duration is OK */
9183 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9184 /* FIXIT : find another way to get duration here. */
9185 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9191 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9193 /* update audio params
9194 NOTE : We need original audio params and it can be only obtained from src pad of audio
9195 decoder. Below code only valid when we are not using 'resampler' just before
9196 'audioconverter'. */
9197 GstCaps *caps_a = NULL;
9199 gint samplerate = 0, channels = 0;
9200 GstStructure *p = NULL;
9201 GstElement *aconv = NULL;
9203 LOGD("try to update audio attrs");
9205 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9207 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9208 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9209 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9210 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9212 LOGE("there is no audio converter");
9216 pad = gst_element_get_static_pad(aconv, "sink");
9219 LOGW("failed to get pad from audio converter");
9223 caps_a = gst_pad_get_current_caps(pad);
9225 LOGW("not ready to get audio caps");
9226 gst_object_unref(pad);
9230 p = gst_caps_get_structure(caps_a, 0);
9232 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9234 gst_structure_get_int(p, "rate", &samplerate);
9235 gst_structure_get_int(p, "channels", &channels);
9237 mm_player_set_attribute((MMHandleType)player, NULL,
9238 "content_audio_samplerate", samplerate,
9239 "content_audio_channels", channels, NULL);
9241 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9243 gst_caps_unref(caps_a);
9244 gst_object_unref(pad);
9250 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9252 LOGD("try to update video attrs");
9254 GstCaps *caps_v = NULL;
9258 GstStructure *p = NULL;
9260 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9261 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9263 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9265 LOGD("no videosink sink pad");
9269 caps_v = gst_pad_get_current_caps(pad);
9270 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9271 if (!caps_v && player->v_stream_caps) {
9272 caps_v = player->v_stream_caps;
9273 gst_caps_ref(caps_v);
9277 LOGD("no negotiated caps from videosink");
9278 gst_object_unref(pad);
9282 p = gst_caps_get_structure(caps_v, 0);
9283 gst_structure_get_int(p, "width", &width);
9284 gst_structure_get_int(p, "height", &height);
9286 mm_player_set_attribute((MMHandleType)player, NULL,
9287 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9289 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9291 SECURE_LOGD("width : %d height : %d", width, height);
9293 gst_caps_unref(caps_v);
9294 gst_object_unref(pad);
9297 mm_player_set_attribute((MMHandleType)player, NULL,
9298 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9299 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9306 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9308 gboolean ret = FALSE;
9309 guint64 data_size = 0;
9313 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9314 if (!player->duration)
9317 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9318 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9319 if (stat(path, &sb) == 0)
9320 data_size = (guint64)sb.st_size;
9322 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9323 data_size = player->http_content_size;
9326 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9329 guint64 bitrate = 0;
9330 guint64 msec_dur = 0;
9332 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9334 bitrate = data_size * 8 * 1000 / msec_dur;
9335 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9336 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9337 mm_player_set_attribute((MMHandleType)player, NULL,
9338 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9341 LOGD("player duration is less than 0");
9345 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9346 if (player->total_bitrate) {
9347 mm_player_set_attribute((MMHandleType)player, NULL,
9348 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9357 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9359 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9360 data->uri_type = uri_type;
9364 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9366 int ret = MM_ERROR_PLAYER_INVALID_URI;
9368 char *buffer = NULL;
9369 char *seperator = strchr(path, ',');
9370 char ext[100] = {0,}, size[100] = {0,};
9373 if ((buffer = strstr(path, "ext="))) {
9374 buffer += strlen("ext=");
9376 if (strlen(buffer)) {
9377 strncpy(ext, buffer, 99);
9379 if ((seperator = strchr(ext, ','))
9380 || (seperator = strchr(ext, ' '))
9381 || (seperator = strchr(ext, '\0'))) {
9382 seperator[0] = '\0';
9387 if ((buffer = strstr(path, "size="))) {
9388 buffer += strlen("size=");
9390 if (strlen(buffer) > 0) {
9391 strncpy(size, buffer, 99);
9393 if ((seperator = strchr(size, ','))
9394 || (seperator = strchr(size, ' '))
9395 || (seperator = strchr(size, '\0'))) {
9396 seperator[0] = '\0';
9399 mem_size = atoi(size);
9404 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9406 if (mem_size && param) {
9407 if (data->input_mem.buf)
9408 free(data->input_mem.buf);
9409 data->input_mem.buf = malloc(mem_size);
9411 if (data->input_mem.buf) {
9412 memcpy(data->input_mem.buf, param, mem_size);
9413 data->input_mem.len = mem_size;
9414 ret = MM_ERROR_NONE;
9416 LOGE("failed to alloc mem %d", mem_size);
9417 ret = MM_ERROR_PLAYER_INTERNAL;
9420 data->input_mem.offset = 0;
9421 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9428 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9430 gchar *location = NULL;
9433 int ret = MM_ERROR_NONE;
9435 if ((path = strstr(uri, "file://"))) {
9436 location = g_filename_from_uri(uri, NULL, &err);
9437 if (!location || (err != NULL)) {
9438 LOGE("Invalid URI '%s' for filesrc: %s", path,
9439 (err != NULL) ? err->message : "unknown error");
9443 MMPLAYER_FREEIF(location);
9445 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9446 return MM_ERROR_PLAYER_INVALID_URI;
9448 LOGD("path from uri: %s", location);
9451 path = (location != NULL) ? (location) : ((char *)uri);
9454 ret = _mmplayer_exist_file_path(path);
9456 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9457 if (ret == MM_ERROR_NONE) {
9458 if (_mmplayer_is_sdp_file(path)) {
9459 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9460 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9461 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9463 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9464 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9466 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9467 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9469 LOGE("invalid uri, could not play..");
9470 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9473 MMPLAYER_FREEIF(location);
9478 static mmplayer_video_decoded_data_info_t *
9479 __mmplayer_create_stream_from_pad(GstPad *pad)
9481 GstCaps *caps = NULL;
9482 GstStructure *structure = NULL;
9483 unsigned int fourcc = 0;
9484 const gchar *string_format = NULL;
9485 mmplayer_video_decoded_data_info_t *stream = NULL;
9487 MMPixelFormatType format;
9490 caps = gst_pad_get_current_caps(pad);
9492 LOGE("Caps is NULL.");
9497 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9499 structure = gst_caps_get_structure(caps, 0);
9500 gst_structure_get_int(structure, "width", &width);
9501 gst_structure_get_int(structure, "height", &height);
9502 string_format = gst_structure_get_string(structure, "format");
9505 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9506 format = _mmplayer_get_pixtype(fourcc);
9507 gst_video_info_from_caps(&info, caps);
9508 gst_caps_unref(caps);
9511 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9512 LOGE("Wrong condition!!");
9516 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9518 LOGE("failed to alloc mem for video data");
9522 stream->width = width;
9523 stream->height = height;
9524 stream->format = format;
9525 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9531 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9533 unsigned int pitch = 0;
9534 unsigned int size = 0;
9536 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9539 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9540 bo = gst_tizen_memory_get_bos(mem, index);
9542 stream->bo[index] = tbm_bo_ref(bo);
9544 LOGE("failed to get bo for index %d", index);
9547 for (index = 0; index < stream->plane_num; index++) {
9548 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9549 stream->stride[index] = pitch;
9551 stream->elevation[index] = size / pitch;
9553 stream->elevation[index] = stream->height;
9558 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9560 if (stream->format == MM_PIXEL_FORMAT_I420) {
9561 int ret = TBM_SURFACE_ERROR_NONE;
9562 tbm_surface_h surface;
9563 tbm_surface_info_s info;
9565 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9567 ret = tbm_surface_get_info(surface, &info);
9568 if (ret != TBM_SURFACE_ERROR_NONE) {
9569 tbm_surface_destroy(surface);
9573 tbm_surface_destroy(surface);
9574 stream->stride[0] = info.planes[0].stride;
9575 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9576 stream->stride[1] = info.planes[1].stride;
9577 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9578 stream->stride[2] = info.planes[2].stride;
9579 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9580 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9581 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9582 stream->stride[0] = stream->width * 4;
9583 stream->elevation[0] = stream->height;
9584 stream->bo_size = stream->stride[0] * stream->height;
9586 LOGE("Not support format %d", stream->format);
9594 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9596 tbm_bo_handle thandle;
9598 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9599 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9600 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9604 unsigned char *src = NULL;
9605 unsigned char *dest = NULL;
9606 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9608 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9610 LOGE("fail to gst_memory_map");
9614 if (!mapinfo.data) {
9615 LOGE("data pointer is wrong");
9619 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9620 if (!stream->bo[0]) {
9621 LOGE("Fail to tbm_bo_alloc!!");
9625 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9627 LOGE("thandle pointer is wrong");
9631 if (stream->format == MM_PIXEL_FORMAT_I420) {
9632 src_stride[0] = GST_ROUND_UP_4(stream->width);
9633 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9634 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9635 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9638 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9639 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9641 for (i = 0; i < 3; i++) {
9642 src = mapinfo.data + src_offset[i];
9643 dest = thandle.ptr + dest_offset[i];
9648 for (j = 0; j < stream->height >> k; j++) {
9649 memcpy(dest, src, stream->width>>k);
9650 src += src_stride[i];
9651 dest += stream->stride[i];
9654 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9655 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9657 LOGE("Not support format %d", stream->format);
9661 tbm_bo_unmap(stream->bo[0]);
9662 gst_memory_unmap(mem, &mapinfo);
9668 tbm_bo_unmap(stream->bo[0]);
9671 gst_memory_unmap(mem, &mapinfo);
9677 __mmplayer_set_pause_state(mmplayer_t *player)
9679 if (player->sent_bos)
9682 /* rtsp case, get content attrs by GstMessage */
9683 if (MMPLAYER_IS_RTSP_STREAMING(player))
9686 /* it's first time to update all content attrs. */
9687 _mmplayer_update_content_attrs(player, ATTR_ALL);
9691 __mmplayer_set_playing_state(mmplayer_t *player)
9693 gchar *audio_codec = NULL;
9695 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9696 /* initialize because auto resume is done well. */
9697 player->resumed_by_rewind = FALSE;
9698 player->playback_rate = 1.0;
9701 if (player->sent_bos)
9704 /* try to get content metadata */
9706 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9707 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9708 * legacy mmfw-player api
9710 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9712 if ((player->cmd == MMPLAYER_COMMAND_START)
9713 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9714 __mmplayer_handle_missed_plugin(player);
9717 /* check audio codec field is set or not
9718 * we can get it from typefinder or codec's caps.
9720 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9722 /* The codec format can't be sent for audio only case like amr, mid etc.
9723 * Because, parser don't make related TAG.
9724 * So, if it's not set yet, fill it with found data.
9727 if (g_strrstr(player->type, "audio/midi"))
9728 audio_codec = "MIDI";
9729 else if (g_strrstr(player->type, "audio/x-amr"))
9730 audio_codec = "AMR";
9731 else if (g_strrstr(player->type, "audio/mpeg")
9732 && !g_strrstr(player->type, "mpegversion=(int)1"))
9733 audio_codec = "AAC";
9735 audio_codec = "unknown";
9737 if (mm_player_set_attribute((MMHandleType)player, NULL,
9738 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9739 LOGE("failed to set attribute");
9741 LOGD("set audio codec type with caps");