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 static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
200 /*===========================================================================================
202 | FUNCTION DEFINITIONS |
204 ========================================================================================== */
206 /* This function should be called after the pipeline goes PAUSED or higher
209 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
211 static gboolean has_duration = FALSE;
212 static gboolean has_video_attrs = FALSE;
213 static gboolean has_audio_attrs = FALSE;
214 static gboolean has_bitrate = FALSE;
215 gboolean missing_only = FALSE;
216 gboolean all = FALSE;
217 MMHandleType attrs = 0;
221 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
223 /* check player state here */
224 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
225 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
226 /* give warning now only */
227 LOGW("be careful. content attributes may not available in this state ");
230 /* get content attribute first */
231 attrs = MMPLAYER_GET_ATTRS(player);
233 LOGE("cannot get content attribute");
237 /* get update flag */
239 if (flag & ATTR_MISSING_ONLY) {
241 LOGD("updating missed attr only");
244 if (flag & ATTR_ALL) {
246 has_duration = FALSE;
247 has_video_attrs = FALSE;
248 has_audio_attrs = FALSE;
251 LOGD("updating all attrs");
254 if (missing_only && all) {
255 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
256 missing_only = FALSE;
259 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
260 has_duration = __mmplayer_update_duration_value(player);
262 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
263 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
265 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
266 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
268 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
269 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
277 _mmplayer_get_stream_service_type(mmplayer_t *player)
279 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
283 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
285 player->pipeline->mainbin &&
286 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
287 STREAMING_SERVICE_NONE);
289 /* streaming service type if streaming */
290 if (!MMPLAYER_IS_STREAMING(player))
291 return STREAMING_SERVICE_NONE;
293 streaming_type = (player->duration == 0) ?
294 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
296 switch (streaming_type) {
297 case STREAMING_SERVICE_LIVE:
298 LOGD("it's live streaming");
300 case STREAMING_SERVICE_VOD:
301 LOGD("it's vod streaming");
304 LOGE("should not get here");
310 return streaming_type;
313 /* this function sets the player state and also report
314 * it to application by calling callback function
317 _mmplayer_set_state(mmplayer_t *player, int state)
319 MMMessageParamType msg = {0, };
321 MMPLAYER_RETURN_IF_FAIL(player);
323 if (MMPLAYER_CURRENT_STATE(player) == state) {
324 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
325 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
329 /* update player states */
330 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
331 MMPLAYER_CURRENT_STATE(player) = state;
333 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
334 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
337 MMPLAYER_PRINT_STATE(player);
339 switch (MMPLAYER_CURRENT_STATE(player)) {
340 case MM_PLAYER_STATE_NULL:
341 case MM_PLAYER_STATE_READY:
343 case MM_PLAYER_STATE_PAUSED:
344 __mmplayer_set_pause_state(player);
346 case MM_PLAYER_STATE_PLAYING:
347 __mmplayer_set_playing_state(player);
349 case MM_PLAYER_STATE_NONE:
351 LOGW("invalid target state, there is nothing to do.");
356 /* post message to application */
357 if (MMPLAYER_TARGET_STATE(player) == state) {
358 /* fill the message with state of player */
359 msg.union_type = MM_MSG_UNION_STATE;
360 msg.state.previous = MMPLAYER_PREV_STATE(player);
361 msg.state.current = MMPLAYER_CURRENT_STATE(player);
363 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
365 /* state changed by resource callback */
366 if (player->interrupted_by_resource)
367 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
368 else /* state changed by usecase */
369 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
372 LOGD("intermediate state, do nothing.");
373 MMPLAYER_PRINT_STATE(player);
377 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
378 && !player->sent_bos) {
379 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
380 player->sent_bos = TRUE;
387 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
389 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
390 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
394 LOGD("incoming command : %d ", command);
396 current_state = MMPLAYER_CURRENT_STATE(player);
397 pending_state = MMPLAYER_PENDING_STATE(player);
399 MMPLAYER_PRINT_STATE(player);
402 case MMPLAYER_COMMAND_CREATE:
404 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
406 if (current_state == MM_PLAYER_STATE_NULL ||
407 current_state == MM_PLAYER_STATE_READY ||
408 current_state == MM_PLAYER_STATE_PAUSED ||
409 current_state == MM_PLAYER_STATE_PLAYING)
414 case MMPLAYER_COMMAND_DESTROY:
416 /* destroy can called anytime */
418 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
422 case MMPLAYER_COMMAND_REALIZE:
424 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
426 if (pending_state != MM_PLAYER_STATE_NONE) {
429 /* need ready state to realize */
430 if (current_state == MM_PLAYER_STATE_READY)
433 if (current_state != MM_PLAYER_STATE_NULL)
439 case MMPLAYER_COMMAND_UNREALIZE:
441 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
443 if (current_state == MM_PLAYER_STATE_NULL)
448 case MMPLAYER_COMMAND_START:
450 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
452 if (pending_state == MM_PLAYER_STATE_NONE) {
453 if (current_state == MM_PLAYER_STATE_PLAYING)
455 else if (current_state != MM_PLAYER_STATE_READY &&
456 current_state != MM_PLAYER_STATE_PAUSED)
458 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
460 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
461 LOGD("player is going to paused state, just change the pending state as playing");
468 case MMPLAYER_COMMAND_STOP:
470 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
472 if (current_state == MM_PLAYER_STATE_READY)
475 /* need playing/paused state to stop */
476 if (current_state != MM_PLAYER_STATE_PLAYING &&
477 current_state != MM_PLAYER_STATE_PAUSED)
482 case MMPLAYER_COMMAND_PAUSE:
484 if (MMPLAYER_IS_LIVE_STREAMING(player))
487 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
488 goto NOT_COMPLETED_SEEK;
490 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
492 if (pending_state == MM_PLAYER_STATE_NONE) {
493 if (current_state == MM_PLAYER_STATE_PAUSED)
495 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
497 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
499 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
500 if (current_state == MM_PLAYER_STATE_PAUSED)
501 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
508 case MMPLAYER_COMMAND_RESUME:
510 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
511 goto NOT_COMPLETED_SEEK;
513 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
515 if (pending_state == MM_PLAYER_STATE_NONE) {
516 if (current_state == MM_PLAYER_STATE_PLAYING)
518 else if (current_state != MM_PLAYER_STATE_PAUSED)
520 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
522 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
523 LOGD("player is going to paused state, just change the pending state as playing");
533 player->cmd = command;
535 return MM_ERROR_NONE;
538 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
539 MMPLAYER_STATE_GET_NAME(current_state), command);
540 return MM_ERROR_PLAYER_INVALID_STATE;
543 LOGW("not completed seek");
544 return MM_ERROR_PLAYER_DOING_SEEK;
547 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
548 return MM_ERROR_PLAYER_NO_OP;
551 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
552 return MM_ERROR_PLAYER_NO_OP;
555 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
557 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
558 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
561 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
562 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
564 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
565 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
567 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
568 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
571 LOGE("invalid mmplayer resource type %d", type);
572 return MM_ERROR_PLAYER_INTERNAL;
575 if (player->hw_resource[type] != NULL) {
576 LOGD("[%d type] resource was already acquired", type);
577 return MM_ERROR_NONE;
580 LOGD("mark for acquire [%d type] resource", type);
581 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
582 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
583 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
584 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
585 return MM_ERROR_PLAYER_INTERNAL;
588 LOGD("commit [%d type] resource", type);
589 rm_ret = mm_resource_manager_commit(player->resource_manager);
590 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
591 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
592 return MM_ERROR_PLAYER_INTERNAL;
596 return MM_ERROR_NONE;
599 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
601 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
603 MMPLAYER_RETURN_IF_FAIL(player);
604 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
606 rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
607 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
608 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
612 rm_ret = mm_resource_manager_commit(player->resource_manager);
613 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
614 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
617 /* de-initialize resource manager */
618 rm_ret = mm_resource_manager_destroy(player->resource_manager);
619 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
620 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
624 player->resource_manager = NULL;
626 LOGD("resource manager is destroyed");
629 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
631 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
635 if (player->hw_resource[type] == NULL) {
636 LOGD("there is no acquired [%d type] resource", type);
637 return MM_ERROR_NONE;
640 LOGD("mark for release [%d type] resource", type);
641 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
642 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
643 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
644 return MM_ERROR_PLAYER_INTERNAL;
647 player->hw_resource[type] = NULL;
649 LOGD("commit [%d type] resource", type);
650 rm_ret = mm_resource_manager_commit(player->resource_manager);
651 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
652 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
653 return MM_ERROR_PLAYER_INTERNAL;
657 return MM_ERROR_NONE;
661 __mmplayer_initialize_gapless_play(mmplayer_t *player)
667 player->smooth_streaming = FALSE;
668 player->videodec_linked = 0;
669 player->audiodec_linked = 0;
670 player->textsink_linked = 0;
671 player->is_external_subtitle_present = FALSE;
672 player->is_external_subtitle_added_now = FALSE;
673 player->not_supported_codec = MISSING_PLUGIN_NONE;
674 player->can_support_codec = FOUND_PLUGIN_NONE;
675 player->pending_seek.is_pending = false;
676 player->pending_seek.pos = 0;
677 player->msg_posted = FALSE;
678 player->has_many_types = FALSE;
679 player->no_more_pad = FALSE;
680 player->not_found_demuxer = 0;
681 player->seek_state = MMPLAYER_SEEK_NONE;
682 player->is_subtitle_force_drop = FALSE;
683 player->play_subtitle = FALSE;
684 player->adjust_subtitle_pos = 0;
686 player->total_bitrate = 0;
687 player->total_maximum_bitrate = 0;
689 _mmplayer_track_initialize(player);
690 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
692 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
693 player->bitrate[i] = 0;
694 player->maximum_bitrate[i] = 0;
697 if (player->v_stream_caps) {
698 gst_caps_unref(player->v_stream_caps);
699 player->v_stream_caps = NULL;
702 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
704 /* clean found audio decoders */
705 if (player->audio_decoders) {
706 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
707 player->audio_decoders = NULL;
710 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
715 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
717 LOGI("set pipeline reconfigure state %d", state);
718 MMPLAYER_RECONFIGURE_LOCK(player);
719 player->gapless.reconfigure = state;
720 if (!state) /* wake up the waiting job */
721 MMPLAYER_RECONFIGURE_SIGNAL(player);
722 MMPLAYER_RECONFIGURE_UNLOCK(player);
726 __mmplayer_gapless_play_thread(gpointer data)
728 mmplayer_t *player = (mmplayer_t *)data;
729 mmplayer_gst_element_t *mainbin = NULL;
731 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
733 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
734 while (!player->gapless_play_thread_exit) {
735 LOGD("gapless play thread started. waiting for signal.");
736 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
738 LOGD("reconfigure pipeline for gapless play.");
740 if (player->gapless_play_thread_exit) {
741 _mmplayer_set_reconfigure_state(player, FALSE);
742 LOGD("exiting gapless play thread");
746 mainbin = player->pipeline->mainbin;
748 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
749 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
752 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
754 /* Initialize Player values */
755 __mmplayer_initialize_gapless_play(player);
757 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
759 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
765 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
767 GSource *source = NULL;
771 source = g_main_context_find_source_by_id(context, source_id);
772 if (source != NULL) {
773 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
774 g_source_destroy(source);
781 _mmplayer_watcher_removed_notify(gpointer data)
783 mmplayer_t *player = (mmplayer_t *)data;
784 MMPLAYER_RETURN_IF_FAIL(player);
786 MMPLAYER_BUS_WATCHER_LOCK(player);
787 player->bus_watcher = 0;
788 MMPLAYER_BUS_WATCHER_SIGNAL(player);
789 MMPLAYER_BUS_WATCHER_UNLOCK(player);
793 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
795 mmplayer_t *player = (mmplayer_t *)hplayer;
798 MMPLAYER_RETURN_IF_FAIL(player);
800 /* disconnecting bus watch */
801 if (player->bus_watcher > 0) {
802 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
803 MMPLAYER_BUS_WATCHER_LOCK(player);
804 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
805 while (player->bus_watcher > 0) {
806 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
807 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
808 player->bus_watcher);
812 MMPLAYER_BUS_WATCHER_UNLOCK(player);
813 g_mutex_clear(&player->bus_watcher_mutex);
814 g_cond_clear(&player->bus_watcher_cond);
821 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
823 mmplayer_t *player = (mmplayer_t *)hplayer;
824 GstMessage *msg = NULL;
825 GQueue *queue = NULL;
828 MMPLAYER_RETURN_IF_FAIL(player);
830 /* destroy the gst bus msg thread */
831 if (player->bus_msg_thread) {
832 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
833 player->bus_msg_thread_exit = TRUE;
834 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
835 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
837 LOGD("gst bus msg thread exit.");
838 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
839 player->bus_msg_thread = NULL;
841 g_mutex_clear(&player->bus_msg_thread_mutex);
842 g_cond_clear(&player->bus_msg_thread_cond);
845 g_mutex_lock(&player->bus_msg_q_lock);
846 queue = player->bus_msg_q;
847 while (!g_queue_is_empty(queue)) {
848 msg = (GstMessage *)g_queue_pop_head(queue);
853 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
854 gst_message_unref(msg);
856 g_mutex_unlock(&player->bus_msg_q_lock);
862 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
864 GstElement *parent = NULL;
866 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
867 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
870 MMPLAYER_FSINK_LOCK(player);
872 /* get parent of fakesink */
873 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
875 LOGD("fakesink already removed");
879 gst_element_set_locked_state(fakesink->gst, TRUE);
881 /* setting the state to NULL never returns async
882 * so no need to wait for completion of state transition
884 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
885 LOGE("fakesink state change failure!");
886 /* FIXIT : should I return here? or try to proceed to next? */
889 /* remove fakesink from it's parent */
890 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
891 LOGE("failed to remove fakesink");
893 gst_object_unref(parent);
898 gst_object_unref(parent);
900 LOGD("state-holder removed");
902 gst_element_set_locked_state(fakesink->gst, FALSE);
904 MMPLAYER_FSINK_UNLOCK(player);
909 gst_element_set_locked_state(fakesink->gst, FALSE);
911 MMPLAYER_FSINK_UNLOCK(player);
915 static GstPadProbeReturn
916 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
918 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
919 return GST_PAD_PROBE_OK;
923 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
925 gint64 stop_running_time = 0;
926 gint64 position_running_time = 0;
930 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
931 if ((player->gapless.update_segment[idx] == TRUE) ||
932 !(player->track[idx].event_probe_id)) {
934 LOGW("[%d] skip", idx);
939 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
941 gst_segment_to_running_time(&player->gapless.segment[idx],
942 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
943 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
945 gst_segment_to_running_time(&player->gapless.segment[idx],
946 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
948 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
950 gst_segment_to_running_time(&player->gapless.segment[idx],
951 GST_FORMAT_TIME, player->duration);
954 position_running_time =
955 gst_segment_to_running_time(&player->gapless.segment[idx],
956 GST_FORMAT_TIME, player->gapless.segment[idx].position);
958 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
959 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
961 GST_TIME_ARGS(stop_running_time),
962 GST_TIME_ARGS(position_running_time),
963 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
964 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
966 position_running_time = MAX(position_running_time, stop_running_time);
967 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
968 GST_FORMAT_TIME, player->gapless.segment[idx].start);
969 position_running_time = MAX(0, position_running_time);
970 position = MAX(position, position_running_time);
974 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
975 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
976 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
978 player->gapless.start_time[stream_type] += position;
984 static GstPadProbeReturn
985 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
987 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
988 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
989 mmplayer_t *player = (mmplayer_t *)data;
990 GstCaps *caps = NULL;
991 GstStructure *str = NULL;
992 const gchar *name = NULL;
993 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
994 gboolean caps_ret = TRUE;
996 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
997 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
998 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
999 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1000 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1003 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1007 if (strstr(name, "audio")) {
1008 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1009 } else if (strstr(name, "video")) {
1010 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1012 /* text track is not supportable */
1013 LOGE("invalid name %s", name);
1017 switch (GST_EVENT_TYPE(event)) {
1020 /* in case of gapless, drop eos event not to send it to sink */
1021 if (player->gapless.reconfigure && !player->msg_posted) {
1022 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1023 ret = GST_PAD_PROBE_DROP;
1027 case GST_EVENT_STREAM_START:
1029 __mmplayer_gst_selector_update_start_time(player, stream_type);
1032 case GST_EVENT_FLUSH_STOP:
1034 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1035 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1036 player->gapless.start_time[stream_type] = 0;
1039 case GST_EVENT_SEGMENT:
1044 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1045 gst_event_copy_segment(event, &segment);
1047 if (segment.format != GST_FORMAT_TIME)
1050 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1051 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1052 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1053 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1054 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1055 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1057 /* keep the all the segment ev to cover the seeking */
1058 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1059 player->gapless.update_segment[stream_type] = TRUE;
1061 if (!player->gapless.running)
1064 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1066 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1068 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1069 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1070 gst_event_unref(event);
1071 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1077 gdouble proportion = 0.0;
1078 GstClockTimeDiff diff = 0;
1079 GstClockTime timestamp = 0;
1080 gint64 running_time_diff = -1;
1081 GstQOSType type = 0;
1082 GstEvent *tmpev = NULL;
1084 running_time_diff = player->gapless.segment[stream_type].base;
1086 if (running_time_diff <= 0) /* don't need to adjust */
1089 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1090 gst_event_unref(event);
1092 if (timestamp < running_time_diff) {
1093 LOGW("QOS event from previous group");
1094 ret = GST_PAD_PROBE_DROP;
1099 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1100 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1101 stream_type, GST_TIME_ARGS(timestamp),
1102 GST_TIME_ARGS(running_time_diff),
1103 GST_TIME_ARGS(timestamp - running_time_diff));
1106 timestamp -= running_time_diff;
1108 /* That case is invalid for QoS events */
1109 if (diff < 0 && -diff > timestamp) {
1110 LOGW("QOS event from previous group");
1111 ret = GST_PAD_PROBE_DROP;
1115 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1116 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1126 gst_caps_unref(caps);
1130 /* create fakesink for audio or video path without audiobin or videobin */
1132 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1134 GstElement *pipeline = NULL;
1135 GstElement *fakesink = NULL;
1136 GstPad *sinkpad = NULL;
1139 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1141 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1144 fakesink = gst_element_factory_make("fakesink", NULL);
1145 if (fakesink == NULL) {
1146 LOGE("failed to create fakesink");
1150 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1151 LOGE("failed to add fakesink to pipeline");
1156 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1158 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1160 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1161 LOGE("failed to link fakesink");
1165 if (strstr(name, "video")) {
1166 if (player->v_stream_caps) {
1167 gst_caps_unref(player->v_stream_caps);
1168 player->v_stream_caps = NULL;
1170 if (player->ini.set_dump_element_flag)
1171 __mmplayer_add_dump_buffer_probe(player, fakesink);
1174 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1175 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1177 /* store it as it's sink element */
1178 __mmplayer_add_sink(player, fakesink, FALSE);
1181 gst_object_unref(GST_OBJECT(sinkpad));
1189 gst_object_unref(GST_OBJECT(sinkpad));
1192 gst_element_set_state(fakesink, GST_STATE_NULL);
1194 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1195 gst_object_unref(GST_OBJECT(fakesink));
1202 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1204 GstElement *pipeline = NULL;
1205 GstElement *concat = NULL;
1208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1210 concat = gst_element_factory_make("concat", NULL);
1212 LOGE("failed to create concat");
1216 gst_element_set_state(concat, GST_STATE_PAUSED);
1218 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1219 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1220 LOGE("failed to add concat to pipeline");
1221 gst_element_set_state(concat, GST_STATE_NULL);
1222 gst_object_unref(GST_OBJECT(concat));
1226 LOGD("Create concat [%d] element", elem_idx);
1228 player->pipeline->mainbin[elem_idx].id = elem_idx;
1229 player->pipeline->mainbin[elem_idx].gst = concat;
1236 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1238 GstElement *pipeline = NULL;
1239 GstElement *selector = NULL;
1240 GstPad *srcpad = NULL;
1243 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1245 selector = gst_element_factory_make("input-selector", NULL);
1247 LOGE("failed to create input-selector");
1250 g_object_set(selector, "sync-streams", TRUE, NULL);
1252 srcpad = gst_element_get_static_pad(selector, "src");
1254 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1255 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1256 __mmplayer_gst_selector_blocked, NULL, NULL);
1257 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1258 __mmplayer_gst_selector_event_probe, player, NULL);
1260 gst_element_set_state(selector, GST_STATE_PAUSED);
1262 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1263 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1264 LOGE("failed to add selector to pipeline");
1266 if (player->track[stream_type].block_id != 0)
1267 gst_pad_remove_probe (srcpad, player->track[stream_type].block_id);
1268 player->track[stream_type].block_id = 0;
1270 if (player->track[stream_type].event_probe_id != 0)
1271 gst_pad_remove_probe (srcpad, player->track[stream_type].event_probe_id);
1272 player->track[stream_type].event_probe_id = 0;
1274 gst_object_unref(GST_OBJECT(srcpad));
1276 gst_element_set_state(selector, GST_STATE_NULL);
1277 gst_object_unref(GST_OBJECT(selector));
1281 gst_object_unref(GST_OBJECT(srcpad));
1283 player->pipeline->mainbin[elem_idx].id = elem_idx;
1284 player->pipeline->mainbin[elem_idx].gst = selector;
1291 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1293 mmplayer_t *player = (mmplayer_t *)data;
1294 GstElement *combiner = NULL;
1295 GstCaps *caps = NULL;
1296 GstStructure *str = NULL;
1297 const gchar *name = NULL;
1298 GstPad *sinkpad = NULL;
1299 gboolean first_track = FALSE;
1300 gboolean caps_ret = TRUE;
1302 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1303 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1306 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1307 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1309 LOGD("pad-added signal handling");
1311 /* get mimetype from caps */
1312 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1316 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1318 LOGD("detected mimetype : %s", name);
1321 if (strstr(name, "video")) {
1323 gchar *caps_str = NULL;
1325 caps_str = gst_caps_to_string(caps);
1326 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1327 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1328 player->set_mode.video_zc = true;
1330 MMPLAYER_FREEIF(caps_str);
1332 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1333 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1335 LOGD("surface type : %d", stype);
1337 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1338 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1342 /* in case of exporting video frame, it requires the 360 video filter.
1343 * it will be handled in _no_more_pads(). */
1344 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1345 __mmplayer_gst_make_fakesink(player, pad, name);
1349 if (MMPLAYER_USE_DECODEBIN(player)) {
1350 LOGD("video selector is required");
1351 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1353 LOGD("video concat is required");
1354 elem_idx = MMPLAYER_M_V_CONCAT;
1356 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1357 } else if (strstr(name, "audio")) {
1358 gint samplerate = 0;
1361 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1362 if (player->build_audio_offload)
1363 player->no_more_pad = TRUE; /* remove state holder */
1364 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1368 gst_structure_get_int(str, "rate", &samplerate);
1369 gst_structure_get_int(str, "channels", &channels);
1371 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1372 __mmplayer_gst_make_fakesink(player, pad, name);
1375 if (MMPLAYER_USE_DECODEBIN(player)) {
1376 LOGD("audio selector is required");
1377 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1379 LOGD("audio concat is required");
1380 elem_idx = MMPLAYER_M_A_CONCAT;
1382 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1384 } else if (strstr(name, "text")) {
1385 if (MMPLAYER_USE_DECODEBIN(player)) {
1386 LOGD("text selector is required");
1387 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1389 LOGD("text concat is required");
1390 elem_idx = MMPLAYER_M_T_CONCAT;
1392 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1394 LOGE("invalid caps info");
1398 /* check selector and create it */
1399 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1400 if (MMPLAYER_USE_DECODEBIN(player))
1401 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1403 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1409 LOGD("Combiner element is already created.");
1413 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1415 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1417 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1418 LOGE("failed to link combiner");
1419 gst_object_unref(GST_OBJECT(combiner));
1424 if (MMPLAYER_USE_DECODEBIN(player)) {
1425 LOGD("this track will be activated");
1426 g_object_set(combiner, "active-pad", sinkpad, NULL);
1430 if (MMPLAYER_USE_DECODEBIN(player)) {
1431 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1433 /* apply the text track information */
1434 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1435 mm_player_set_attribute((MMHandleType)player, NULL,
1436 "content_text_track_num", player->track[stream_type].total_track_num,
1437 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1438 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1445 gst_caps_unref(caps);
1448 gst_object_unref(GST_OBJECT(sinkpad));
1452 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1457 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1459 GstPad *srcpad = NULL;
1462 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1464 LOGD("type %d", type);
1467 LOGD("there is no %d track", type);
1471 srcpad = gst_element_get_static_pad(combiner, "src");
1473 LOGE("failed to get srcpad from combiner");
1477 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1479 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1481 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1482 if (player->track[type].block_id) {
1483 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1484 player->track[type].block_id = 0;
1488 gst_object_unref(GST_OBJECT(srcpad));
1497 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1499 gint active_index = 0;
1502 MMPLAYER_RETURN_IF_FAIL(player);
1504 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1506 /* change track to active pad */
1507 active_index = player->track[type].active_track_index;
1508 if ((active_index != DEFAULT_TRACK_INDEX) &&
1509 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1510 LOGW("failed to change %d type track to %d", type, active_index);
1511 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1515 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1516 mm_player_set_attribute((MMHandleType)player, NULL,
1517 "content_text_track_num", player->track[type].total_track_num,
1518 "current_text_track_index", player->track[type].active_track_index, NULL);
1525 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1528 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1530 if (!audio_selector) {
1531 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1533 /* in case the source is changed, output can be changed. */
1534 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1535 LOGD("remove previous audiobin if it exist");
1537 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1538 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1540 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1541 MMPLAYER_FREEIF(player->pipeline->audiobin);
1544 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1545 _mmplayer_pipeline_complete(NULL, player);
1550 /* apply the audio track information */
1551 if (MMPLAYER_USE_DECODEBIN(player))
1552 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1554 /* create audio sink path */
1555 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1556 LOGE("failed to create audio sink path");
1565 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1568 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1570 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1571 LOGD("text path is not supported");
1575 /* apply the text track information */
1576 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1578 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1579 player->has_closed_caption = TRUE;
1581 /* create text decode path */
1582 player->no_more_pad = TRUE;
1584 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1585 LOGE("failed to create text sink path");
1594 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1596 gint64 dur_bytes = 0L;
1599 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1600 player->pipeline->mainbin && player->streamer, FALSE);
1602 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1603 LOGE("fail to get duration.");
1605 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1606 * use file information was already set on Q2 when it was created. */
1607 _mm_player_streaming_set_queue2(player->streamer,
1608 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1609 TRUE, /* use_buffering */
1610 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1611 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1618 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1620 mmplayer_t *player = NULL;
1621 GstElement *video_selector = NULL;
1622 GstElement *audio_selector = NULL;
1623 GstElement *text_selector = NULL;
1626 player = (mmplayer_t *)data;
1628 LOGD("no-more-pad signal handling");
1630 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1631 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1632 LOGW("player is shutting down");
1636 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1637 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1638 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1639 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1640 LOGE("failed to set queue2 buffering");
1645 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1646 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1647 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1649 if (!video_selector && !audio_selector && !text_selector) {
1650 LOGW("there is no selector");
1651 player->no_more_pad = TRUE;
1655 /* create video path followed by video-select */
1656 if (video_selector && !audio_selector && !text_selector)
1657 player->no_more_pad = TRUE;
1659 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1662 /* create audio path followed by audio-select */
1663 if (audio_selector && !text_selector)
1664 player->no_more_pad = TRUE;
1666 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1669 /* create text path followed by text-select */
1670 __mmplayer_create_text_sink_path(player, text_selector);
1673 _mmplayer_set_reconfigure_state(player, FALSE);
1678 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1680 gboolean ret = FALSE;
1681 GstElement *pipeline = NULL;
1682 GstPad *sinkpad = NULL;
1685 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1686 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1688 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1690 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1692 LOGE("failed to get pad from sinkbin");
1698 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1699 LOGE("failed to link sinkbin for reusing");
1700 goto EXIT; /* exit either pass or fail */
1704 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1705 LOGE("failed to set state(READY) to sinkbin");
1710 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1711 LOGE("failed to add sinkbin to pipeline");
1716 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1717 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1722 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1723 LOGE("failed to set state(PAUSED) to sinkbin");
1732 gst_object_unref(GST_OBJECT(sinkpad));
1740 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1742 mmplayer_t *player = NULL;
1743 GstCaps *caps = NULL;
1744 gchar *caps_str = NULL;
1745 GstStructure *str = NULL;
1746 const gchar *name = NULL;
1747 GstElement *sinkbin = NULL;
1748 gboolean reusing = FALSE;
1749 gboolean caps_ret = TRUE;
1750 gchar *sink_pad_name = "sink";
1753 player = (mmplayer_t *)data;
1756 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1757 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1758 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1760 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1764 gst_caps_unref(caps);
1765 caps = gst_caps_ref(ref_caps);
1768 caps_str = gst_caps_to_string(caps);
1770 LOGD("detected mimetype : %s", name);
1772 if (strstr(name, "audio")) {
1773 if (player->pipeline->audiobin == NULL) {
1774 const gchar *audio_format = gst_structure_get_string(str, "format");
1776 LOGD("original audio format %s", audio_format);
1777 mm_player_set_attribute((MMHandleType)player, NULL,
1778 "content_audio_format", audio_format, strlen(audio_format), NULL);
1781 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1782 LOGE("failed to create audiobin. continuing without audio");
1786 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1787 LOGD("creating audiobin success");
1790 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1791 LOGD("reusing audiobin");
1792 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1794 } else if (strstr(name, "video")) {
1795 /* 1. zero copy is updated at _decode_pad_added()
1796 * 2. NULL surface type is handled in _decode_pad_added() */
1797 LOGD("zero copy %d", player->set_mode.video_zc);
1798 if (player->pipeline->videobin == NULL) {
1799 int surface_type = 0;
1800 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1801 LOGD("display_surface_type (%d)", surface_type);
1803 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1804 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1805 LOGE("failed to acquire video overlay resource");
1809 player->interrupted_by_resource = FALSE;
1811 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1812 LOGE("failed to create videobin. continuing without video");
1816 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1817 LOGD("creating videosink bin success");
1820 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1821 LOGD("re-using videobin");
1822 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1824 } else if (strstr(name, "text")) {
1825 if (player->pipeline->textbin == NULL) {
1826 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1827 LOGE("failed to create text sink bin. continuing without text");
1831 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1832 player->textsink_linked = 1;
1833 LOGD("creating textsink bin success");
1835 if (!player->textsink_linked) {
1836 LOGD("re-using textbin");
1838 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1839 player->textsink_linked = 1;
1841 /* linked textbin exist which means that the external subtitle path exist already */
1842 LOGW("ignoring internal subtitle since external subtitle is available");
1845 sink_pad_name = "text_sink";
1847 LOGW("unknown mime type %s, ignoring it", name);
1851 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1854 LOGD("[handle: %p] success to create and link sink bin", player);
1856 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1857 * streaming task. if the task blocked, then buffer will not flow to the next element
1858 *(autoplugging element). so this is special hack for streaming. please try to remove it
1860 /* dec stream count. we can remove fakesink if it's zero */
1861 if (player->num_dynamic_pad)
1862 player->num_dynamic_pad--;
1864 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1866 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1867 _mmplayer_pipeline_complete(NULL, player);
1871 MMPLAYER_FREEIF(caps_str);
1874 gst_caps_unref(caps);
1880 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1882 int required_angle = 0; /* Angle required for straight view */
1883 int rotation_angle = 0;
1885 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1886 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1888 /* Counter clockwise */
1889 switch (orientation) {
1894 required_angle = 270;
1897 required_angle = 180;
1900 required_angle = 90;
1904 rotation_angle = display_angle + required_angle;
1905 if (rotation_angle >= 360)
1906 rotation_angle -= 360;
1908 /* check if supported or not */
1909 if (rotation_angle % 90) {
1910 LOGD("not supported rotation angle = %d", rotation_angle);
1914 switch (rotation_angle) {
1916 *value = MM_DISPLAY_ROTATION_NONE;
1919 *value = MM_DISPLAY_ROTATION_90;
1922 *value = MM_DISPLAY_ROTATION_180;
1925 *value = MM_DISPLAY_ROTATION_270;
1929 LOGD("setting rotation property value : %d", *value);
1935 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1937 int display_rotation = 0;
1938 gchar *org_orient = NULL;
1939 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1942 LOGE("cannot get content attribute");
1943 return MM_ERROR_PLAYER_INTERNAL;
1946 if (display_angle) {
1947 /* update user rotation */
1948 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1950 /* Counter clockwise */
1951 switch (display_rotation) {
1952 case MM_DISPLAY_ROTATION_NONE:
1955 case MM_DISPLAY_ROTATION_90:
1956 *display_angle = 90;
1958 case MM_DISPLAY_ROTATION_180:
1959 *display_angle = 180;
1961 case MM_DISPLAY_ROTATION_270:
1962 *display_angle = 270;
1965 LOGW("wrong angle type : %d", display_rotation);
1968 LOGD("check user angle: %d", *display_angle);
1972 /* Counter clockwise */
1973 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1976 if (!strcmp(org_orient, "rotate-90"))
1978 else if (!strcmp(org_orient, "rotate-180"))
1980 else if (!strcmp(org_orient, "rotate-270"))
1983 LOGD("original rotation is %s", org_orient);
1985 LOGD("content_video_orientation get fail");
1988 LOGD("check orientation: %d", *orientation);
1991 return MM_ERROR_NONE;
1994 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1996 int rotation_value = 0;
1997 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1998 int display_angle = 0;
2001 /* check video sinkbin is created */
2002 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2005 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2007 /* get rotation value to set */
2008 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2009 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2010 LOGD("set video param : rotate %d", rotation_value);
2013 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2015 MMHandleType attrs = 0;
2019 /* check video sinkbin is created */
2020 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2021 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2024 attrs = MMPLAYER_GET_ATTRS(player);
2025 MMPLAYER_RETURN_IF_FAIL(attrs);
2027 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2028 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2029 LOGD("set video param : visible %d", visible);
2032 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2034 MMHandleType attrs = 0;
2035 int display_method = 0;
2038 /* check video sinkbin is created */
2039 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2042 attrs = MMPLAYER_GET_ATTRS(player);
2043 MMPLAYER_RETURN_IF_FAIL(attrs);
2045 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2046 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2047 LOGD("set video param : method %d", display_method);
2050 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2052 MMHandleType attrs = 0;
2056 /* check video sinkbin is created */
2057 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2060 attrs = MMPLAYER_GET_ATTRS(player);
2061 MMPLAYER_RETURN_IF_FAIL(attrs);
2063 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2064 MMPLAYER_RETURN_IF_FAIL(handle);
2066 gst_video_overlay_set_video_roi_area(
2067 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2068 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2069 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2070 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2073 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2075 MMHandleType attrs = 0;
2080 int win_roi_width = 0;
2081 int win_roi_height = 0;
2084 /* check video sinkbin is created */
2085 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2088 attrs = MMPLAYER_GET_ATTRS(player);
2089 MMPLAYER_RETURN_IF_FAIL(attrs);
2091 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2092 MMPLAYER_RETURN_IF_FAIL(handle);
2094 /* It should be set after setting window */
2095 mm_attrs_multiple_get(attrs, NULL,
2096 "display_win_roi_x", &win_roi_x,
2097 "display_win_roi_y", &win_roi_y,
2098 "display_win_roi_width", &win_roi_width,
2099 "display_win_roi_height", &win_roi_height, NULL);
2101 /* After setting window handle, set display roi area */
2102 gst_video_overlay_set_display_roi_area(
2103 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2104 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2105 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2106 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2109 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2111 MMHandleType attrs = 0;
2112 gchar *handle = NULL;
2114 /* check video sinkbin is created */
2115 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2118 attrs = MMPLAYER_GET_ATTRS(player);
2119 MMPLAYER_RETURN_IF_FAIL(attrs);
2121 /* common case if using overlay surface */
2122 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2123 MMPLAYER_RETURN_IF_FAIL(handle);
2125 gst_video_overlay_set_wl_window_exported_shell_handle(
2126 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2128 LOGD("set video param: exported_shell_handle (%s)", handle);
2131 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2133 MMHandleType attrs = 0;
2136 /* check video sinkbin is created */
2137 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2140 attrs = MMPLAYER_GET_ATTRS(player);
2141 MMPLAYER_RETURN_IF_FAIL(attrs);
2143 /* common case if using overlay surface */
2144 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2145 MMPLAYER_RETURN_IF_FAIL(handle);
2147 /* default is using wl_surface_id */
2148 LOGD("set video param : wl_surface_id %d", handle);
2149 gst_video_overlay_set_wl_window_wl_surface_id(
2150 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2155 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2157 gboolean update_all_param = FALSE;
2158 int curr_type = MM_DISPLAY_SURFACE_NUM;
2162 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2163 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2164 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2165 LOGW("videosink is not ready yet");
2166 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2169 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2171 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2172 LOGE("current type(%d) is wrong", curr_type);
2173 return MM_ERROR_PLAYER_INTERNAL;
2176 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2177 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2178 return MM_ERROR_PLAYER_INTERNAL;
2181 LOGD("param_name : %s", param_name);
2182 if (!g_strcmp0(param_name, "update_all_param"))
2183 update_all_param = TRUE;
2185 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2186 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2188 return MM_ERROR_NONE;
2190 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2191 __mmplayer_video_param_set_display_overlay(player);
2192 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2193 __mmplayer_video_param_set_display_method(player);
2194 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2195 __mmplayer_video_param_set_display_visible(player);
2196 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2197 __mmplayer_video_param_set_display_rotation(player);
2198 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2199 __mmplayer_video_param_set_roi_area(player);
2200 if (update_all_param)
2201 __mmplayer_video_param_set_video_roi_area(player);
2204 return MM_ERROR_NONE;
2207 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2209 gboolean disable_overlay = FALSE;
2212 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2213 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2214 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2216 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2217 LOGW("Display control is not supported");
2218 return MM_ERROR_PLAYER_INTERNAL;
2221 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2223 if (disable == (bool)disable_overlay) {
2224 LOGE("It's the same with current setting: (%d)", disable);
2225 return MM_ERROR_NONE;
2229 LOGE("disable overlay");
2230 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2232 /* release overlay resource */
2233 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2234 LOGE("failed to release overlay resource");
2235 return MM_ERROR_PLAYER_INTERNAL;
2238 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2239 LOGE("failed to acquire video overlay resource");
2240 return MM_ERROR_PLAYER_INTERNAL;
2242 player->interrupted_by_resource = FALSE;
2244 LOGD("enable overlay");
2245 __mmplayer_video_param_set_display_overlay(player);
2246 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2247 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2251 return MM_ERROR_NONE;
2255 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2257 int ret = MM_ERROR_NONE;
2258 mmplayer_t *player = (mmplayer_t *)hplayer;
2261 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2263 if (MMPLAYER_USE_DECODEBIN(player)) {
2264 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2269 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2270 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2271 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2273 __mmplayer_del_sink(player, player->pipeline->videobin[MMPLAYER_V_SINK].gst);
2275 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2277 /* release decoder resource */
2278 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2279 LOGE("failed to release video decoder resources");
2280 return MM_ERROR_PLAYER_INTERNAL;
2282 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2284 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2288 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2295 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2297 GList *bucket = element_bucket;
2298 mmplayer_gst_element_t *element = NULL;
2299 mmplayer_gst_element_t *prv_element = NULL;
2300 GstElement *tee_element = NULL;
2301 gint successful_link_count = 0;
2305 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2307 prv_element = (mmplayer_gst_element_t *)bucket->data;
2308 bucket = bucket->next;
2310 for (; bucket; bucket = bucket->next) {
2311 element = (mmplayer_gst_element_t *)bucket->data;
2313 if (element && element->gst) {
2314 if (prv_element && prv_element->gst) {
2315 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2317 prv_element->gst = tee_element;
2319 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2320 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2321 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2325 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2326 LOGD("linking [%s] to [%s] success",
2327 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2328 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2329 successful_link_count++;
2330 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2331 LOGD("keep audio-tee element for next audio pipeline branch");
2332 tee_element = prv_element->gst;
2335 LOGD("linking [%s] to [%s] failed",
2336 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2337 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2343 prv_element = element;
2348 return successful_link_count;
2352 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2354 GList *bucket = element_bucket;
2355 mmplayer_gst_element_t *element = NULL;
2356 int successful_add_count = 0;
2360 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2361 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2363 for (; bucket; bucket = bucket->next) {
2364 element = (mmplayer_gst_element_t *)bucket->data;
2366 if (element && element->gst) {
2367 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2368 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2369 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2370 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2373 successful_add_count++;
2379 return successful_add_count;
2383 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2385 mmplayer_t *player = (mmplayer_t *)data;
2386 GstCaps *caps = NULL;
2387 GstStructure *str = NULL;
2389 gboolean caps_ret = TRUE;
2393 MMPLAYER_RETURN_IF_FAIL(pad);
2394 MMPLAYER_RETURN_IF_FAIL(unused);
2395 MMPLAYER_RETURN_IF_FAIL(data);
2397 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2401 LOGD("name = %s", name);
2403 if (strstr(name, "audio")) {
2404 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2406 if (player->audio_stream_changed_cb) {
2407 LOGE("call the audio stream changed cb");
2408 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2410 } else if (strstr(name, "video")) {
2411 if ((name = gst_structure_get_string(str, "format")))
2412 player->set_mode.video_zc = name[0] == 'S';
2414 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2415 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2417 LOGW("invalid caps info");
2422 gst_caps_unref(caps);
2430 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2435 MMPLAYER_RETURN_IF_FAIL(player);
2437 if (player->audio_stream_buff_list) {
2438 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2439 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2442 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2443 __mmplayer_audio_stream_send_data(player, tmp);
2445 MMPLAYER_FREEIF(tmp->pcm_data);
2446 MMPLAYER_FREEIF(tmp);
2449 g_list_free(player->audio_stream_buff_list);
2450 player->audio_stream_buff_list = NULL;
2457 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2459 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2462 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2464 audio_stream.bitrate = a_buffer->bitrate;
2465 audio_stream.channel = a_buffer->channel;
2466 audio_stream.channel_mask = a_buffer->channel_mask;
2467 audio_stream.data_size = a_buffer->data_size;
2468 audio_stream.data = a_buffer->pcm_data;
2469 audio_stream.pcm_format = a_buffer->pcm_format;
2471 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2473 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2479 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2481 mmplayer_t *player = (mmplayer_t *)data;
2482 const gchar *pcm_format = NULL;
2485 guint64 channel_mask = 0;
2486 void *a_data = NULL;
2488 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2489 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2493 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2495 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2496 a_data = mapinfo.data;
2497 a_size = mapinfo.size;
2499 GstCaps *caps = gst_pad_get_current_caps(pad);
2500 GstStructure *structure = gst_caps_get_structure(caps, 0);
2502 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2504 pcm_format = gst_structure_get_string(structure, "format");
2505 gst_structure_get_int(structure, "rate", &rate);
2506 gst_structure_get_int(structure, "channels", &channel);
2507 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2508 gst_caps_unref(GST_CAPS(caps));
2510 /* In case of the sync is false, use buffer list. *
2511 * The num of buffer list depends on the num of audio channels */
2512 if (player->audio_stream_buff_list) {
2513 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2514 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2516 if (channel_mask == tmp->channel_mask) {
2518 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2520 if (tmp->data_size + a_size < tmp->buff_size) {
2521 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2522 tmp->data_size += a_size;
2524 /* send data to client */
2525 __mmplayer_audio_stream_send_data(player, tmp);
2527 if (a_size > tmp->buff_size) {
2528 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2529 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2530 if (tmp->pcm_data == NULL) {
2531 LOGE("failed to realloc data.");
2534 tmp->buff_size = a_size;
2536 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2537 memcpy(tmp->pcm_data, a_data, a_size);
2538 tmp->data_size = a_size;
2543 LOGE("data is empty in list.");
2549 /* create new audio stream data for newly found audio channel */
2550 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2551 if (a_buffer == NULL) {
2552 LOGE("failed to alloc data.");
2555 a_buffer->bitrate = rate;
2556 a_buffer->channel = channel;
2557 a_buffer->channel_mask = channel_mask;
2558 a_buffer->data_size = a_size;
2559 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2561 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2562 /* If sync is FALSE, use buffer list to reduce the IPC. */
2563 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2564 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2565 if (a_buffer->pcm_data == NULL) {
2566 LOGE("failed to alloc data.");
2567 MMPLAYER_FREEIF(a_buffer);
2570 memcpy(a_buffer->pcm_data, a_data, a_size);
2572 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2574 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2576 /* If sync is TRUE, send data directly. */
2577 a_buffer->pcm_data = a_data;
2578 __mmplayer_audio_stream_send_data(player, a_buffer);
2579 MMPLAYER_FREEIF(a_buffer);
2583 gst_buffer_unmap(buffer, &mapinfo);
2588 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2590 mmplayer_t *player = (mmplayer_t *)data;
2591 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2592 GstPad *sinkpad = NULL;
2593 GstElement *queue = NULL, *sink = NULL;
2596 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2598 queue = gst_element_factory_make("queue", NULL);
2599 if (queue == NULL) {
2600 LOGD("fail make queue");
2604 sink = gst_element_factory_make("fakesink", NULL);
2606 LOGD("fail make fakesink");
2610 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2612 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2613 LOGW("failed to link queue & sink");
2617 sinkpad = gst_element_get_static_pad(queue, "sink");
2619 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2620 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2624 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2626 gst_object_unref(sinkpad);
2627 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2628 g_object_set(sink, "sync", TRUE, NULL);
2629 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2631 /* keep the first sink reference only */
2632 if (!audiobin[MMPLAYER_A_SINK].gst) {
2633 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2634 audiobin[MMPLAYER_A_SINK].gst = sink;
2638 _mmplayer_add_signal_connection(player,
2640 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2642 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2645 __mmplayer_add_sink(player, sink, FALSE);
2647 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2648 LOGE("failed to sync state");
2652 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2653 LOGE("failed to sync state");
2661 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2663 gst_object_unref(GST_OBJECT(queue));
2667 gst_object_unref(GST_OBJECT(sink));
2671 gst_object_unref(GST_OBJECT(sinkpad));
2679 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2681 mmplayer_t *player = (mmplayer_t *)data;
2684 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2686 player->no_more_pad = TRUE;
2687 _mmplayer_pipeline_complete(NULL, player);
2694 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2696 #define MAX_PROPS_LEN 128
2697 mmplayer_gst_element_t *audiobin = NULL;
2698 gint latency_mode = 0;
2699 gchar *stream_type = NULL;
2700 gchar *latency = NULL;
2702 gchar stream_props[MAX_PROPS_LEN] = {0,};
2703 GstStructure *props = NULL;
2706 * It should be set after player creation through attribute.
2707 * But, it can not be changed during playing.
2710 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2712 audiobin = player->pipeline->audiobin;
2714 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2715 if (player->sound.mute) {
2716 LOGD("mute enabled");
2717 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2720 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2721 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2724 snprintf(stream_props, sizeof(stream_props) - 1,
2725 "props,application.process.id.origin=%d", player->client_pid);
2727 snprintf(stream_props, sizeof(stream_props) - 1,
2728 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2729 stream_type, stream_id, player->client_pid);
2731 props = gst_structure_from_string(stream_props, NULL);
2732 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2733 LOGI("props result[%s].", stream_props);
2734 gst_structure_free(props);
2736 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2738 switch (latency_mode) {
2739 case AUDIO_LATENCY_MODE_LOW:
2740 latency = g_strdup("low");
2742 case AUDIO_LATENCY_MODE_MID:
2743 latency = g_strdup("mid");
2745 case AUDIO_LATENCY_MODE_HIGH:
2746 latency = g_strdup("high");
2749 latency = g_strdup("mid");
2753 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2755 LOGD("audiosink property - latency=%s", latency);
2757 MMPLAYER_FREEIF(latency);
2763 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2765 mmplayer_gst_element_t *audiobin = NULL;
2768 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2769 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2771 audiobin = player->pipeline->audiobin;
2773 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2774 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2775 LOGE("failed to create media stream info");
2776 return MM_ERROR_PLAYER_INTERNAL;
2779 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2781 if (player->video360_yaw_radians <= M_PI &&
2782 player->video360_yaw_radians >= -M_PI &&
2783 player->video360_pitch_radians <= M_PI_2 &&
2784 player->video360_pitch_radians >= -M_PI_2) {
2785 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2786 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2787 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2788 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2789 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2790 "source-orientation-y", player->video360_metadata.init_view_heading,
2791 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2795 return MM_ERROR_NONE;
2799 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2801 mmplayer_gst_element_t *audiobin = NULL;
2802 GstPad *sink_pad = NULL;
2803 GstCaps *acaps = NULL;
2805 int pitch_control = 0;
2806 double pitch_value = 1.0;
2809 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2810 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2812 audiobin = player->pipeline->audiobin;
2814 LOGD("make element for normal audio playback");
2816 /* audio bin structure for playback. {} means optional.
2817 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2819 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2820 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2823 /* for pitch control */
2824 mm_attrs_multiple_get(player->attrs, NULL,
2825 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2826 MM_PLAYER_PITCH_VALUE, &pitch_value,
2829 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2830 if (pitch_control && (player->videodec_linked == 0)) {
2831 GstElementFactory *factory;
2833 factory = gst_element_factory_find("pitch");
2835 gst_object_unref(factory);
2838 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2841 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2842 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2844 LOGW("there is no pitch element");
2849 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2851 /* replaygain volume */
2852 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2853 if (player->sound.rg_enable)
2854 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2856 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2859 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2861 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2862 /* currently, only openalsink uses volume element */
2863 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2864 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2866 if (player->sound.mute) {
2867 LOGD("mute enabled");
2868 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2872 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2874 /* audio effect element. if audio effect is enabled */
2875 if ((strcmp(player->ini.audioeffect_element, ""))
2877 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2878 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2880 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2882 if ((!player->bypass_audio_effect)
2883 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2884 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2885 if (!_mmplayer_audio_effect_custom_apply(player))
2886 LOGI("apply audio effect(custom) setting success");
2890 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2891 && (player->set_mode.rich_audio)) {
2892 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2896 /* create audio sink */
2897 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2898 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2899 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2901 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2902 if (player->is_360_feature_enabled &&
2903 player->is_content_spherical &&
2905 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2906 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2907 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2909 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2911 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2913 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2914 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2915 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2916 gst_caps_unref(acaps);
2918 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2920 player->is_openal_plugin_used = TRUE;
2922 if (player->is_360_feature_enabled && player->is_content_spherical)
2923 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2924 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2927 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2928 (player->videodec_linked && player->ini.use_system_clock)) {
2929 LOGD("system clock will be used.");
2930 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2933 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2934 __mmplayer_gst_set_pulsesink_property(player);
2935 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2936 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2941 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2942 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2944 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2945 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2946 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2947 gst_object_unref(GST_OBJECT(sink_pad));
2949 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2952 return MM_ERROR_NONE;
2954 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2956 return MM_ERROR_PLAYER_INTERNAL;
2960 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2962 mmplayer_gst_element_t *audiobin = NULL;
2963 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2965 gchar *dst_format = NULL;
2967 int dst_samplerate = 0;
2968 int dst_channels = 0;
2969 GstCaps *caps = NULL;
2970 char *caps_str = NULL;
2973 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2974 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2976 audiobin = player->pipeline->audiobin;
2978 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2980 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2982 [case 1] extract interleave audio pcm without playback
2983 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2984 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2986 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2988 [case 2] deinterleave for each channel without playback
2989 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2990 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2992 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2993 - fakesink (sync or not)
2996 [case 3] [case 1(sync only)] + playback
2997 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2999 * src - ... - tee - queue1 - playback path
3000 - queue2 - [case1 pipeline with sync]
3002 [case 4] [case 2(sync only)] + playback
3003 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3005 * src - ... - tee - queue1 - playback path
3006 - queue2 - [case2 pipeline with sync]
3010 /* 1. create tee and playback path
3011 'tee' should be added at first to copy the decoded stream
3013 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3014 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3015 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3017 /* tee - path 1 : for playback path */
3018 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3019 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3021 /* tee - path 2 : for extract path */
3022 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3023 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3026 /* if there is tee, 'tee - path 2' is linked here */
3028 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3031 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3033 /* 2. decide the extract pcm format */
3034 mm_attrs_multiple_get(player->attrs, NULL,
3035 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3036 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3037 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3040 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3041 dst_format, dst_len, dst_samplerate, dst_channels);
3043 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3044 mm_attrs_multiple_get(player->attrs, NULL,
3045 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3046 "content_audio_samplerate", &dst_samplerate,
3047 "content_audio_channels", &dst_channels,
3050 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3051 dst_format, dst_len, dst_samplerate, dst_channels);
3053 /* If there is no enough information, set it to platform default value. */
3054 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3055 LOGD("set platform default format");
3056 dst_format = DEFAULT_PCM_OUT_FORMAT;
3058 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3059 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3062 /* 3. create capsfilter */
3063 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3064 caps = gst_caps_new_simple("audio/x-raw",
3065 "format", G_TYPE_STRING, dst_format,
3066 "rate", G_TYPE_INT, dst_samplerate,
3067 "channels", G_TYPE_INT, dst_channels,
3070 caps_str = gst_caps_to_string(caps);
3071 LOGD("new caps : %s", caps_str);
3073 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3076 gst_caps_unref(caps);
3077 MMPLAYER_FREEIF(caps_str);
3079 /* 4-1. create deinterleave to extract pcm for each channel */
3080 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3081 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3082 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3084 /* audiosink will be added after getting signal for each channel */
3085 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3086 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3087 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3088 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3089 player->no_more_pad = FALSE;
3091 /* 4-2. create fakesink to extract interleaved pcm */
3092 LOGD("add audio fakesink for interleaved audio");
3093 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3094 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3095 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3096 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3098 _mmplayer_add_signal_connection(player,
3099 G_OBJECT(audiobin[extract_sink_id].gst),
3100 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3102 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3105 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3109 return MM_ERROR_NONE;
3111 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3113 return MM_ERROR_PLAYER_INTERNAL;
3117 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3119 int ret = MM_ERROR_NONE;
3120 mmplayer_gst_element_t *audiobin = NULL;
3121 GList *element_bucket = NULL;
3124 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3125 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3127 audiobin = player->pipeline->audiobin;
3129 if (player->build_audio_offload) { /* skip all the audio filters */
3130 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3132 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3133 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3134 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3136 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3140 /* FIXME: need to mention the supportable condition at API reference */
3141 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3142 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3144 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3146 if (ret != MM_ERROR_NONE)
3149 LOGD("success to make audio bin element");
3150 *bucket = element_bucket;
3153 return MM_ERROR_NONE;
3156 LOGE("failed to make audio bin element");
3157 g_list_free(element_bucket);
3161 return MM_ERROR_PLAYER_INTERNAL;
3165 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3167 mmplayer_gst_element_t *first_element = NULL;
3168 mmplayer_gst_element_t *audiobin = NULL;
3170 GstPad *ghostpad = NULL;
3171 GList *element_bucket = NULL;
3175 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3178 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3180 LOGE("failed to allocate memory for audiobin");
3181 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3185 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3186 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3187 if (!audiobin[MMPLAYER_A_BIN].gst) {
3188 LOGE("failed to create audiobin");
3193 player->pipeline->audiobin = audiobin;
3195 /* create audio filters and audiosink */
3196 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3199 /* adding created elements to bin */
3200 LOGD("adding created elements to bin");
3201 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3204 /* linking elements in the bucket by added order. */
3205 LOGD("Linking elements in the bucket by added order.");
3206 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3209 /* get first element's sinkpad for creating ghostpad */
3210 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3211 if (!first_element) {
3212 LOGE("failed to get first elem");
3216 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3218 LOGE("failed to get pad from first element of audiobin");
3222 ghostpad = gst_ghost_pad_new("sink", pad);
3224 LOGE("failed to create ghostpad");
3228 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3229 LOGE("failed to add ghostpad to audiobin");
3233 gst_object_unref(pad);
3235 g_list_free(element_bucket);
3238 return MM_ERROR_NONE;
3241 LOGD("ERROR : releasing audiobin");
3244 gst_object_unref(GST_OBJECT(pad));
3247 gst_object_unref(GST_OBJECT(ghostpad));
3250 g_list_free(element_bucket);
3252 /* release element which are not added to bin */
3253 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3254 /* NOTE : skip bin */
3255 if (audiobin[i].gst) {
3256 GstObject *parent = NULL;
3257 parent = gst_element_get_parent(audiobin[i].gst);
3260 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3261 audiobin[i].gst = NULL;
3263 gst_object_unref(GST_OBJECT(parent));
3267 /* release audiobin with it's children */
3268 if (audiobin[MMPLAYER_A_BIN].gst)
3269 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3271 MMPLAYER_FREEIF(audiobin);
3273 player->pipeline->audiobin = NULL;
3275 return MM_ERROR_PLAYER_INTERNAL;
3279 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3281 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3285 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3287 int ret = MM_ERROR_NONE;
3289 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3290 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3292 MMPLAYER_VIDEO_BO_LOCK(player);
3294 if (player->video_bo_list) {
3295 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3296 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3297 if (tmp && tmp->bo == bo) {
3299 LOGD("release bo %p", bo);
3300 tbm_bo_unref(tmp->bo);
3301 MMPLAYER_VIDEO_BO_UNLOCK(player);
3302 MMPLAYER_VIDEO_BO_SIGNAL(player);
3307 /* hw codec is running or the list was reset for DRC. */
3308 LOGW("there is no bo list.");
3310 MMPLAYER_VIDEO_BO_UNLOCK(player);
3312 LOGW("failed to find bo %p", bo);
3316 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3322 tbm_bo_unref(tmp->bo);
3327 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3330 MMPLAYER_RETURN_IF_FAIL(player);
3332 MMPLAYER_VIDEO_BO_LOCK(player);
3333 if (player->video_bo_list) {
3334 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3335 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3336 player->video_bo_list = NULL;
3338 player->video_bo_size = 0;
3339 MMPLAYER_VIDEO_BO_UNLOCK(player);
3346 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3349 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3350 gboolean ret = TRUE;
3351 gint64 end_time = 0;
3353 /* check DRC, if it is, destroy the prev bo list to create again */
3354 if (player->video_bo_size != size) {
3355 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3356 __mmplayer_video_stream_destroy_bo_list(player);
3357 player->video_bo_size = size;
3360 MMPLAYER_VIDEO_BO_LOCK(player);
3362 if ((!player->video_bo_list) ||
3363 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3365 /* create bo list */
3367 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3369 if (player->video_bo_list) {
3370 /* if bo list did not created all, try it again. */
3371 idx = g_list_length(player->video_bo_list);
3372 LOGD("bo list exist(len: %d)", idx);
3375 for (; idx < player->ini.num_of_video_bo; idx++) {
3376 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3378 LOGE("Fail to alloc bo_info.");
3381 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3383 LOGE("Fail to tbm_bo_alloc.");
3384 MMPLAYER_FREEIF(bo_info);
3387 bo_info->used = FALSE;
3388 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3391 /* update video num buffers */
3392 LOGD("video_num_buffers : %d", idx);
3393 mm_player_set_attribute((MMHandleType)player, NULL,
3394 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3395 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3399 MMPLAYER_VIDEO_BO_UNLOCK(player);
3404 if (player->ini.video_bo_timeout > 0)
3405 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3408 /* get bo from list*/
3409 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3410 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3411 if (tmp && (tmp->used == FALSE)) {
3412 LOGD("found bo %p to use", tmp->bo);
3414 MMPLAYER_VIDEO_BO_UNLOCK(player);
3415 return tbm_bo_ref(tmp->bo);
3419 if (player->ini.video_bo_timeout <= 0) {
3420 MMPLAYER_VIDEO_BO_WAIT(player);
3422 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3424 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3430 MMPLAYER_VIDEO_BO_UNLOCK(player);
3435 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3437 mmplayer_t *player = (mmplayer_t *)data;
3439 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3441 /* send prerolled pkt */
3442 player->video_stream_prerolled = false;
3444 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3446 /* not to send prerolled pkt again */
3447 player->video_stream_prerolled = true;
3451 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3453 mmplayer_t *player = (mmplayer_t *)data;
3454 mmplayer_video_decoded_data_info_t *stream = NULL;
3455 GstMemory *mem = NULL;
3458 MMPLAYER_RETURN_IF_FAIL(player);
3459 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3461 if (player->video_stream_prerolled) {
3462 player->video_stream_prerolled = false;
3463 LOGD("skip the prerolled pkt not to send it again");
3467 /* clear stream data structure */
3468 stream = __mmplayer_create_stream_from_pad(pad);
3470 LOGE("failed to alloc stream");
3474 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3476 /* set size and timestamp */
3477 mem = gst_buffer_peek_memory(buffer, 0);
3478 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3479 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3481 /* check zero-copy */
3482 if (player->set_mode.video_zc &&
3483 player->set_mode.video_export &&
3484 gst_is_tizen_memory(mem)) {
3485 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3486 stream->internal_buffer = gst_buffer_ref(buffer);
3487 } else { /* sw codec */
3488 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3491 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3495 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3496 LOGE("failed to send video decoded data.");
3503 LOGE("release video stream resource.");
3504 if (gst_is_tizen_memory(mem)) {
3506 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3508 tbm_bo_unref(stream->bo[i]);
3511 /* unref gst buffer */
3512 if (stream->internal_buffer)
3513 gst_buffer_unref(stream->internal_buffer);
3516 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3518 MMPLAYER_FREEIF(stream);
3523 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3525 mmplayer_gst_element_t *videobin = NULL;
3528 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3530 videobin = player->pipeline->videobin;
3532 /* Set spatial media metadata and/or user settings to the element.
3534 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3535 "projection-type", player->video360_metadata.projection_type, NULL);
3537 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3538 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3540 if (player->video360_metadata.full_pano_width_pixels &&
3541 player->video360_metadata.full_pano_height_pixels &&
3542 player->video360_metadata.cropped_area_image_width &&
3543 player->video360_metadata.cropped_area_image_height) {
3544 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3545 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3546 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3547 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3548 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3549 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3550 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3554 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3555 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3556 "horizontal-fov", player->video360_horizontal_fov,
3557 "vertical-fov", player->video360_vertical_fov, NULL);
3560 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3561 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3562 "zoom", 1.0f / player->video360_zoom, NULL);
3565 if (player->video360_yaw_radians <= M_PI &&
3566 player->video360_yaw_radians >= -M_PI &&
3567 player->video360_pitch_radians <= M_PI_2 &&
3568 player->video360_pitch_radians >= -M_PI_2) {
3569 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3570 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3571 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3572 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3573 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3574 "pose-yaw", player->video360_metadata.init_view_heading,
3575 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3578 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3579 "passthrough", !player->is_video360_enabled, NULL);
3586 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3588 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3589 GList *element_bucket = NULL;
3592 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3594 /* create video360 filter */
3595 if (player->is_360_feature_enabled && player->is_content_spherical) {
3596 LOGD("create video360 element");
3597 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3598 __mmplayer_gst_set_video360_property(player);
3602 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3603 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3604 player->set_mode.video_zc) {
3605 LOGD("skip creating the videoconv and rotator");
3606 return MM_ERROR_NONE;
3609 /* in case of sw codec & overlay surface type, except 360 playback.
3610 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3611 LOGD("create video converter: %s", video_csc);
3612 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3615 *bucket = element_bucket;
3617 return MM_ERROR_NONE;
3619 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3620 g_list_free(element_bucket);
3624 return MM_ERROR_PLAYER_INTERNAL;
3628 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3630 gchar *factory_name = NULL;
3632 switch (surface_type) {
3633 case MM_DISPLAY_SURFACE_OVERLAY:
3635 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3636 if (strlen(player->ini.videosink_element_overlay) > 0)
3637 factory_name = player->ini.videosink_element_overlay;
3639 case MM_DISPLAY_SURFACE_REMOTE:
3641 case MM_DISPLAY_SURFACE_NULL:
3642 if (strlen(player->ini.videosink_element_fake) > 0)
3643 factory_name = player->ini.videosink_element_fake;
3646 LOGE("unidentified surface type");
3650 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3651 return factory_name;
3655 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3657 gchar *factory_name = NULL;
3658 mmplayer_gst_element_t *videobin = NULL;
3663 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3665 videobin = player->pipeline->videobin;
3666 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3668 attrs = MMPLAYER_GET_ATTRS(player);
3670 LOGE("cannot get content attribute");
3671 return MM_ERROR_PLAYER_INTERNAL;
3674 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3675 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3676 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3677 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3678 "use-tbm", use_tbm, NULL);
3681 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3682 return MM_ERROR_PLAYER_INTERNAL;
3684 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3687 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3688 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3691 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3693 LOGD("disable last-sample");
3694 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3697 if (player->set_mode.video_export) {
3699 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3700 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3701 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3703 _mmplayer_add_signal_connection(player,
3704 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3705 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3707 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3710 _mmplayer_add_signal_connection(player,
3711 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3712 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3714 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3718 if (videobin[MMPLAYER_V_SINK].gst) {
3719 GstPad *sink_pad = NULL;
3720 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3722 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3723 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3724 gst_object_unref(GST_OBJECT(sink_pad));
3726 LOGE("failed to get sink pad from videosink");
3730 return MM_ERROR_NONE;
3735 * - video overlay surface(arm/x86) : tizenwlsink
3738 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3741 GList *element_bucket = NULL;
3742 mmplayer_gst_element_t *first_element = NULL;
3743 mmplayer_gst_element_t *videobin = NULL;
3744 gchar *videosink_factory_name = NULL;
3747 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3750 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3752 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3754 player->pipeline->videobin = videobin;
3757 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3758 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3759 if (!videobin[MMPLAYER_V_BIN].gst) {
3760 LOGE("failed to create videobin");
3764 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3767 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3768 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3770 /* additional setting for sink plug-in */
3771 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3772 LOGE("failed to set video property");
3776 /* store it as it's sink element */
3777 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3779 /* adding created elements to bin */
3780 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3781 LOGE("failed to add elements");
3785 /* Linking elements in the bucket by added order */
3786 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3787 LOGE("failed to link elements");
3791 /* get first element's sinkpad for creating ghostpad */
3792 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3793 if (!first_element) {
3794 LOGE("failed to get first element from bucket");
3798 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3800 LOGE("failed to get pad from first element");
3804 /* create ghostpad */
3805 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3806 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3807 LOGE("failed to add ghostpad to videobin");
3810 gst_object_unref(pad);
3812 /* done. free allocated variables */
3813 g_list_free(element_bucket);
3817 return MM_ERROR_NONE;
3820 LOGE("ERROR : releasing videobin");
3821 g_list_free(element_bucket);
3824 gst_object_unref(GST_OBJECT(pad));
3826 /* release videobin with it's children */
3827 if (videobin[MMPLAYER_V_BIN].gst)
3828 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3830 MMPLAYER_FREEIF(videobin);
3831 player->pipeline->videobin = NULL;
3833 return MM_ERROR_PLAYER_INTERNAL;
3837 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3839 GList *element_bucket = NULL;
3840 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3842 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3843 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3844 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3845 "signal-handoffs", FALSE,
3848 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3849 _mmplayer_add_signal_connection(player,
3850 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3851 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3853 G_CALLBACK(__mmplayer_update_subtitle),
3856 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3857 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3859 if (!player->play_subtitle) {
3860 LOGD("add textbin sink as sink element of whole pipeline.");
3861 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3864 /* adding created elements to bin */
3865 LOGD("adding created elements to bin");
3866 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3867 LOGE("failed to add elements");
3871 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3872 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3873 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3875 /* linking elements in the bucket by added order. */
3876 LOGD("Linking elements in the bucket by added order.");
3877 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3878 LOGE("failed to link elements");
3882 if (textbin[MMPLAYER_T_QUEUE].gst) {
3884 GstPad *ghostpad = NULL;
3886 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3888 LOGE("failed to get sink pad of text queue");
3892 ghostpad = gst_ghost_pad_new("text_sink", pad);
3893 gst_object_unref(pad);
3896 LOGE("failed to create ghostpad of textbin");
3900 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3901 LOGE("failed to add ghostpad to textbin");
3902 gst_object_unref(ghostpad);
3907 g_list_free(element_bucket);
3909 return MM_ERROR_NONE;
3913 g_list_free(element_bucket);
3915 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3916 LOGE("remove textbin sink from sink list");
3917 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3920 /* release element at __mmplayer_gst_create_text_sink_bin */
3921 return MM_ERROR_PLAYER_INTERNAL;
3925 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3927 mmplayer_gst_element_t *textbin = NULL;
3928 int surface_type = 0;
3933 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3936 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3938 LOGE("failed to allocate memory for textbin");
3939 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3943 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3944 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3945 if (!textbin[MMPLAYER_T_BIN].gst) {
3946 LOGE("failed to create textbin");
3951 player->pipeline->textbin = textbin;
3954 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3955 LOGD("surface type for subtitle : %d", surface_type);
3956 switch (surface_type) {
3957 case MM_DISPLAY_SURFACE_OVERLAY:
3958 case MM_DISPLAY_SURFACE_NULL:
3959 case MM_DISPLAY_SURFACE_REMOTE:
3960 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3961 LOGE("failed to make plain text elements");
3972 return MM_ERROR_NONE;
3976 LOGD("ERROR : releasing textbin");
3978 /* release signal */
3979 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3981 /* release element which are not added to bin */
3982 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3983 /* NOTE : skip bin */
3984 if (textbin[i].gst) {
3985 GstObject *parent = NULL;
3986 parent = gst_element_get_parent(textbin[i].gst);
3989 gst_object_unref(GST_OBJECT(textbin[i].gst));
3990 textbin[i].gst = NULL;
3992 gst_object_unref(GST_OBJECT(parent));
3997 /* release textbin with it's children */
3998 if (textbin[MMPLAYER_T_BIN].gst)
3999 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4001 MMPLAYER_FREEIF(textbin);
4002 player->pipeline->textbin = NULL;
4005 return MM_ERROR_PLAYER_INTERNAL;
4009 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4011 mmplayer_gst_element_t *mainbin = NULL;
4012 mmplayer_gst_element_t *textbin = NULL;
4013 MMHandleType attrs = 0;
4014 GstElement *subsrc = NULL;
4015 GstElement *subparse = NULL;
4016 gchar *subtitle_uri = NULL;
4017 const gchar *charset = NULL;
4023 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4025 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4027 mainbin = player->pipeline->mainbin;
4029 attrs = MMPLAYER_GET_ATTRS(player);
4031 LOGE("cannot get content attribute");
4032 return MM_ERROR_PLAYER_INTERNAL;
4035 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4036 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4037 LOGE("subtitle uri is not proper filepath.");
4038 return MM_ERROR_PLAYER_INVALID_URI;
4041 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4042 LOGE("failed to get storage info of subtitle path");
4043 return MM_ERROR_PLAYER_INVALID_URI;
4046 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4048 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4049 player->subtitle_language_list = NULL;
4050 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4052 /* create the subtitle source */
4053 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4055 LOGE("failed to create filesrc element");
4058 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4060 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4061 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4063 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4064 LOGW("failed to add queue");
4065 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4066 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4067 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4072 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4074 LOGE("failed to create subparse element");
4078 charset = _mmplayer_get_charset(subtitle_uri);
4080 LOGD("detected charset is %s", charset);
4081 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4084 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4085 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4087 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4088 LOGW("failed to add subparse");
4089 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4090 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4091 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4095 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4096 LOGW("failed to link subsrc and subparse");
4100 player->play_subtitle = TRUE;
4101 player->adjust_subtitle_pos = 0;
4103 LOGD("play subtitle using subtitle file");
4105 if (player->pipeline->textbin == NULL) {
4106 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4107 LOGE("failed to create text sink bin. continuing without text");
4111 textbin = player->pipeline->textbin;
4113 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4114 LOGW("failed to add textbin");
4116 /* release signal */
4117 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4119 /* release textbin with it's children */
4120 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4121 MMPLAYER_FREEIF(player->pipeline->textbin);
4122 player->pipeline->textbin = textbin = NULL;
4126 LOGD("link text input selector and textbin ghost pad");
4128 player->textsink_linked = 1;
4129 player->external_text_idx = 0;
4130 LOGI("textsink is linked");
4132 textbin = player->pipeline->textbin;
4133 LOGD("text bin has been created. reuse it.");
4134 player->external_text_idx = 1;
4137 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4138 LOGW("failed to link subparse and textbin");
4142 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4144 LOGE("failed to get sink pad from textsink to probe data");
4148 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4149 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4151 gst_object_unref(pad);
4154 /* create dot. for debugging */
4155 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4158 return MM_ERROR_NONE;
4161 /* release text pipeline resource */
4162 player->textsink_linked = 0;
4164 /* release signal */
4165 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4167 if (player->pipeline->textbin) {
4168 LOGE("remove textbin");
4170 /* release textbin with it's children */
4171 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4172 MMPLAYER_FREEIF(player->pipeline->textbin);
4173 player->pipeline->textbin = NULL;
4177 /* release subtitle elem */
4178 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4179 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4181 return MM_ERROR_PLAYER_INTERNAL;
4185 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4187 mmplayer_t *player = (mmplayer_t *)data;
4188 MMMessageParamType msg = {0, };
4189 GstClockTime duration = 0;
4190 gpointer text = NULL;
4191 guint text_size = 0;
4192 gboolean ret = TRUE;
4193 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4197 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4198 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4200 if (player->is_subtitle_force_drop) {
4201 LOGW("subtitle is dropped forcedly.");
4205 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4206 text = mapinfo.data;
4207 text_size = mapinfo.size;
4209 if (player->set_mode.subtitle_off) {
4210 LOGD("subtitle is OFF.");
4214 if (!text || (text_size == 0)) {
4215 LOGD("There is no subtitle to be displayed.");
4219 msg.data = (void *)text;
4221 duration = GST_BUFFER_DURATION(buffer);
4223 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4224 if (player->duration > GST_BUFFER_PTS(buffer))
4225 duration = player->duration - GST_BUFFER_PTS(buffer);
4228 LOGI("subtitle duration is invalid, subtitle duration change "
4229 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4231 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4233 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4235 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4236 gst_buffer_unmap(buffer, &mapinfo);
4243 static GstPadProbeReturn
4244 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4246 mmplayer_t *player = (mmplayer_t *)u_data;
4247 GstClockTime cur_timestamp = 0;
4248 gint64 adjusted_timestamp = 0;
4249 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4251 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4253 if (player->set_mode.subtitle_off) {
4254 LOGD("subtitle is OFF.");
4258 if (player->adjust_subtitle_pos == 0) {
4259 LOGD("nothing to do");
4263 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4264 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4266 if (adjusted_timestamp < 0) {
4267 LOGD("adjusted_timestamp under zero");
4272 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4273 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4274 GST_TIME_ARGS(cur_timestamp),
4275 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4277 return GST_PAD_PROBE_OK;
4281 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4285 /* check player and subtitlebin are created */
4286 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4287 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4289 if (position == 0) {
4290 LOGD("nothing to do");
4292 return MM_ERROR_NONE;
4295 /* check current position */
4296 player->adjust_subtitle_pos = position;
4298 LOGD("save adjust_subtitle_pos in player");
4302 return MM_ERROR_NONE;
4306 * This function is to create audio or video pipeline for playing.
4308 * @param player [in] handle of player
4310 * @return This function returns zero on success.
4315 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4317 int ret = MM_ERROR_NONE;
4318 mmplayer_gst_element_t *mainbin = NULL;
4319 MMHandleType attrs = 0;
4322 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4324 /* get profile attribute */
4325 attrs = MMPLAYER_GET_ATTRS(player);
4327 LOGE("failed to get content attribute");
4331 /* create pipeline handles */
4332 if (player->pipeline) {
4333 LOGE("pipeline should be released before create new one");
4337 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4339 /* create mainbin */
4340 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4341 if (mainbin == NULL)
4344 /* create pipeline */
4345 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4346 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4347 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4348 LOGE("failed to create pipeline");
4353 player->pipeline->mainbin = mainbin;
4355 /* create the source and decoder elements */
4356 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4357 ret = _mmplayer_gst_build_es_pipeline(player);
4359 if (MMPLAYER_USE_DECODEBIN(player))
4360 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4362 ret = _mmplayer_gst_build_pipeline_with_src(player);
4365 if (ret != MM_ERROR_NONE) {
4366 LOGE("failed to create some elements");
4370 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4371 if (__mmplayer_check_subtitle(player)
4372 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4373 LOGE("failed to create text pipeline");
4376 ret = _mmplayer_gst_add_bus_watch(player);
4377 if (ret != MM_ERROR_NONE) {
4378 LOGE("failed to add bus watch");
4383 return MM_ERROR_NONE;
4386 _mmplayer_bus_watcher_remove(player);
4387 __mmplayer_gst_destroy_pipeline(player);
4388 return MM_ERROR_PLAYER_INTERNAL;
4392 __mmplayer_reset_gapless_state(mmplayer_t *player)
4395 MMPLAYER_RETURN_IF_FAIL(player
4397 && player->pipeline->audiobin
4398 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4400 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4407 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4410 int ret = MM_ERROR_NONE;
4414 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4416 /* cleanup stuffs */
4417 MMPLAYER_FREEIF(player->type);
4418 player->no_more_pad = FALSE;
4419 player->num_dynamic_pad = 0;
4421 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4422 player->subtitle_language_list = NULL;
4423 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4425 MMPLAYER_RECONFIGURE_LOCK(player);
4426 __mmplayer_reset_gapless_state(player);
4427 MMPLAYER_RECONFIGURE_UNLOCK(player);
4429 if (player->streamer) {
4430 _mm_player_streaming_initialize(player->streamer, FALSE);
4431 _mm_player_streaming_destroy(player->streamer);
4432 player->streamer = NULL;
4435 /* cleanup unlinked mime type */
4436 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4437 MMPLAYER_FREEIF(player->unlinked_video_mime);
4438 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4440 /* cleanup running stuffs */
4441 _mmplayer_cancel_eos_timer(player);
4443 /* cleanup gst stuffs */
4444 if (player->pipeline) {
4445 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4446 GstTagList *tag_list = player->pipeline->tag_list;
4448 /* first we need to disconnect all signal hander */
4449 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4452 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4453 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4454 gst_object_unref(bus);
4456 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4457 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4458 if (ret != MM_ERROR_NONE) {
4459 LOGE("fail to change state to NULL");
4460 return MM_ERROR_PLAYER_INTERNAL;
4463 LOGW("succeeded in changing state to NULL");
4465 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4468 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4469 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4471 MMPLAYER_FREEIF(player->pipeline->audiobin);
4472 MMPLAYER_FREEIF(player->pipeline->videobin);
4473 MMPLAYER_FREEIF(player->pipeline->textbin);
4474 MMPLAYER_FREEIF(mainbin);
4478 gst_tag_list_unref(tag_list);
4480 MMPLAYER_FREEIF(player->pipeline);
4482 MMPLAYER_FREEIF(player->album_art);
4484 if (player->type_caps) {
4485 gst_caps_unref(player->type_caps);
4486 player->type_caps = NULL;
4489 if (player->v_stream_caps) {
4490 gst_caps_unref(player->v_stream_caps);
4491 player->v_stream_caps = NULL;
4494 if (player->a_stream_caps) {
4495 gst_caps_unref(player->a_stream_caps);
4496 player->a_stream_caps = NULL;
4499 if (player->s_stream_caps) {
4500 gst_caps_unref(player->s_stream_caps);
4501 player->s_stream_caps = NULL;
4503 _mmplayer_track_destroy(player);
4505 if (player->sink_elements)
4506 g_list_free(player->sink_elements);
4507 player->sink_elements = NULL;
4509 if (player->bufmgr) {
4510 tbm_bufmgr_deinit(player->bufmgr);
4511 player->bufmgr = NULL;
4514 LOGW("finished destroy pipeline");
4522 __mmplayer_gst_realize(mmplayer_t *player)
4525 int ret = MM_ERROR_NONE;
4529 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4531 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4533 ret = __mmplayer_gst_create_pipeline(player);
4535 LOGE("failed to create pipeline");
4539 /* set pipeline state to READY */
4540 /* NOTE : state change to READY must be performed sync. */
4541 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4542 ret = _mmplayer_gst_set_state(player,
4543 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4545 if (ret != MM_ERROR_NONE) {
4546 /* return error if failed to set state */
4547 LOGE("failed to set READY state");
4551 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4553 /* create dot before error-return. for debugging */
4554 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4562 __mmplayer_gst_unrealize(mmplayer_t *player)
4564 int ret = MM_ERROR_NONE;
4568 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4570 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4571 MMPLAYER_PRINT_STATE(player);
4573 /* release miscellaneous information */
4574 __mmplayer_release_misc(player);
4576 /* destroy pipeline */
4577 ret = __mmplayer_gst_destroy_pipeline(player);
4578 if (ret != MM_ERROR_NONE) {
4579 LOGE("failed to destroy pipeline");
4583 /* release miscellaneous information.
4584 these info needs to be released after pipeline is destroyed. */
4585 __mmplayer_release_misc_post(player);
4587 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4595 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4600 LOGW("set_message_callback is called with invalid player handle");
4601 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4604 player->msg_cb = callback;
4605 player->msg_cb_param = user_param;
4607 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4611 return MM_ERROR_NONE;
4615 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4617 int ret = MM_ERROR_NONE;
4622 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4623 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4624 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4626 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4628 if (strstr(uri, "es_buff://")) {
4629 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4630 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4631 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4632 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4634 tmp = g_ascii_strdown(uri, strlen(uri));
4635 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4636 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4638 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4640 } else if (strstr(uri, "mms://")) {
4641 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4642 } else if ((path = strstr(uri, "mem://"))) {
4643 ret = __mmplayer_set_mem_uri(data, path, param);
4645 ret = __mmplayer_set_file_uri(data, uri);
4648 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4649 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4650 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4651 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4653 /* dump parse result */
4654 SECURE_LOGW("incoming uri : %s", uri);
4655 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4656 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4664 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4667 mmplayer_t *player = NULL;
4668 MMMessageParamType msg = {0, };
4670 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4675 LOGE("user_data is null");
4679 player = (mmplayer_t *)user_data;
4681 if (!player->pipeline || !player->attrs) {
4682 LOGW("not initialized");
4686 LOGD("cmd lock player, cmd state : %d", player->cmd);
4687 MMPLAYER_CMD_LOCK(player);
4688 LOGD("cmd locked player");
4690 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4691 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4692 LOGW("player already destroyed");
4693 MMPLAYER_CMD_UNLOCK(player);
4697 player->interrupted_by_resource = TRUE;
4699 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4701 /* get last play position */
4702 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4703 msg.union_type = MM_MSG_UNION_TIME;
4704 msg.time.elapsed = pos;
4705 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4707 LOGW("failed to get play position.");
4710 LOGD("video resource conflict so, resource will be freed by unrealizing");
4711 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4712 LOGE("failed to unrealize");
4714 MMPLAYER_CMD_UNLOCK(player);
4716 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4717 player->hw_resource[res_idx] = NULL;
4721 return TRUE; /* release all the resources */
4725 __mmplayer_initialize_video_roi(mmplayer_t *player)
4727 player->video_roi.scale_x = 0.0;
4728 player->video_roi.scale_y = 0.0;
4729 player->video_roi.scale_width = 1.0;
4730 player->video_roi.scale_height = 1.0;
4734 _mmplayer_create_player(MMHandleType handle)
4736 int ret = MM_ERROR_PLAYER_INTERNAL;
4737 bool enabled = false;
4739 mmplayer_t *player = MM_PLAYER_CAST(handle);
4743 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4745 /* initialize player state */
4746 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4747 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4748 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4749 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4751 /* check current state */
4752 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4754 /* construct attributes */
4755 player->attrs = _mmplayer_construct_attribute(handle);
4757 if (!player->attrs) {
4758 LOGE("Failed to construct attributes");
4762 /* initialize gstreamer with configured parameter */
4763 if (!__mmplayer_init_gstreamer(player)) {
4764 LOGE("Initializing gstreamer failed");
4765 _mmplayer_deconstruct_attribute(handle);
4769 /* create lock. note that g_tread_init() has already called in gst_init() */
4770 g_mutex_init(&player->fsink_lock);
4772 /* create update tag lock */
4773 g_mutex_init(&player->update_tag_lock);
4775 /* create gapless play mutex */
4776 g_mutex_init(&player->gapless_play_thread_mutex);
4778 /* create gapless play cond */
4779 g_cond_init(&player->gapless_play_thread_cond);
4781 /* create gapless play thread */
4782 player->gapless_play_thread =
4783 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4784 if (!player->gapless_play_thread) {
4785 LOGE("failed to create gapless play thread");
4786 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4787 g_mutex_clear(&player->gapless_play_thread_mutex);
4788 g_cond_clear(&player->gapless_play_thread_cond);
4792 player->bus_msg_q = g_queue_new();
4793 if (!player->bus_msg_q) {
4794 LOGE("failed to create queue for bus_msg");
4795 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4799 ret = _mmplayer_initialize_video_capture(player);
4800 if (ret != MM_ERROR_NONE) {
4801 LOGW("video capture is not supported");
4802 /* do not handle as error for headless profile */
4805 /* initialize resource manager */
4806 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4807 __resource_release_cb, player, &player->resource_manager)
4808 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4809 LOGE("failed to create resource manager");
4810 ret = MM_ERROR_PLAYER_INTERNAL;
4814 /* create video bo lock and cond */
4815 g_mutex_init(&player->video_bo_mutex);
4816 g_cond_init(&player->video_bo_cond);
4818 /* create subtitle info lock and cond */
4819 g_mutex_init(&player->subtitle_info_mutex);
4820 g_cond_init(&player->subtitle_info_cond);
4822 player->streaming_type = STREAMING_SERVICE_NONE;
4824 /* give default value of audio effect setting */
4825 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4826 player->sound.rg_enable = false;
4827 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4829 player->play_subtitle = FALSE;
4830 player->has_closed_caption = FALSE;
4831 player->pending_resume = FALSE;
4832 if (player->ini.dump_element_keyword[0][0] == '\0')
4833 player->ini.set_dump_element_flag = FALSE;
4835 player->ini.set_dump_element_flag = TRUE;
4837 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4838 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4839 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4841 /* Set video360 settings to their defaults for just-created player.
4844 player->is_360_feature_enabled = FALSE;
4845 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4846 LOGI("spherical feature info: %d", enabled);
4848 player->is_360_feature_enabled = TRUE;
4850 LOGE("failed to get spherical feature info");
4853 player->is_content_spherical = FALSE;
4854 player->is_video360_enabled = TRUE;
4855 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4856 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4857 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4858 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4859 player->video360_zoom = 1.0f;
4860 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4861 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4863 __mmplayer_initialize_video_roi(player);
4865 /* set player state to null */
4866 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4867 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4871 return MM_ERROR_NONE;
4875 g_mutex_clear(&player->fsink_lock);
4876 /* free update tag lock */
4877 g_mutex_clear(&player->update_tag_lock);
4878 g_queue_free(player->bus_msg_q);
4879 player->bus_msg_q = NULL;
4880 /* free gapless play thread */
4881 if (player->gapless_play_thread) {
4882 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4883 player->gapless_play_thread_exit = TRUE;
4884 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4885 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4887 g_thread_join(player->gapless_play_thread);
4888 player->gapless_play_thread = NULL;
4890 g_mutex_clear(&player->gapless_play_thread_mutex);
4891 g_cond_clear(&player->gapless_play_thread_cond);
4894 /* release attributes */
4895 _mmplayer_deconstruct_attribute(handle);
4903 __mmplayer_init_gstreamer(mmplayer_t *player)
4905 static gboolean initialized = FALSE;
4906 static const int max_argc = 50;
4908 gchar **argv = NULL;
4909 gchar **argv2 = NULL;
4915 LOGD("gstreamer already initialized.");
4920 argc = malloc(sizeof(int));
4921 argv = malloc(sizeof(gchar *) * max_argc);
4922 argv2 = malloc(sizeof(gchar *) * max_argc);
4924 if (!argc || !argv || !argv2)
4927 memset(argv, 0, sizeof(gchar *) * max_argc);
4928 memset(argv2, 0, sizeof(gchar *) * max_argc);
4932 argv[0] = g_strdup("mmplayer");
4935 for (i = 0; i < 5; i++) {
4936 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4937 if (strlen(player->ini.gst_param[i]) > 0) {
4938 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4943 /* we would not do fork for scanning plugins */
4944 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4947 /* check disable registry scan */
4948 if (player->ini.skip_rescan) {
4949 argv[*argc] = g_strdup("--gst-disable-registry-update");
4953 /* check disable segtrap */
4954 if (player->ini.disable_segtrap) {
4955 argv[*argc] = g_strdup("--gst-disable-segtrap");
4959 LOGD("initializing gstreamer with following parameter");
4960 LOGD("argc : %d", *argc);
4963 for (i = 0; i < arg_count; i++) {
4965 LOGD("argv[%d] : %s", i, argv2[i]);
4968 /* initializing gstreamer */
4969 if (!gst_init_check(argc, &argv, &err)) {
4970 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4977 for (i = 0; i < arg_count; i++) {
4979 LOGD("release - argv[%d] : %s", i, argv2[i]);
4981 MMPLAYER_FREEIF(argv2[i]);
4984 MMPLAYER_FREEIF(argv);
4985 MMPLAYER_FREEIF(argv2);
4986 MMPLAYER_FREEIF(argc);
4996 for (i = 0; i < arg_count; i++) {
4997 LOGD("free[%d] : %s", i, argv2[i]);
4998 MMPLAYER_FREEIF(argv2[i]);
5001 MMPLAYER_FREEIF(argv);
5002 MMPLAYER_FREEIF(argv2);
5003 MMPLAYER_FREEIF(argc);
5009 __mmplayer_check_async_state_transition(mmplayer_t *player)
5011 GstState element_state = GST_STATE_VOID_PENDING;
5012 GstState element_pending_state = GST_STATE_VOID_PENDING;
5013 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5014 GstElement *element = NULL;
5015 gboolean async = FALSE;
5017 /* check player handle */
5018 MMPLAYER_RETURN_IF_FAIL(player &&
5020 player->pipeline->mainbin &&
5021 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5024 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5026 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5027 LOGD("don't need to check the pipeline state");
5031 MMPLAYER_PRINT_STATE(player);
5033 /* wait for state transition */
5034 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5035 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5037 if (ret == GST_STATE_CHANGE_FAILURE) {
5038 LOGE(" [%s] state : %s pending : %s",
5039 GST_ELEMENT_NAME(element),
5040 gst_element_state_get_name(element_state),
5041 gst_element_state_get_name(element_pending_state));
5043 /* dump state of all element */
5044 _mmplayer_dump_pipeline_state(player);
5049 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5054 _mmplayer_destroy(MMHandleType handle)
5056 mmplayer_t *player = MM_PLAYER_CAST(handle);
5060 /* check player handle */
5061 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5063 /* destroy can called at anytime */
5064 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5066 /* check async state transition */
5067 __mmplayer_check_async_state_transition(player);
5069 /* release gapless play thread */
5070 if (player->gapless_play_thread) {
5071 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5072 player->gapless_play_thread_exit = TRUE;
5073 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5074 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5076 LOGD("waiting for gapless play thread exit");
5077 g_thread_join(player->gapless_play_thread);
5078 g_mutex_clear(&player->gapless_play_thread_mutex);
5079 g_cond_clear(&player->gapless_play_thread_cond);
5080 LOGD("gapless play thread released");
5083 _mmplayer_release_video_capture(player);
5085 /* release miscellaneous information */
5086 __mmplayer_release_misc(player);
5088 /* release pipeline */
5089 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5090 LOGE("failed to destroy pipeline");
5091 return MM_ERROR_PLAYER_INTERNAL;
5094 __mmplayer_destroy_hw_resource(player);
5096 g_queue_free(player->bus_msg_q);
5098 /* release subtitle info lock and cond */
5099 g_mutex_clear(&player->subtitle_info_mutex);
5100 g_cond_clear(&player->subtitle_info_cond);
5102 __mmplayer_release_dump_list(player->dump_list);
5104 /* release miscellaneous information.
5105 these info needs to be released after pipeline is destroyed. */
5106 __mmplayer_release_misc_post(player);
5108 /* release attributes */
5109 _mmplayer_deconstruct_attribute(handle);
5111 if (player->uri_info.uri_list) {
5112 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5113 player->uri_info.uri_list = NULL;
5117 g_mutex_clear(&player->fsink_lock);
5120 g_mutex_clear(&player->update_tag_lock);
5122 /* release video bo lock and cond */
5123 g_mutex_clear(&player->video_bo_mutex);
5124 g_cond_clear(&player->video_bo_cond);
5128 return MM_ERROR_NONE;
5132 _mmplayer_realize(MMHandleType hplayer)
5134 mmplayer_t *player = (mmplayer_t *)hplayer;
5135 int ret = MM_ERROR_NONE;
5138 MMHandleType attrs = 0;
5142 /* check player handle */
5143 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5145 /* check current state */
5146 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5148 attrs = MMPLAYER_GET_ATTRS(player);
5150 LOGE("fail to get attributes.");
5151 return MM_ERROR_PLAYER_INTERNAL;
5153 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5154 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5156 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5157 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5159 if (ret != MM_ERROR_NONE) {
5160 LOGE("failed to parse profile");
5165 if (uri && (strstr(uri, "es_buff://"))) {
5166 if (strstr(uri, "es_buff://push_mode"))
5167 player->es_player_push_mode = TRUE;
5169 player->es_player_push_mode = FALSE;
5172 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5173 LOGW("mms protocol is not supported format.");
5174 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5177 if (MMPLAYER_IS_STREAMING(player))
5178 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5180 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5182 player->smooth_streaming = FALSE;
5183 player->videodec_linked = 0;
5184 player->audiodec_linked = 0;
5185 player->textsink_linked = 0;
5186 player->is_external_subtitle_present = FALSE;
5187 player->is_external_subtitle_added_now = FALSE;
5188 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5189 player->video360_metadata.is_spherical = -1;
5190 player->is_openal_plugin_used = FALSE;
5191 player->subtitle_language_list = NULL;
5192 player->is_subtitle_force_drop = FALSE;
5194 _mmplayer_track_initialize(player);
5195 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5197 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5198 gint prebuffer_ms = 0, rebuffer_ms = 0;
5200 player->streamer = _mm_player_streaming_create();
5201 _mm_player_streaming_initialize(player->streamer, TRUE);
5203 mm_attrs_multiple_get(player->attrs, NULL,
5204 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5205 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5207 if (prebuffer_ms > 0) {
5208 prebuffer_ms = MAX(prebuffer_ms, 1000);
5209 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5212 if (rebuffer_ms > 0) {
5213 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5214 rebuffer_ms = MAX(rebuffer_ms, 1000);
5215 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5218 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5219 player->streamer->buffering_req.rebuffer_time);
5222 /* realize pipeline */
5223 ret = __mmplayer_gst_realize(player);
5224 if (ret != MM_ERROR_NONE)
5225 LOGE("fail to realize the player.");
5227 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5235 _mmplayer_unrealize(MMHandleType hplayer)
5237 mmplayer_t *player = (mmplayer_t *)hplayer;
5238 int ret = MM_ERROR_NONE;
5239 int rm_ret = MM_ERROR_NONE;
5240 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5244 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5246 MMPLAYER_CMD_UNLOCK(player);
5247 _mmplayer_bus_watcher_remove(player);
5248 /* destroy the gst bus msg thread which is created during realize.
5249 this funct have to be called before getting cmd lock. */
5250 _mmplayer_bus_msg_thread_destroy(player);
5251 MMPLAYER_CMD_LOCK(player);
5253 /* check current state */
5254 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5256 /* check async state transition */
5257 __mmplayer_check_async_state_transition(player);
5259 /* unrealize pipeline */
5260 ret = __mmplayer_gst_unrealize(player);
5262 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5263 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5264 if (rm_ret != MM_ERROR_NONE)
5265 LOGE("failed to release [%d] resources", res_idx);
5268 player->interrupted_by_resource = FALSE;
5275 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5277 mmplayer_t *player = (mmplayer_t *)hplayer;
5279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5281 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5285 _mmplayer_get_state(MMHandleType hplayer, int *state)
5287 mmplayer_t *player = (mmplayer_t *)hplayer;
5289 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5291 *state = MMPLAYER_CURRENT_STATE(player);
5293 return MM_ERROR_NONE;
5297 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5299 GstElement *vol_element = NULL;
5300 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5303 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5304 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5306 /* check pipeline handle */
5307 if (!player->pipeline || !player->pipeline->audiobin) {
5308 LOGD("'%s' will be applied when audiobin is created", prop_name);
5310 /* NOTE : stored value will be used in create_audiobin
5311 * returning MM_ERROR_NONE here makes application to able to
5312 * set audio volume or mute at anytime.
5314 return MM_ERROR_NONE;
5317 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5318 volume_elem_id = MMPLAYER_A_SINK;
5320 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5322 LOGE("failed to get vol element %d", volume_elem_id);
5323 return MM_ERROR_PLAYER_INTERNAL;
5326 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5328 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5329 LOGE("there is no '%s' property", prop_name);
5330 return MM_ERROR_PLAYER_INTERNAL;
5333 if (!strcmp(prop_name, "volume")) {
5334 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5335 } else if (!strcmp(prop_name, "mute")) {
5336 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5338 LOGE("invalid property %s", prop_name);
5339 return MM_ERROR_PLAYER_INTERNAL;
5342 return MM_ERROR_NONE;
5346 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5348 int ret = MM_ERROR_NONE;
5349 mmplayer_t *player = (mmplayer_t *)hplayer;
5352 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5354 LOGD("volume = %f", volume);
5356 /* invalid factor range or not */
5357 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5358 LOGE("Invalid volume value");
5359 return MM_ERROR_INVALID_ARGUMENT;
5362 player->sound.volume = volume;
5364 ret = __mmplayer_gst_set_volume_property(player, "volume");
5371 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5373 mmplayer_t *player = (mmplayer_t *)hplayer;
5377 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5378 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5380 *volume = player->sound.volume;
5382 LOGD("current vol = %f", *volume);
5385 return MM_ERROR_NONE;
5389 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5391 int ret = MM_ERROR_NONE;
5392 mmplayer_t *player = (mmplayer_t *)hplayer;
5395 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5397 LOGD("mute = %d", mute);
5399 player->sound.mute = mute;
5401 ret = __mmplayer_gst_set_volume_property(player, "mute");
5408 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5410 mmplayer_t *player = (mmplayer_t *)hplayer;
5414 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5415 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5417 *mute = player->sound.mute;
5419 LOGD("current mute = %d", *mute);
5423 return MM_ERROR_NONE;
5427 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5429 mmplayer_t *player = (mmplayer_t *)hplayer;
5433 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5435 player->audio_stream_changed_cb = callback;
5436 player->audio_stream_changed_cb_user_param = user_param;
5437 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5441 return MM_ERROR_NONE;
5445 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5447 mmplayer_t *player = (mmplayer_t *)hplayer;
5451 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5453 player->audio_decoded_cb = callback;
5454 player->audio_decoded_cb_user_param = user_param;
5455 player->audio_extract_opt = opt;
5456 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5460 return MM_ERROR_NONE;
5464 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5466 mmplayer_t *player = (mmplayer_t *)hplayer;
5470 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5472 if (callback && !player->bufmgr)
5473 player->bufmgr = tbm_bufmgr_init(-1);
5475 player->set_mode.video_export = (callback) ? true : false;
5476 player->video_decoded_cb = callback;
5477 player->video_decoded_cb_user_param = user_param;
5479 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5483 return MM_ERROR_NONE;
5487 _mmplayer_start(MMHandleType hplayer)
5489 mmplayer_t *player = (mmplayer_t *)hplayer;
5490 gint ret = MM_ERROR_NONE;
5494 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5496 /* check current state */
5497 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5499 /* start pipeline */
5500 ret = _mmplayer_gst_start(player);
5501 if (ret != MM_ERROR_NONE)
5502 LOGE("failed to start player.");
5504 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5505 LOGD("force playing start even during buffering");
5506 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5514 /* NOTE: post "not supported codec message" to application
5515 * when one codec is not found during AUTOPLUGGING in MSL.
5516 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5517 * And, if any codec is not found, don't send message here.
5518 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5521 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5523 MMMessageParamType msg_param;
5524 memset(&msg_param, 0, sizeof(MMMessageParamType));
5525 gboolean post_msg_direct = FALSE;
5529 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5531 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5532 player->not_supported_codec, player->can_support_codec);
5534 if (player->not_found_demuxer) {
5535 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5536 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5538 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5539 MMPLAYER_FREEIF(msg_param.data);
5541 return MM_ERROR_NONE;
5544 if (player->not_supported_codec) {
5545 if (player->can_support_codec) {
5546 // There is one codec to play
5547 post_msg_direct = TRUE;
5549 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5550 post_msg_direct = TRUE;
5553 if (post_msg_direct) {
5554 MMMessageParamType msg_param;
5555 memset(&msg_param, 0, sizeof(MMMessageParamType));
5557 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5558 LOGW("not found AUDIO codec, posting error code to application.");
5560 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5561 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5562 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5563 LOGW("not found VIDEO codec, posting error code to application.");
5565 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5566 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5569 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5571 MMPLAYER_FREEIF(msg_param.data);
5573 return MM_ERROR_NONE;
5575 // no any supported codec case
5576 LOGW("not found any codec, posting error code to application.");
5578 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5579 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5580 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5582 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5583 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5586 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5588 MMPLAYER_FREEIF(msg_param.data);
5594 return MM_ERROR_NONE;
5597 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5599 GstState element_state = GST_STATE_VOID_PENDING;
5600 GstState element_pending_state = GST_STATE_VOID_PENDING;
5601 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5602 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5604 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5606 MMPLAYER_RECONFIGURE_LOCK(player);
5607 if (!player->gapless.reconfigure) {
5608 MMPLAYER_RECONFIGURE_UNLOCK(player);
5612 LOGI("reconfigure is under process");
5613 MMPLAYER_RECONFIGURE_WAIT(player);
5614 MMPLAYER_RECONFIGURE_UNLOCK(player);
5615 LOGI("reconfigure is completed.");
5617 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5618 &element_state, &element_pending_state, timeout * GST_SECOND);
5619 if (result == GST_STATE_CHANGE_FAILURE)
5620 LOGW("failed to get pipeline state in %d sec", timeout);
5625 /* NOTE : it should be able to call 'stop' anytime*/
5627 _mmplayer_stop(MMHandleType hplayer)
5629 mmplayer_t *player = (mmplayer_t *)hplayer;
5630 int ret = MM_ERROR_NONE;
5634 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5636 /* check current state */
5637 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5639 /* need to wait till the rebuilding pipeline is completed */
5640 __mmplayer_check_pipeline_reconfigure_state(player);
5641 MMPLAYER_RECONFIGURE_LOCK(player);
5642 __mmplayer_reset_gapless_state(player);
5643 MMPLAYER_RECONFIGURE_UNLOCK(player);
5645 /* NOTE : application should not wait for EOS after calling STOP */
5646 _mmplayer_cancel_eos_timer(player);
5649 player->seek_state = MMPLAYER_SEEK_NONE;
5652 ret = _mmplayer_gst_stop(player);
5654 if (ret != MM_ERROR_NONE)
5655 LOGE("failed to stop player.");
5663 _mmplayer_pause(MMHandleType hplayer)
5665 mmplayer_t *player = (mmplayer_t *)hplayer;
5666 gint64 pos_nsec = 0;
5667 gboolean async = FALSE;
5668 gint ret = MM_ERROR_NONE;
5672 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5674 /* check current state */
5675 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5677 /* check pipeline reconfigure state */
5678 __mmplayer_check_pipeline_reconfigure_state(player);
5680 switch (MMPLAYER_CURRENT_STATE(player)) {
5681 case MM_PLAYER_STATE_READY:
5683 /* check prepare async or not.
5684 * In the case of streaming playback, it's recommended to avoid blocking wait.
5686 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5687 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5689 /* Changing back sync of rtspsrc to async */
5690 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5691 LOGD("async prepare working mode for rtsp");
5697 case MM_PLAYER_STATE_PLAYING:
5699 /* NOTE : store current point to overcome some bad operation
5700 *(returning zero when getting current position in paused state) of some
5703 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5704 LOGW("getting current position failed in paused");
5706 player->last_position = pos_nsec;
5708 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5709 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5710 This causes problem is position calculation during normal pause resume scenarios also.
5711 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5712 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5713 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5714 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5720 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5721 LOGD("doing async pause in case of ms buff src");
5725 /* pause pipeline */
5726 ret = _mmplayer_gst_pause(player, async);
5727 if (ret != MM_ERROR_NONE) {
5728 LOGE("failed to pause player. ret : 0x%x", ret);
5729 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5733 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5734 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5735 LOGE("failed to update display_rotation");
5739 return MM_ERROR_NONE;
5742 /* in case of streaming, pause could take long time.*/
5744 _mmplayer_abort_pause(MMHandleType hplayer)
5746 mmplayer_t *player = (mmplayer_t *)hplayer;
5747 int ret = MM_ERROR_NONE;
5751 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5753 player->pipeline->mainbin,
5754 MM_ERROR_PLAYER_NOT_INITIALIZED);
5756 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5757 LOGD("set the videobin state to READY");
5758 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5759 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5763 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5764 LOGD("set the audiobin state to READY");
5765 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5766 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5770 LOGD("set the pipeline state to READY");
5771 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5772 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5774 if (ret != MM_ERROR_NONE) {
5775 LOGE("fail to change state to READY");
5776 return MM_ERROR_PLAYER_INTERNAL;
5779 LOGD("succeeded in changing state to READY");
5784 _mmplayer_resume(MMHandleType hplayer)
5786 mmplayer_t *player = (mmplayer_t *)hplayer;
5787 int ret = MM_ERROR_NONE;
5788 gboolean async = FALSE;
5792 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5794 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5795 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5796 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5800 /* Changing back sync mode rtspsrc to async */
5801 LOGD("async resume for rtsp case");
5805 /* check current state */
5806 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5808 ret = _mmplayer_gst_resume(player, async);
5809 if (ret != MM_ERROR_NONE)
5810 LOGE("failed to resume player.");
5812 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5813 LOGD("force resume even during buffering");
5814 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5823 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5825 mmplayer_t *player = (mmplayer_t *)hplayer;
5826 gint64 pos_nsec = 0;
5827 int ret = MM_ERROR_NONE;
5829 signed long long start = 0, stop = 0;
5830 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5833 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5834 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5836 /* The sound of video is not supported under 0.0 and over 2.0. */
5837 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5838 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5841 _mmplayer_set_mute(hplayer, mute);
5843 if (player->playback_rate == rate)
5844 return MM_ERROR_NONE;
5846 /* If the position is reached at start potion during fast backward, EOS is posted.
5847 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5849 player->playback_rate = rate;
5851 current_state = MMPLAYER_CURRENT_STATE(player);
5853 if (current_state != MM_PLAYER_STATE_PAUSED)
5854 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5856 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5858 if ((current_state == MM_PLAYER_STATE_PAUSED)
5859 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5860 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5861 pos_nsec = player->last_position;
5866 stop = GST_CLOCK_TIME_NONE;
5868 start = GST_CLOCK_TIME_NONE;
5872 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5873 player->playback_rate,
5875 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5876 GST_SEEK_TYPE_SET, start,
5877 GST_SEEK_TYPE_SET, stop)) {
5878 LOGE("failed to set speed playback");
5879 return MM_ERROR_PLAYER_SEEK;
5882 LOGD("succeeded to set speed playback as %0.1f", rate);
5886 return MM_ERROR_NONE;;
5890 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5892 mmplayer_t *player = (mmplayer_t *)hplayer;
5893 int ret = MM_ERROR_NONE;
5897 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5899 /* check pipeline reconfigure state */
5900 __mmplayer_check_pipeline_reconfigure_state(player);
5902 ret = _mmplayer_gst_set_position(player, position, FALSE);
5910 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5912 mmplayer_t *player = (mmplayer_t *)hplayer;
5913 int ret = MM_ERROR_NONE;
5915 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5916 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5918 if (g_strrstr(player->type, "video/mpegts"))
5919 __mmplayer_update_duration_value(player);
5921 *duration = player->duration;
5926 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5928 mmplayer_t *player = (mmplayer_t *)hplayer;
5929 int ret = MM_ERROR_NONE;
5931 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5933 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5939 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5941 mmplayer_t *player = (mmplayer_t *)hplayer;
5942 int ret = MM_ERROR_NONE;
5946 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5948 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5956 __mmplayer_is_midi_type(gchar *str_caps)
5958 if ((g_strrstr(str_caps, "audio/midi")) ||
5959 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5960 (g_strrstr(str_caps, "application/x-smaf")) ||
5961 (g_strrstr(str_caps, "audio/x-imelody")) ||
5962 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5963 (g_strrstr(str_caps, "audio/xmf")) ||
5964 (g_strrstr(str_caps, "audio/mxmf"))) {
5973 __mmplayer_is_only_mp3_type(gchar *str_caps)
5975 if (g_strrstr(str_caps, "application/x-id3") ||
5976 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5982 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5984 GstStructure *caps_structure = NULL;
5985 gint samplerate = 0;
5989 MMPLAYER_RETURN_IF_FAIL(player && caps);
5991 caps_structure = gst_caps_get_structure(caps, 0);
5993 /* set stream information */
5994 gst_structure_get_int(caps_structure, "rate", &samplerate);
5995 gst_structure_get_int(caps_structure, "channels", &channels);
5997 mm_player_set_attribute((MMHandleType)player, NULL,
5998 "content_audio_samplerate", samplerate,
5999 "content_audio_channels", channels, NULL);
6001 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6005 __mmplayer_update_content_type_info(mmplayer_t *player)
6008 MMPLAYER_RETURN_IF_FAIL(player && player->type);
6010 if (__mmplayer_is_midi_type(player->type)) {
6011 player->bypass_audio_effect = TRUE;
6015 if (!player->streamer) {
6016 LOGD("no need to check streaming type");
6020 if (g_strrstr(player->type, "application/x-hls")) {
6021 /* If it can't know exact type when it parses uri because of redirection case,
6022 * it will be fixed by typefinder or when doing autoplugging.
6024 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6025 player->streamer->is_adaptive_streaming = TRUE;
6026 } else if (g_strrstr(player->type, "application/dash+xml")) {
6027 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6028 player->streamer->is_adaptive_streaming = TRUE;
6031 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6032 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
6033 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6035 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6036 if (player->streamer->is_adaptive_streaming)
6037 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6039 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6043 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6048 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6049 GstCaps *caps, gpointer data)
6051 mmplayer_t *player = (mmplayer_t *)data;
6055 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6057 /* store type string */
6058 if (player->type_caps) {
6059 gst_caps_unref(player->type_caps);
6060 player->type_caps = NULL;
6063 player->type_caps = gst_caps_copy(caps);
6064 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
6066 MMPLAYER_FREEIF(player->type);
6067 player->type = gst_caps_to_string(caps);
6069 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6070 player, player->type, probability, gst_caps_get_size(caps));
6072 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6073 (g_strrstr(player->type, "audio/x-raw-int"))) {
6074 LOGE("not support media format");
6076 if (player->msg_posted == FALSE) {
6077 MMMessageParamType msg_param;
6078 memset(&msg_param, 0, sizeof(MMMessageParamType));
6080 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6081 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6083 /* don't post more if one was sent already */
6084 player->msg_posted = TRUE;
6089 __mmplayer_update_content_type_info(player);
6091 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6094 pad = gst_element_get_static_pad(tf, "src");
6096 LOGE("fail to get typefind src pad.");
6100 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6101 gboolean async = FALSE;
6102 LOGE("failed to autoplug %s", player->type);
6104 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6106 if (async && player->msg_posted == FALSE)
6107 __mmplayer_handle_missed_plugin(player);
6109 gst_object_unref(GST_OBJECT(pad));
6116 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6118 GstElement *decodebin = NULL;
6122 /* create decodebin */
6123 decodebin = gst_element_factory_make("decodebin", NULL);
6126 LOGE("fail to create decodebin");
6130 /* raw pad handling signal */
6131 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6132 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6134 /* no-more-pad pad handling signal */
6135 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6136 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6138 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6139 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6141 /* This signal is emitted when a pad for which there is no further possible
6142 decoding is added to the decodebin.*/
6143 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6144 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6146 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6147 before looking for any elements that can handle that stream.*/
6148 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6149 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6151 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6152 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6153 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6155 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6156 before looking for any elements that can handle that stream.*/
6157 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6158 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6160 /* This signal is emitted once decodebin has finished decoding all the data.*/
6161 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6162 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6164 /* This signal is emitted when a element is added to the bin.*/
6165 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6166 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6173 __mmplayer_gst_make_queue2(mmplayer_t *player)
6175 GstElement *queue2 = NULL;
6176 gint64 dur_bytes = 0L;
6177 mmplayer_gst_element_t *mainbin = NULL;
6178 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6181 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6183 mainbin = player->pipeline->mainbin;
6185 queue2 = gst_element_factory_make("queue2", "queue2");
6187 LOGE("failed to create buffering queue element");
6191 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6192 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6194 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6196 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6197 * skip the pull mode(file or ring buffering) setting. */
6198 if (dur_bytes > 0) {
6199 if (!g_strrstr(player->type, "video/mpegts")) {
6200 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6201 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6207 _mm_player_streaming_set_queue2(player->streamer,
6211 (guint64)dur_bytes); /* no meaning at the moment */
6217 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6219 mmplayer_gst_element_t *mainbin = NULL;
6220 GstElement *decodebin = NULL;
6221 GstElement *queue2 = NULL;
6222 GstPad *sinkpad = NULL;
6223 GstPad *qsrcpad = NULL;
6226 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6228 mainbin = player->pipeline->mainbin;
6230 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6232 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6233 LOGW("need to check: muxed buffer is not null");
6236 queue2 = __mmplayer_gst_make_queue2(player);
6238 LOGE("failed to make queue2");
6242 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6243 LOGE("failed to add buffering queue");
6247 sinkpad = gst_element_get_static_pad(queue2, "sink");
6248 qsrcpad = gst_element_get_static_pad(queue2, "src");
6250 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6251 LOGE("failed to link [%s:%s]-[%s:%s]",
6252 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6256 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6257 LOGE("failed to sync queue2 state with parent");
6261 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6262 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6266 gst_object_unref(GST_OBJECT(sinkpad));
6270 /* create decodebin */
6271 decodebin = _mmplayer_gst_make_decodebin(player);
6273 LOGE("failed to make decodebin");
6277 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6278 LOGE("failed to add decodebin");
6282 /* to force caps on the decodebin element and avoid reparsing stuff by
6283 * typefind. It also avoids a deadlock in the way typefind activates pads in
6284 * the state change */
6285 g_object_set(decodebin, "sink-caps", caps, NULL);
6287 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6289 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6290 LOGE("failed to link [%s:%s]-[%s:%s]",
6291 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6295 gst_object_unref(GST_OBJECT(sinkpad));
6297 gst_object_unref(GST_OBJECT(qsrcpad));
6300 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6301 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6303 /* set decodebin property about buffer in streaming playback. *
6304 * in case of HLS/DASH, it does not need to have big buffer *
6305 * because it is kind of adaptive streaming. */
6306 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6307 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6308 gint high_percent = 0;
6310 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6311 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6313 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6315 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6317 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6318 "high-percent", high_percent,
6319 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6320 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6321 "max-size-buffers", 0, NULL); // disable or automatic
6324 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6325 LOGE("failed to sync decodebin state with parent");
6336 gst_object_unref(GST_OBJECT(sinkpad));
6339 gst_object_unref(GST_OBJECT(qsrcpad));
6342 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6343 * You need to explicitly set elements to the NULL state before
6344 * dropping the final reference, to allow them to clean up.
6346 gst_element_set_state(queue2, GST_STATE_NULL);
6348 /* And, it still has a parent "player".
6349 * You need to let the parent manage the object instead of unreffing the object directly.
6351 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6352 LOGE("failed to remove queue2");
6353 gst_object_unref(queue2);
6359 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6360 * You need to explicitly set elements to the NULL state before
6361 * dropping the final reference, to allow them to clean up.
6363 gst_element_set_state(decodebin, GST_STATE_NULL);
6365 /* And, it still has a parent "player".
6366 * You need to let the parent manage the object instead of unreffing the object directly.
6369 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6370 LOGE("failed to remove decodebin");
6371 gst_object_unref(decodebin);
6380 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6384 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6385 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6387 LOGD("class : %s, mime : %s", factory_class, mime);
6389 /* add missing plugin */
6390 /* NOTE : msl should check missing plugin for image mime type.
6391 * Some motion jpeg clips can have playable audio track.
6392 * So, msl have to play audio after displaying popup written video format not supported.
6394 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6395 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6396 LOGD("not found demuxer");
6397 player->not_found_demuxer = TRUE;
6398 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6404 if (!g_strrstr(factory_class, "Demuxer")) {
6405 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6406 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6407 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6409 /* check that clip have multi tracks or not */
6410 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6411 LOGD("video plugin is already linked");
6413 LOGW("add VIDEO to missing plugin");
6414 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6415 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6417 } else if (g_str_has_prefix(mime, "audio")) {
6418 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6419 LOGD("audio plugin is already linked");
6421 LOGW("add AUDIO to missing plugin");
6422 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6423 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6431 return MM_ERROR_NONE;
6435 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6437 mmplayer_t *player = (mmplayer_t *)data;
6441 MMPLAYER_RETURN_IF_FAIL(player);
6443 /* remove fakesink. */
6444 if (!_mmplayer_gst_remove_fakesink(player,
6445 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6446 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6447 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6448 * source element are not same. To overcome this situation, this function will called
6449 * several places and several times. Therefore, this is not an error case.
6454 LOGD("[handle: %p] pipeline has completely constructed", player);
6456 if ((player->msg_posted == FALSE) &&
6457 (player->cmd >= MMPLAYER_COMMAND_START))
6458 __mmplayer_handle_missed_plugin(player);
6460 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6464 __mmplayer_check_profile(void)
6467 static int profile_tv = -1;
6469 if (__builtin_expect(profile_tv != -1, 1))
6472 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6473 switch (*profileName) {
6488 __mmplayer_get_next_uri(mmplayer_t *player)
6490 mmplayer_parse_profile_t profile;
6492 guint num_of_list = 0;
6495 num_of_list = g_list_length(player->uri_info.uri_list);
6496 uri_idx = player->uri_info.uri_idx;
6498 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6499 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6500 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6502 LOGW("next uri does not exist");
6506 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6507 LOGE("failed to parse profile");
6511 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6512 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6513 LOGW("uri type is not supported(%d)", profile.uri_type);
6517 LOGD("success to find next uri %d", uri_idx);
6521 if (!uri || uri_idx == num_of_list) {
6522 LOGE("failed to find next uri");
6526 player->uri_info.uri_idx = uri_idx;
6527 if (mm_player_set_attribute((MMHandleType)player, NULL,
6528 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6529 LOGE("failed to set attribute");
6533 SECURE_LOGD("next playback uri: %s", uri);
6538 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6540 #define REPEAT_COUNT_INFINITE -1
6541 #define REPEAT_COUNT_MIN 2
6542 #define ORIGINAL_URI_ONLY 1
6544 MMHandleType attrs = 0;
6548 guint num_of_uri = 0;
6549 int profile_tv = -1;
6553 LOGD("checking for gapless play option");
6555 if (player->build_audio_offload) {
6556 LOGE("offload path is not supportable.");
6560 if (player->pipeline->textbin) {
6561 LOGE("subtitle path is enabled. gapless play is not supported.");
6565 attrs = MMPLAYER_GET_ATTRS(player);
6567 LOGE("fail to get attributes.");
6571 mm_attrs_multiple_get(player->attrs, NULL,
6572 "content_video_found", &video,
6573 "profile_play_count", &count,
6574 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6576 /* gapless playback is not supported in case of video at TV profile. */
6577 profile_tv = __mmplayer_check_profile();
6578 if (profile_tv && video) {
6579 LOGW("not support video gapless playback");
6583 /* check repeat count in case of audio */
6585 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6586 LOGW("gapless is disabled");
6590 num_of_uri = g_list_length(player->uri_info.uri_list);
6592 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6594 if (num_of_uri == ORIGINAL_URI_ONLY) {
6595 /* audio looping path */
6596 if (count >= REPEAT_COUNT_MIN) {
6597 /* decrease play count */
6598 /* we succeeded to rewind. update play count and then wait for next EOS */
6600 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6601 } else if (count != REPEAT_COUNT_INFINITE) {
6602 LOGD("there is no next uri and no repeat");
6605 LOGD("looping cnt %d", count);
6607 /* gapless playback path */
6608 if (!__mmplayer_get_next_uri(player)) {
6609 LOGE("failed to get next uri");
6616 LOGE("unable to play gapless path. EOS will be posted soon");
6621 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6623 GstPad *sinkpad = g_value_get_object (item);
6624 GstElement *element = GST_ELEMENT(user_data);
6625 if (!sinkpad || !element) {
6626 LOGE("invalid parameter");
6630 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6631 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6635 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6637 mmplayer_gst_element_t *sinkbin = NULL;
6638 main_element_id_e concatId = MMPLAYER_M_NUM;
6639 main_element_id_e sinkId = MMPLAYER_M_NUM;
6640 gboolean send_notice = FALSE;
6641 GstElement *element;
6645 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6647 LOGD("type %d", type);
6650 case MM_PLAYER_TRACK_TYPE_AUDIO:
6651 concatId = MMPLAYER_M_A_CONCAT;
6652 sinkId = MMPLAYER_A_BIN;
6653 sinkbin = player->pipeline->audiobin;
6655 case MM_PLAYER_TRACK_TYPE_VIDEO:
6656 concatId = MMPLAYER_M_V_CONCAT;
6657 sinkId = MMPLAYER_V_BIN;
6658 sinkbin = player->pipeline->videobin;
6661 case MM_PLAYER_TRACK_TYPE_TEXT:
6662 concatId = MMPLAYER_M_T_CONCAT;
6663 sinkId = MMPLAYER_T_BIN;
6664 sinkbin = player->pipeline->textbin;
6667 LOGE("requested type is not supportable");
6672 element = player->pipeline->mainbin[concatId].gst;
6676 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6677 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6678 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6679 if (srcpad && sinkpad) {
6680 /* after getting drained signal there is no data flows, so no need to do pad_block */
6681 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6682 gst_pad_unlink(srcpad, sinkpad);
6684 /* send custom event to sink pad to handle it at video sink */
6686 LOGD("send custom event to sinkpad");
6687 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6688 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6689 gst_pad_send_event(sinkpad, event);
6692 gst_object_unref(srcpad);
6693 gst_object_unref(sinkpad);
6696 LOGD("release concat request pad");
6697 /* release and unref requests pad from the selector */
6698 iter = gst_element_iterate_sink_pads(element);
6699 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6700 gst_iterator_resync(iter);
6701 gst_iterator_free(iter);
6707 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6709 mmplayer_track_t *selector = &player->track[type];
6710 mmplayer_gst_element_t *sinkbin = NULL;
6711 main_element_id_e selectorId = MMPLAYER_M_NUM;
6712 main_element_id_e sinkId = MMPLAYER_M_NUM;
6713 GstPad *srcpad = NULL;
6714 GstPad *sinkpad = NULL;
6715 gboolean send_notice = FALSE;
6718 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6720 LOGD("type %d", type);
6723 case MM_PLAYER_TRACK_TYPE_AUDIO:
6724 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6725 sinkId = MMPLAYER_A_BIN;
6726 sinkbin = player->pipeline->audiobin;
6728 case MM_PLAYER_TRACK_TYPE_VIDEO:
6729 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6730 sinkId = MMPLAYER_V_BIN;
6731 sinkbin = player->pipeline->videobin;
6734 case MM_PLAYER_TRACK_TYPE_TEXT:
6735 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6736 sinkId = MMPLAYER_T_BIN;
6737 sinkbin = player->pipeline->textbin;
6740 LOGE("requested type is not supportable");
6745 if (player->pipeline->mainbin[selectorId].gst) {
6748 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6750 if (selector->event_probe_id != 0)
6751 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6752 selector->event_probe_id = 0;
6754 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6755 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6757 if (srcpad && sinkpad) {
6758 /* after getting drained signal there is no data flows, so no need to do pad_block */
6759 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6760 gst_pad_unlink(srcpad, sinkpad);
6762 /* send custom event to sink pad to handle it at video sink */
6764 LOGD("send custom event to sinkpad");
6765 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6766 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6767 gst_pad_send_event(sinkpad, event);
6771 gst_object_unref(sinkpad);
6774 gst_object_unref(srcpad);
6777 LOGD("selector release");
6779 /* release and unref requests pad from the selector */
6780 for (n = 0; n < selector->streams->len; n++) {
6781 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6782 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6785 g_ptr_array_set_size(selector->streams, 0);
6787 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6788 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6789 player->pipeline->mainbin[selectorId].gst)) {
6790 LOGE("failed to remove selector");
6791 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6794 player->pipeline->mainbin[selectorId].gst = NULL;
6802 __mmplayer_deactivate_old_path(mmplayer_t *player)
6805 MMPLAYER_RETURN_IF_FAIL(player);
6807 if (MMPLAYER_USE_DECODEBIN(player)) {
6808 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6809 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6810 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6811 LOGE("deactivate selector error");
6815 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6816 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6817 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6818 LOGE("deactivate concat error");
6823 _mmplayer_track_destroy(player);
6824 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6826 if (player->streamer) {
6827 _mm_player_streaming_initialize(player->streamer, FALSE);
6828 _mm_player_streaming_destroy(player->streamer);
6829 player->streamer = NULL;
6832 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6838 if (!player->msg_posted) {
6839 MMMessageParamType msg = {0,};
6842 msg.code = MM_ERROR_PLAYER_INTERNAL;
6843 LOGE("gapless_uri_play> deactivate error");
6845 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6846 player->msg_posted = TRUE;
6852 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6854 int result = MM_ERROR_NONE;
6855 mmplayer_t *player = (mmplayer_t *)hplayer;
6858 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6859 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6861 if (mm_player_set_attribute(hplayer, NULL,
6862 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6863 LOGE("failed to set attribute");
6864 result = MM_ERROR_PLAYER_INTERNAL;
6866 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6867 LOGE("failed to add the original uri in the uri list.");
6875 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6877 mmplayer_t *player = (mmplayer_t *)hplayer;
6878 guint num_of_list = 0;
6882 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6883 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6885 if (player->pipeline && player->pipeline->textbin) {
6886 LOGE("subtitle path is enabled.");
6887 return MM_ERROR_PLAYER_INVALID_STATE;
6890 num_of_list = g_list_length(player->uri_info.uri_list);
6892 if (is_first_path) {
6893 if (num_of_list == 0) {
6894 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6895 SECURE_LOGD("add original path : %s", uri);
6897 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6898 player->uri_info.uri_list = g_list_prepend(
6899 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6900 SECURE_LOGD("change original path : %s", uri);
6903 MMHandleType attrs = 0;
6904 attrs = MMPLAYER_GET_ATTRS(player);
6906 if (num_of_list == 0) {
6907 char *original_uri = NULL;
6910 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6912 if (!original_uri) {
6913 LOGE("there is no original uri.");
6914 return MM_ERROR_PLAYER_INVALID_STATE;
6917 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6918 player->uri_info.uri_idx = 0;
6920 SECURE_LOGD("add original path at first : %s", original_uri);
6924 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6925 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6929 return MM_ERROR_NONE;
6933 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6935 mmplayer_t *player = (mmplayer_t *)hplayer;
6936 char *next_uri = NULL;
6937 guint num_of_list = 0;
6940 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6942 num_of_list = g_list_length(player->uri_info.uri_list);
6944 if (num_of_list > 0) {
6945 gint uri_idx = player->uri_info.uri_idx;
6947 if (uri_idx < num_of_list - 1)
6952 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6953 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6955 *uri = g_strdup(next_uri);
6959 return MM_ERROR_NONE;
6963 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6964 GstCaps *caps, gpointer data)
6966 mmplayer_t *player = (mmplayer_t *)data;
6967 const gchar *klass = NULL;
6968 const gchar *mime = NULL;
6969 gchar *caps_str = NULL;
6971 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6972 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6973 caps_str = gst_caps_to_string(caps);
6975 LOGW("unknown type of caps : %s from %s",
6976 caps_str, GST_ELEMENT_NAME(elem));
6978 MMPLAYER_FREEIF(caps_str);
6980 /* There is no available codec. */
6981 __mmplayer_check_not_supported_codec(player, klass, mime);
6985 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6986 GstCaps *caps, gpointer data)
6988 mmplayer_t *player = (mmplayer_t *)data;
6989 const char *mime = NULL;
6990 gboolean ret = TRUE;
6992 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6993 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6995 if (g_str_has_prefix(mime, "audio")) {
6996 GstStructure *caps_structure = NULL;
6997 gint samplerate = 0;
6999 gchar *caps_str = NULL;
7001 caps_structure = gst_caps_get_structure(caps, 0);
7002 gst_structure_get_int(caps_structure, "rate", &samplerate);
7003 gst_structure_get_int(caps_structure, "channels", &channels);
7005 if ((channels > 0 && samplerate == 0)) {
7006 LOGD("exclude audio...");
7010 caps_str = gst_caps_to_string(caps);
7011 /* set it directly because not sent by TAG */
7012 if (g_strrstr(caps_str, "mobile-xmf"))
7013 mm_player_set_attribute((MMHandleType)player, NULL,
7014 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7016 MMPLAYER_FREEIF(caps_str);
7017 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7018 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7019 LOGD("video is already linked, allow the stream switch");
7022 LOGD("video is already linked");
7026 LOGD("found new stream");
7033 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7035 gboolean ret = FALSE;
7036 GDBusConnection *conn = NULL;
7038 GVariant *result = NULL;
7039 const gchar *dbus_device_type = NULL;
7040 const gchar *dbus_ret = NULL;
7043 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7045 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7050 result = g_dbus_connection_call_sync(conn,
7051 "org.pulseaudio.Server",
7052 "/org/pulseaudio/StreamManager",
7053 "org.pulseaudio.StreamManager",
7054 "GetCurrentMediaRoutingPath",
7055 g_variant_new("(s)", "out"),
7056 G_VARIANT_TYPE("(ss)"),
7057 G_DBUS_CALL_FLAGS_NONE,
7061 if (!result || err) {
7062 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7067 /* device type is listed in stream-map.json at mmfw-sysconf */
7068 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7070 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7071 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7074 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7075 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7076 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7077 LOGD("audio offload is supportable");
7083 LOGD("audio offload is not supportable");
7086 g_variant_unref(result);
7088 g_object_unref(conn);
7093 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7095 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7096 gint64 position = 0;
7098 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7099 player->pipeline && player->pipeline->mainbin);
7101 MMPLAYER_CMD_LOCK(player);
7102 current_state = MMPLAYER_CURRENT_STATE(player);
7104 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7105 LOGW("getting current position failed in paused");
7107 _mmplayer_unrealize((MMHandleType)player);
7108 _mmplayer_realize((MMHandleType)player);
7110 _mmplayer_set_position((MMHandleType)player, position);
7112 /* async not to be blocked in streaming case */
7113 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7115 _mmplayer_pause((MMHandleType)player);
7117 if (current_state == MM_PLAYER_STATE_PLAYING)
7118 _mmplayer_start((MMHandleType)player);
7119 MMPLAYER_CMD_UNLOCK(player);
7121 LOGD("rebuilding audio pipeline is completed.");
7124 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7126 mmplayer_t *player = (mmplayer_t *)user_data;
7127 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7128 gboolean is_supportable = FALSE;
7130 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7131 LOGW("failed to get device type");
7133 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7135 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7136 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7137 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7138 LOGD("ignore this dev connected info");
7142 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7143 if (player->build_audio_offload == is_supportable) {
7144 LOGD("keep current pipeline without re-building");
7148 /* rebuild pipeline */
7149 LOGD("re-build pipeline - offload: %d", is_supportable);
7150 player->build_audio_offload = FALSE;
7151 __mmplayer_rebuild_audio_pipeline(player);
7157 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7159 unsigned int id = 0;
7161 if (player->audio_device_cb_id != 0) {
7162 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7166 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7167 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7168 LOGD("added device connected cb (%u)", id);
7169 player->audio_device_cb_id = id;
7171 LOGW("failed to add device connected cb");
7178 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7180 mmplayer_t *player = (mmplayer_t *)hplayer;
7183 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7184 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7186 *activated = player->build_audio_offload;
7188 LOGD("offload activated : %d", (int)*activated);
7191 return MM_ERROR_NONE;
7195 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7198 this function need to be updated according to the supported media format
7199 @see player->ini.audio_offload_media_format */
7201 if (__mmplayer_is_only_mp3_type(player->type)) {
7202 LOGD("offload supportable media format type");
7210 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7212 gboolean ret = FALSE;
7213 GstElementFactory *factory = NULL;
7216 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7218 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7219 if (!__mmplayer_is_offload_supported_type(player))
7222 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7223 LOGD("there is no audio offload sink");
7227 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7228 LOGW("there is no audio device type to support offload");
7232 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7234 LOGW("there is no installed audio offload sink element");
7237 gst_object_unref(factory);
7239 if (_mmplayer_acquire_hw_resource(player,
7240 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7241 LOGE("failed to acquire audio offload decoder resource");
7245 if (!__mmplayer_add_audio_device_connected_cb(player))
7248 if (!__mmplayer_is_audio_offload_device_type(player))
7251 LOGD("audio offload can be built");
7256 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7262 static GstAutoplugSelectResult
7263 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7265 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7266 int audio_offload = 0;
7268 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7269 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7271 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7272 LOGD("expose audio path to build offload output path");
7273 player->build_audio_offload = TRUE;
7274 /* update codec info */
7275 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7276 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7277 player->audiodec_linked = 1;
7279 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7283 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7284 And need to consider the multi-track audio content.
7285 There is no HW audio decoder in public. */
7287 /* set stream information */
7288 if (!player->audiodec_linked)
7289 _mmplayer_set_audio_attrs(player, caps);
7291 /* update codec info */
7292 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7293 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7294 player->audiodec_linked = 1;
7296 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7298 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7299 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7301 /* mark video decoder for acquire */
7302 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7303 LOGW("video decoder resource is already acquired, skip it.");
7304 ret = GST_AUTOPLUG_SELECT_SKIP;
7308 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7309 LOGE("failed to acquire video decoder resource");
7310 ret = GST_AUTOPLUG_SELECT_SKIP;
7313 player->interrupted_by_resource = FALSE;
7316 /* update codec info */
7317 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7318 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7319 player->videodec_linked = 1;
7327 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7328 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7330 #define DEFAULT_IDX 0xFFFF
7331 #define MIN_FACTORY_NUM 2
7332 mmplayer_t *player = (mmplayer_t *)data;
7333 GValueArray *new_factories = NULL;
7334 GValue val = { 0, };
7335 GstElementFactory *factory = NULL;
7336 const gchar *klass = NULL;
7337 gchar *factory_name = NULL;
7338 guint hw_dec_idx = DEFAULT_IDX;
7339 guint first_sw_dec_idx = DEFAULT_IDX;
7340 guint last_sw_dec_idx = DEFAULT_IDX;
7341 guint new_pos = DEFAULT_IDX;
7342 guint rm_pos = DEFAULT_IDX;
7343 int audio_codec_type;
7344 int video_codec_type;
7345 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7347 if (factories->n_values < MIN_FACTORY_NUM)
7350 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7351 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7354 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7356 for (int i = 0 ; i < factories->n_values ; i++) {
7357 gchar *hw_dec_info = NULL;
7358 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7360 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7362 LOGW("failed to get factory object");
7365 klass = gst_element_factory_get_klass(factory);
7366 factory_name = GST_OBJECT_NAME(factory);
7369 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7371 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7372 if (!player->need_audio_dec_sorting) {
7373 LOGD("sorting is not required");
7376 codec_type = audio_codec_type;
7377 hw_dec_info = player->ini.audiocodec_element_hw;
7378 sw_dec_info = player->ini.audiocodec_element_sw;
7379 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7380 if (!player->need_video_dec_sorting) {
7381 LOGD("sorting is not required");
7384 codec_type = video_codec_type;
7385 hw_dec_info = player->ini.videocodec_element_hw;
7386 sw_dec_info = player->ini.videocodec_element_sw;
7391 if (g_strrstr(factory_name, hw_dec_info)) {
7394 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7395 if (strstr(factory_name, sw_dec_info[j])) {
7396 last_sw_dec_idx = i;
7397 if (first_sw_dec_idx == DEFAULT_IDX) {
7398 first_sw_dec_idx = i;
7403 if (first_sw_dec_idx == DEFAULT_IDX)
7404 LOGW("unknown codec %s", factory_name);
7408 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7411 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7412 if (hw_dec_idx < first_sw_dec_idx)
7414 new_pos = first_sw_dec_idx;
7415 rm_pos = hw_dec_idx + 1;
7416 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7417 if (last_sw_dec_idx < hw_dec_idx)
7419 new_pos = last_sw_dec_idx + 1;
7420 rm_pos = hw_dec_idx;
7425 /* change position - insert H/W decoder according to the new position */
7426 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7428 LOGW("failed to get factory object");
7431 new_factories = g_value_array_copy(factories);
7432 g_value_init (&val, G_TYPE_OBJECT);
7433 g_value_set_object (&val, factory);
7434 g_value_array_insert(new_factories, new_pos, &val);
7435 g_value_unset (&val);
7436 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7438 for (int i = 0 ; i < new_factories->n_values ; i++) {
7439 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7441 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7442 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7444 LOGE("[Re-arranged] failed to get factory object");
7447 return new_factories;
7451 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7452 GstCaps *caps, GstElementFactory *factory, gpointer data)
7454 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7455 mmplayer_t *player = (mmplayer_t *)data;
7457 gchar *factory_name = NULL;
7458 gchar *caps_str = NULL;
7459 const gchar *klass = NULL;
7462 factory_name = GST_OBJECT_NAME(factory);
7463 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7464 caps_str = gst_caps_to_string(caps);
7466 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7468 /* store type string */
7469 if (player->type == NULL) {
7470 player->type = gst_caps_to_string(caps);
7471 __mmplayer_update_content_type_info(player);
7474 /* filtering exclude keyword */
7475 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7476 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7477 LOGW("skipping [%s] by exclude keyword [%s]",
7478 factory_name, player->ini.exclude_element_keyword[idx]);
7480 result = GST_AUTOPLUG_SELECT_SKIP;
7485 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7486 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7487 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7488 factory_name, player->ini.unsupported_codec_keyword[idx]);
7489 result = GST_AUTOPLUG_SELECT_SKIP;
7494 /* exclude webm format */
7495 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7496 * because webm format is not supportable.
7497 * If webm is disabled in "autoplug-continue", there is no state change
7498 * failure or error because the decodebin will expose the pad directly.
7499 * It make MSL invoke _prepare_async_callback.
7500 * So, we need to disable webm format in "autoplug-select" */
7501 if (caps_str && strstr(caps_str, "webm")) {
7502 LOGW("webm is not supported");
7503 result = GST_AUTOPLUG_SELECT_SKIP;
7507 /* check factory class for filtering */
7508 /* NOTE : msl don't need to use image plugins.
7509 * So, those plugins should be skipped for error handling.
7511 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7512 LOGD("skipping [%s] by not required", factory_name);
7513 result = GST_AUTOPLUG_SELECT_SKIP;
7517 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7518 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7519 // TO CHECK : subtitle if needed, add subparse exception.
7520 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7521 result = GST_AUTOPLUG_SELECT_SKIP;
7525 if (g_strrstr(factory_name, "mpegpsdemux")) {
7526 LOGD("skipping PS container - not support");
7527 result = GST_AUTOPLUG_SELECT_SKIP;
7531 if (g_strrstr(factory_name, "mssdemux"))
7532 player->smooth_streaming = TRUE;
7534 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7535 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7538 GstStructure *str = NULL;
7539 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7541 /* don't make video because of not required */
7542 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7543 (!player->set_mode.video_export)) {
7544 LOGD("no need video decoding, expose pad");
7545 result = GST_AUTOPLUG_SELECT_EXPOSE;
7549 /* get w/h for omx state-tune */
7550 /* FIXME: deprecated? */
7551 str = gst_caps_get_structure(caps, 0);
7552 gst_structure_get_int(str, "width", &width);
7555 if (player->v_stream_caps) {
7556 gst_caps_unref(player->v_stream_caps);
7557 player->v_stream_caps = NULL;
7560 player->v_stream_caps = gst_caps_copy(caps);
7561 LOGD("take caps for video state tune");
7562 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7566 if (g_strrstr(klass, "Codec/Decoder")) {
7567 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7568 if (result != GST_AUTOPLUG_SELECT_TRY) {
7569 LOGW("skip add decoder");
7575 MMPLAYER_FREEIF(caps_str);
7581 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7584 int ret = MM_ERROR_NONE;
7585 mmplayer_t *player = (mmplayer_t *)data;
7586 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7587 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7590 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7592 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7594 if (MMPLAYER_USE_DECODEBIN(player))
7597 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7600 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7602 __mmplayer_del_sink(player, videobin[MMPLAYER_V_SINK].gst);
7604 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7605 LOGE("failed to remove videobin");
7606 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7609 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7610 LOGE("failed to remove video concat");
7611 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7614 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7615 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7616 MMPLAYER_FREEIF(player->pipeline->videobin);
7618 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7619 if (ret != MM_ERROR_NONE)
7620 LOGE("failed to release overlay resources");
7622 player->videodec_linked = 0;
7624 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7629 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7631 mmplayer_t *player = (mmplayer_t *)data;
7634 MMPLAYER_RETURN_IF_FAIL(player);
7636 LOGD("got about to finish signal");
7638 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7639 LOGW("Fail to get cmd lock");
7643 if (!__mmplayer_verify_gapless_play_path(player)) {
7644 LOGD("decoding is finished.");
7645 MMPLAYER_CMD_UNLOCK(player);
7649 _mmplayer_set_reconfigure_state(player, TRUE);
7650 MMPLAYER_CMD_UNLOCK(player);
7652 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7653 __mmplayer_deactivate_old_path(player);
7659 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7661 mmplayer_t *player = (mmplayer_t *)data;
7662 GstIterator *iter = NULL;
7663 GValue item = { 0, };
7665 gboolean done = FALSE;
7666 gboolean is_all_drained = TRUE;
7669 MMPLAYER_RETURN_IF_FAIL(player);
7671 LOGD("got drained signal");
7673 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7674 LOGW("Fail to get cmd lock");
7678 if (!__mmplayer_verify_gapless_play_path(player)) {
7679 LOGD("decoding is finished.");
7680 MMPLAYER_CMD_UNLOCK(player);
7684 _mmplayer_set_reconfigure_state(player, TRUE);
7685 MMPLAYER_CMD_UNLOCK(player);
7687 /* check decodebin src pads whether they received EOS or not */
7688 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7691 switch (gst_iterator_next(iter, &item)) {
7692 case GST_ITERATOR_OK:
7693 pad = g_value_get_object(&item);
7694 if (pad && !GST_PAD_IS_EOS(pad)) {
7695 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7696 is_all_drained = FALSE;
7699 g_value_reset(&item);
7701 case GST_ITERATOR_RESYNC:
7702 gst_iterator_resync(iter);
7704 case GST_ITERATOR_ERROR:
7705 case GST_ITERATOR_DONE:
7710 g_value_unset(&item);
7711 gst_iterator_free(iter);
7713 if (!is_all_drained) {
7714 LOGD("Wait util the all pads get EOS.");
7719 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7720 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7722 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7723 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7724 __mmplayer_deactivate_old_path(player);
7730 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7732 mmplayer_t *player = (mmplayer_t *)data;
7733 const gchar *klass = NULL;
7734 gchar *factory_name = NULL;
7736 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7737 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7739 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7741 if (__mmplayer_add_dump_buffer_probe(player, element))
7742 LOGD("add buffer probe");
7744 if (g_strrstr(klass, "Decoder")) {
7745 if (g_strrstr(klass, "Audio")) {
7746 player->audio_decoders = g_list_append(player->audio_decoders,
7747 g_strdup(GST_ELEMENT_NAME(element)));
7749 /* update codec info */
7750 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7751 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7752 player->audiodec_linked = 1;
7753 } else if (g_strrstr(klass, "Video")) {
7754 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7755 /* update codec info */
7756 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7757 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7758 player->videodec_linked = 1;
7761 GstPad *srcpad = gst_element_get_static_pad (video_parse, "src");
7763 GstCaps *caps = NULL;
7764 GstStructure *str = NULL;
7765 const gchar *name = NULL;
7766 gboolean caps_ret = TRUE;
7768 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD (srcpad, caps, str, name, caps_ret);
7769 if (caps_ret && str) {
7770 const gchar *stream_format = gst_structure_get_string (str, "stream-format");
7771 if (stream_format && g_strrstr(stream_format, "byte-stream")) {
7772 if ((g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7773 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7774 LOGD("Send SPS and PPS Insertion every IDR frame");
7778 gst_object_unref(GST_OBJECT(srcpad));
7782 } else if (g_strrstr(klass, "Demuxer")) {
7783 if (g_strrstr(klass, "Adaptive")) {
7784 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7785 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7787 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7788 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7790 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7791 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7792 "max-video-width", player->adaptive_info.limit.width,
7793 "max-video-height", player->adaptive_info.limit.height, NULL);
7796 LOGD("plugged element is demuxer. take it");
7798 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7799 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7801 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7802 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7803 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7806 if (g_strrstr(factory_name, "mpegaudioparse")) {
7807 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7808 (__mmplayer_is_only_mp3_type(player->type))) {
7809 LOGD("[mpegaudioparse] set streaming pull mode.");
7810 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7812 } else if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7813 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7814 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7816 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7817 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7819 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7820 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7821 (MMPLAYER_IS_DASH_STREAMING(player))) {
7822 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7823 _mm_player_streaming_set_multiqueue(player->streamer, element);
7824 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7832 __mmplayer_release_misc(mmplayer_t *player)
7835 bool cur_mode = player->set_mode.rich_audio;
7838 MMPLAYER_RETURN_IF_FAIL(player);
7840 player->sent_bos = FALSE;
7841 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7843 player->seek_state = MMPLAYER_SEEK_NONE;
7845 player->total_bitrate = 0;
7846 player->total_maximum_bitrate = 0;
7848 player->not_found_demuxer = 0;
7850 player->last_position = 0;
7851 player->duration = 0;
7852 player->http_content_size = 0;
7853 player->not_supported_codec = MISSING_PLUGIN_NONE;
7854 player->can_support_codec = FOUND_PLUGIN_NONE;
7855 player->pending_seek.is_pending = false;
7856 player->pending_seek.pos = 0;
7857 player->msg_posted = FALSE;
7858 player->has_many_types = FALSE;
7859 player->is_subtitle_force_drop = FALSE;
7860 player->play_subtitle = FALSE;
7861 player->adjust_subtitle_pos = 0;
7862 player->has_closed_caption = FALSE;
7863 player->set_mode.video_export = false;
7864 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7865 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7867 player->set_mode.rich_audio = cur_mode;
7869 if (player->audio_device_cb_id > 0 &&
7870 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7871 LOGW("failed to remove audio device_connected_callback");
7872 player->audio_device_cb_id = 0;
7874 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7875 player->bitrate[i] = 0;
7876 player->maximum_bitrate[i] = 0;
7879 /* free memory related to audio effect */
7880 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7882 if (player->adaptive_info.var_list) {
7883 g_list_free_full(player->adaptive_info.var_list, g_free);
7884 player->adaptive_info.var_list = NULL;
7887 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7888 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7889 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7891 /* Reset video360 settings to their defaults in case if the pipeline is to be
7894 player->video360_metadata.is_spherical = -1;
7895 player->is_openal_plugin_used = FALSE;
7897 player->is_content_spherical = FALSE;
7898 player->is_video360_enabled = TRUE;
7899 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7900 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7901 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7902 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7903 player->video360_zoom = 1.0f;
7904 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7905 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7907 player->sound.rg_enable = false;
7909 __mmplayer_initialize_video_roi(player);
7914 __mmplayer_release_misc_post(mmplayer_t *player)
7916 gchar *original_uri = NULL;
7919 /* player->pipeline is already released before. */
7920 MMPLAYER_RETURN_IF_FAIL(player);
7922 player->video_decoded_cb = NULL;
7923 player->video_decoded_cb_user_param = NULL;
7924 player->video_stream_prerolled = false;
7926 player->audio_decoded_cb = NULL;
7927 player->audio_decoded_cb_user_param = NULL;
7928 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7930 player->audio_stream_changed_cb = NULL;
7931 player->audio_stream_changed_cb_user_param = NULL;
7933 mm_player_set_attribute((MMHandleType)player, NULL,
7934 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7936 /* clean found audio decoders */
7937 if (player->audio_decoders) {
7938 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7939 player->audio_decoders = NULL;
7942 /* clean the uri list except original uri */
7943 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7945 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7946 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7947 g_list_free_full(tmp, (GDestroyNotify)g_free);
7950 LOGW("failed to get original uri info");
7952 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7953 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7954 MMPLAYER_FREEIF(original_uri);
7957 /* clear the audio stream buffer list */
7958 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7960 /* clear the video stream bo list */
7961 __mmplayer_video_stream_destroy_bo_list(player);
7962 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7964 if (player->profile.input_mem.buf) {
7965 free(player->profile.input_mem.buf);
7966 player->profile.input_mem.buf = NULL;
7968 player->profile.input_mem.len = 0;
7969 player->profile.input_mem.offset = 0;
7971 player->uri_info.uri_idx = 0;
7976 __mmplayer_check_subtitle(mmplayer_t *player)
7978 MMHandleType attrs = 0;
7979 char *subtitle_uri = NULL;
7983 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7985 /* get subtitle attribute */
7986 attrs = MMPLAYER_GET_ATTRS(player);
7990 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7991 if (!subtitle_uri || !strlen(subtitle_uri))
7994 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7995 player->is_external_subtitle_present = TRUE;
8003 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8005 MMPLAYER_RETURN_IF_FAIL(player);
8007 if (player->eos_timer) {
8008 LOGD("cancel eos timer");
8009 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8010 player->eos_timer = 0;
8017 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8021 MMPLAYER_RETURN_IF_FAIL(player);
8022 MMPLAYER_RETURN_IF_FAIL(sink);
8025 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8027 player->sink_elements = g_list_append(player->sink_elements, sink);
8033 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8037 MMPLAYER_RETURN_IF_FAIL(player);
8038 MMPLAYER_RETURN_IF_FAIL(sink);
8040 player->sink_elements = g_list_remove(player->sink_elements, sink);
8046 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8047 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8049 mmplayer_signal_item_t *item = NULL;
8052 MMPLAYER_RETURN_IF_FAIL(player);
8054 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8055 LOGE("invalid signal type [%d]", type);
8059 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8061 LOGE("cannot connect signal [%s]", signal);
8066 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8067 player->signals[type] = g_list_append(player->signals[type], item);
8073 /* NOTE : be careful with calling this api. please refer to below glib comment
8074 * glib comment : Note that there is a bug in GObject that makes this function much
8075 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8076 * will no longer be called, but, the signal handler is not currently disconnected.
8077 * If the instance is itself being freed at the same time than this doesn't matter,
8078 * since the signal will automatically be removed, but if instance persists,
8079 * then the signal handler will leak. You should not remove the signal yourself
8080 * because in a future versions of GObject, the handler will automatically be
8083 * It's possible to work around this problem in a way that will continue to work
8084 * with future versions of GObject by checking that the signal handler is still
8085 * connected before disconnected it:
8087 * if (g_signal_handler_is_connected(instance, id))
8088 * g_signal_handler_disconnect(instance, id);
8091 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8093 GList *sig_list = NULL;
8094 mmplayer_signal_item_t *item = NULL;
8098 MMPLAYER_RETURN_IF_FAIL(player);
8100 LOGD("release signals type : %d", type);
8102 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8103 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8104 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8105 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8106 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8107 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8111 sig_list = player->signals[type];
8113 for (; sig_list; sig_list = sig_list->next) {
8114 item = sig_list->data;
8116 if (item && item->obj) {
8117 if (g_signal_handler_is_connected(item->obj, item->sig))
8118 g_signal_handler_disconnect(item->obj, item->sig);
8121 MMPLAYER_FREEIF(item);
8124 g_list_free(player->signals[type]);
8125 player->signals[type] = NULL;
8133 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8135 mmplayer_t *player = 0;
8136 int prev_display_surface_type = 0;
8140 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8142 player = MM_PLAYER_CAST(handle);
8144 /* check video sinkbin is created */
8145 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8146 LOGW("Videosink is already created");
8147 return MM_ERROR_NONE;
8150 LOGD("videosink element is not yet ready");
8152 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8153 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8155 return MM_ERROR_INVALID_ARGUMENT;
8158 /* load previous attributes */
8159 if (player->attrs) {
8160 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8161 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8162 if (prev_display_surface_type == surface_type) {
8163 LOGD("incoming display surface type is same as previous one, do nothing..");
8165 return MM_ERROR_NONE;
8168 LOGE("failed to load attributes");
8170 return MM_ERROR_PLAYER_INTERNAL;
8173 /* videobin is not created yet, so we just set attributes related to display surface */
8174 LOGD("store display attribute for given surface type(%d)", surface_type);
8175 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8176 "display_overlay", wl_surface_id, NULL);
8179 return MM_ERROR_NONE;
8182 /* Note : if silent is true, then subtitle would not be displayed. :*/
8184 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8186 mmplayer_t *player = (mmplayer_t *)hplayer;
8190 /* check player handle */
8191 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8193 player->set_mode.subtitle_off = silent;
8195 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8199 return MM_ERROR_NONE;
8203 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8205 mmplayer_gst_element_t *mainbin = NULL;
8206 mmplayer_gst_element_t *textbin = NULL;
8207 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8208 GstState current_state = GST_STATE_VOID_PENDING;
8209 GstState element_state = GST_STATE_VOID_PENDING;
8210 GstState element_pending_state = GST_STATE_VOID_PENDING;
8212 GstEvent *event = NULL;
8213 int result = MM_ERROR_NONE;
8215 GstClock *curr_clock = NULL;
8216 GstClockTime base_time, start_time, curr_time;
8221 /* check player handle */
8222 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8224 player->pipeline->mainbin &&
8225 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8227 mainbin = player->pipeline->mainbin;
8228 textbin = player->pipeline->textbin;
8230 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8232 // sync clock with current pipeline
8233 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8234 curr_time = gst_clock_get_time(curr_clock);
8236 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8237 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8239 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8240 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8242 if (current_state > GST_STATE_READY) {
8243 // sync state with current pipeline
8244 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8245 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8246 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8248 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8249 if (GST_STATE_CHANGE_FAILURE == ret) {
8250 LOGE("fail to state change.");
8251 result = MM_ERROR_PLAYER_INTERNAL;
8255 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8256 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8259 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8260 gst_object_unref(curr_clock);
8263 // seek to current position
8264 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8265 result = MM_ERROR_PLAYER_INVALID_STATE;
8266 LOGE("gst_element_query_position failed, invalid state");
8270 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8271 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);
8273 _mmplayer_gst_send_event_to_sink(player, event);
8275 result = MM_ERROR_PLAYER_INTERNAL;
8276 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8280 /* sync state with current pipeline */
8281 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8282 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8283 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8285 return MM_ERROR_NONE;
8288 /* release text pipeline resource */
8289 player->textsink_linked = 0;
8291 /* release signal */
8292 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8294 /* release textbin with it's children */
8295 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8296 MMPLAYER_FREEIF(player->pipeline->textbin);
8297 player->pipeline->textbin = NULL;
8299 /* release subtitle elem */
8300 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8301 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8307 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8309 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8310 GstState current_state = GST_STATE_VOID_PENDING;
8312 MMHandleType attrs = 0;
8313 mmplayer_gst_element_t *mainbin = NULL;
8314 mmplayer_gst_element_t *textbin = NULL;
8316 gchar *subtitle_uri = NULL;
8317 int result = MM_ERROR_NONE;
8318 const gchar *charset = NULL;
8322 /* check player handle */
8323 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8325 player->pipeline->mainbin &&
8326 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8327 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8329 mainbin = player->pipeline->mainbin;
8330 textbin = player->pipeline->textbin;
8332 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8333 if (current_state < GST_STATE_READY) {
8334 result = MM_ERROR_PLAYER_INVALID_STATE;
8335 LOGE("Pipeline is not in proper state");
8339 attrs = MMPLAYER_GET_ATTRS(player);
8341 LOGE("cannot get content attribute");
8342 result = MM_ERROR_PLAYER_INTERNAL;
8346 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8347 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8348 LOGE("subtitle uri is not proper filepath");
8349 result = MM_ERROR_PLAYER_INVALID_URI;
8353 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8354 LOGE("failed to get storage info of subtitle path");
8355 result = MM_ERROR_PLAYER_INVALID_URI;
8359 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8360 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8362 if (!strcmp(filepath, subtitle_uri)) {
8363 LOGD("subtitle path is not changed");
8366 if (mm_player_set_attribute((MMHandleType)player, NULL,
8367 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8368 LOGE("failed to set attribute");
8373 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8374 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8375 player->subtitle_language_list = NULL;
8376 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8378 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8379 if (ret != GST_STATE_CHANGE_SUCCESS) {
8380 LOGE("failed to change state of textbin to READY");
8381 result = MM_ERROR_PLAYER_INTERNAL;
8385 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8386 if (ret != GST_STATE_CHANGE_SUCCESS) {
8387 LOGE("failed to change state of subparse to READY");
8388 result = MM_ERROR_PLAYER_INTERNAL;
8392 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8393 if (ret != GST_STATE_CHANGE_SUCCESS) {
8394 LOGE("failed to change state of filesrc to READY");
8395 result = MM_ERROR_PLAYER_INTERNAL;
8399 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8401 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8403 charset = _mmplayer_get_charset(filepath);
8405 LOGD("detected charset is %s", charset);
8406 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8409 result = _mmplayer_sync_subtitle_pipeline(player);
8416 /* API to switch between external subtitles */
8418 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8420 int result = MM_ERROR_NONE;
8421 mmplayer_t *player = (mmplayer_t *)hplayer;
8426 /* check player handle */
8427 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8429 /* filepath can be null in idle state */
8431 /* check file path */
8432 if ((path = strstr(filepath, "file://")))
8433 result = _mmplayer_exist_file_path(path + 7);
8435 result = _mmplayer_exist_file_path(filepath);
8437 if (result != MM_ERROR_NONE) {
8438 LOGE("invalid subtitle path 0x%X", result);
8439 return result; /* file not found or permission denied */
8443 if (!player->pipeline) {
8445 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8446 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8447 LOGE("failed to set attribute");
8448 return MM_ERROR_PLAYER_INTERNAL;
8451 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8452 /* check filepath */
8453 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8455 if (!__mmplayer_check_subtitle(player)) {
8456 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8457 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8458 LOGE("failed to set attribute");
8459 return MM_ERROR_PLAYER_INTERNAL;
8462 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8463 LOGE("fail to create text pipeline");
8464 return MM_ERROR_PLAYER_INTERNAL;
8467 result = _mmplayer_sync_subtitle_pipeline(player);
8469 result = __mmplayer_change_external_subtitle_language(player, filepath);
8472 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8473 player->is_external_subtitle_added_now = TRUE;
8475 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8476 if (!player->subtitle_language_list) {
8477 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8478 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8479 LOGW("subtitle language list is not updated yet");
8481 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8489 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8491 guint active_idx = 0;
8492 GstStream *stream = NULL;
8493 GList *streams = NULL;
8494 GstCaps *caps = NULL;
8497 LOGD("Switching Streams... type: %d, index: %d", type, index);
8499 player->track[type].active_track_index = index;
8501 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8502 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8503 LOGD("track type:%d, total: %d, active: %d", i,
8504 player->track[i].total_track_num, player->track[i].active_track_index);
8505 if (player->track[i].total_track_num > 0 &&
8506 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8507 active_idx = player->track[i].active_track_index;
8508 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8509 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8510 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8512 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8513 caps = gst_stream_get_caps(stream);
8515 _mmplayer_set_audio_attrs(player, caps);
8516 gst_caps_unref(caps);
8523 LOGD("send select stream event");
8524 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8525 gst_event_new_select_streams(streams));
8526 g_list_free(streams);
8529 /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8530 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8531 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8533 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8534 pos_nsec = player->last_position;
8536 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8538 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8539 player->playback_rate, GST_FORMAT_TIME,
8540 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8541 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8542 LOGW("failed to seek");
8543 return MM_ERROR_PLAYER_INTERNAL;
8548 return MM_ERROR_NONE;
8552 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8554 int result = MM_ERROR_NONE;
8555 gchar *change_pad_name = NULL;
8556 GstPad *sinkpad = NULL;
8557 mmplayer_gst_element_t *mainbin = NULL;
8558 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8559 GstCaps *caps = NULL;
8560 gint total_track_num = 0;
8564 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8565 MM_ERROR_PLAYER_NOT_INITIALIZED);
8567 LOGD("Change Track(%d) to %d", type, index);
8569 mainbin = player->pipeline->mainbin;
8571 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8572 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8573 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8574 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8576 /* Changing Video Track is not supported. */
8577 LOGE("Track Type Error");
8581 if (mainbin[elem_idx].gst == NULL) {
8582 result = MM_ERROR_PLAYER_NO_OP;
8583 LOGD("Req track doesn't exist");
8587 total_track_num = player->track[type].total_track_num;
8588 if (total_track_num <= 0) {
8589 result = MM_ERROR_PLAYER_NO_OP;
8590 LOGD("Language list is not available");
8594 if ((index < 0) || (index >= total_track_num)) {
8595 result = MM_ERROR_INVALID_ARGUMENT;
8596 LOGD("Not a proper index : %d", index);
8600 /*To get the new pad from the selector*/
8601 change_pad_name = g_strdup_printf("sink_%u", index);
8602 if (change_pad_name == NULL) {
8603 result = MM_ERROR_PLAYER_INTERNAL;
8604 LOGD("Pad does not exists");
8608 LOGD("new active pad name: %s", change_pad_name);
8610 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8611 if (sinkpad == NULL) {
8612 LOGD("sinkpad is NULL");
8613 result = MM_ERROR_PLAYER_INTERNAL;
8617 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8618 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8620 caps = gst_pad_get_current_caps(sinkpad);
8621 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8624 gst_object_unref(sinkpad);
8626 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8627 _mmplayer_set_audio_attrs(player, caps);
8630 gst_caps_unref(caps);
8633 MMPLAYER_FREEIF(change_pad_name);
8638 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8640 int result = MM_ERROR_NONE;
8641 mmplayer_t *player = NULL;
8642 mmplayer_gst_element_t *mainbin = NULL;
8644 gint current_active_index = 0;
8646 GstState current_state = GST_STATE_VOID_PENDING;
8651 player = (mmplayer_t *)hplayer;
8652 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8654 if (!player->pipeline) {
8655 LOGE("Track %d pre setting -> %d", type, index);
8657 player->track[type].active_track_index = index;
8661 mainbin = player->pipeline->mainbin;
8663 current_active_index = player->track[type].active_track_index;
8665 /*If index is same as running index no need to change the pad*/
8666 if (current_active_index == index)
8669 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8670 result = MM_ERROR_PLAYER_INVALID_STATE;
8674 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8675 if (current_state < GST_STATE_PAUSED) {
8676 result = MM_ERROR_PLAYER_INVALID_STATE;
8677 LOGW("Pipeline not in proper state");
8681 if (MMPLAYER_USE_DECODEBIN(player))
8682 result = __mmplayer_change_selector_pad(player, type, index);
8684 result = __mmplayer_switch_stream(player, type, index);
8686 if (result != MM_ERROR_NONE) {
8687 LOGE("failed to change track");
8691 player->track[type].active_track_index = index;
8693 if (MMPLAYER_USE_DECODEBIN(player)) {
8694 GstEvent *event = NULL;
8695 if (current_state == GST_STATE_PLAYING) {
8696 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8697 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8698 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8700 _mmplayer_gst_send_event_to_sink(player, event);
8702 result = MM_ERROR_PLAYER_INTERNAL;
8713 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8715 mmplayer_t *player = (mmplayer_t *)hplayer;
8719 /* check player handle */
8720 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8722 *silent = player->set_mode.subtitle_off;
8724 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8728 return MM_ERROR_NONE;
8732 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8734 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8735 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8737 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8738 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8742 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8743 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8744 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8745 mmplayer_dump_t *dump_s;
8746 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8747 if (dump_s == NULL) {
8748 LOGE("malloc fail");
8752 dump_s->dump_element_file = NULL;
8753 dump_s->dump_pad = NULL;
8754 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8756 if (dump_s->dump_pad) {
8757 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8758 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]);
8759 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8760 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);
8761 /* add list for removed buffer probe and close FILE */
8762 player->dump_list = g_list_append(player->dump_list, dump_s);
8763 LOGD("%s sink pad added buffer probe for dump", factory_name);
8766 MMPLAYER_FREEIF(dump_s);
8767 LOGE("failed to get %s sink pad added", factory_name);
8774 static GstPadProbeReturn
8775 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8777 FILE *dump_data = (FILE *)u_data;
8779 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8780 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8782 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8784 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8786 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8788 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8790 gst_buffer_unmap(buffer, &probe_info);
8792 return GST_PAD_PROBE_OK;
8796 __mmplayer_release_dump_list(GList *dump_list)
8798 GList *d_list = dump_list;
8803 for (; d_list; d_list = g_list_next(d_list)) {
8804 mmplayer_dump_t *dump_s = d_list->data;
8805 if (dump_s->dump_pad) {
8806 if (dump_s->probe_handle_id)
8807 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8808 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8810 if (dump_s->dump_element_file) {
8811 fclose(dump_s->dump_element_file);
8812 dump_s->dump_element_file = NULL;
8814 MMPLAYER_FREEIF(dump_s);
8816 g_list_free(dump_list);
8821 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8823 mmplayer_t *player = (mmplayer_t *)hplayer;
8827 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8828 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8830 *exist = (bool)player->has_closed_caption;
8834 return MM_ERROR_NONE;
8838 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8843 LOGD("unref internal gst buffer %p", buffer);
8845 gst_buffer_unref((GstBuffer *)buffer);
8852 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8854 mmplayer_t *player = (mmplayer_t *)hplayer;
8858 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8859 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8861 if (MMPLAYER_IS_STREAMING(player))
8862 *timeout = (int)player->ini.live_state_change_timeout;
8864 *timeout = (int)player->ini.localplayback_state_change_timeout;
8866 LOGD("timeout = %d", *timeout);
8869 return MM_ERROR_NONE;
8873 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8877 MMPLAYER_RETURN_IF_FAIL(player);
8879 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8881 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8882 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8883 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8884 player->storage_info[i].id = -1;
8885 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8887 if (path_type != MMPLAYER_PATH_MAX)
8896 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8898 int ret = MM_ERROR_NONE;
8899 mmplayer_t *player = (mmplayer_t *)hplayer;
8900 MMMessageParamType msg_param = {0, };
8903 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8905 LOGW("state changed storage %d:%d", id, state);
8907 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8908 return MM_ERROR_NONE;
8910 /* FIXME: text path should be handled separately. */
8911 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8912 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8913 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8914 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8915 LOGW("external storage is removed");
8917 if (player->msg_posted == FALSE) {
8918 memset(&msg_param, 0, sizeof(MMMessageParamType));
8919 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8920 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8921 player->msg_posted = TRUE;
8924 /* unrealize the player */
8925 ret = _mmplayer_unrealize(hplayer);
8926 if (ret != MM_ERROR_NONE)
8927 LOGE("failed to unrealize");
8935 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8937 int ret = MM_ERROR_NONE;
8938 mmplayer_t *player = (mmplayer_t *)hplayer;
8939 int idx = 0, total = 0;
8940 gchar *result = NULL, *tmp = NULL;
8943 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8944 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8946 total = *num = g_list_length(player->adaptive_info.var_list);
8948 LOGW("There is no stream variant info.");
8952 result = g_strdup("");
8953 for (idx = 0 ; idx < total ; idx++) {
8954 stream_variant_t *v_data = NULL;
8955 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8958 gchar data[64] = {0};
8959 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8961 tmp = g_strconcat(result, data, NULL);
8965 LOGW("There is no variant data in %d", idx);
8970 *var_info = (char *)result;
8972 LOGD("variant info %d:%s", *num, *var_info);
8978 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8980 int ret = MM_ERROR_NONE;
8981 mmplayer_t *player = (mmplayer_t *)hplayer;
8984 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8986 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8988 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8989 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8990 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8992 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8993 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8994 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8995 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8997 /* FIXME: seek to current position for applying new variant limitation */
9006 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9008 int ret = MM_ERROR_NONE;
9009 mmplayer_t *player = (mmplayer_t *)hplayer;
9012 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9013 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9015 *bandwidth = player->adaptive_info.limit.bandwidth;
9016 *width = player->adaptive_info.limit.width;
9017 *height = player->adaptive_info.limit.height;
9019 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9026 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9028 int ret = MM_ERROR_NONE;
9029 mmplayer_t *player = (mmplayer_t *)hplayer;
9032 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9033 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9034 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9036 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9038 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9039 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9040 else /* live case */
9041 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9043 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9050 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9052 #define IDX_FIRST_SW_CODEC 0
9053 mmplayer_t *player = (mmplayer_t *)hplayer;
9054 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9055 const char *attr_name = NULL;
9056 const char *default_type = NULL;
9057 const char *element_hw = NULL;
9058 const char *element_sw = NULL;
9061 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9063 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9065 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9066 switch (stream_type) {
9067 case MM_PLAYER_STREAM_TYPE_AUDIO:
9068 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9069 default_type = player->ini.audiocodec_default_type;
9070 element_hw = player->ini.audiocodec_element_hw;
9071 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9073 case MM_PLAYER_STREAM_TYPE_VIDEO:
9074 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9075 default_type = player->ini.videocodec_default_type;
9076 element_hw = player->ini.videocodec_element_hw;
9077 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9080 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9081 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9085 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9087 if (!strcmp(default_type, "sw"))
9088 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9090 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9092 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9093 codec_type = default_codec_type;
9095 /* to support codec selection, codec info have to be added in ini file.
9096 in case of hw codec is selected, filter elements should be applied
9097 depending on the hw capabilities. */
9098 if (codec_type != default_codec_type) {
9099 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9100 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9101 LOGE("There is no codec for type %d", codec_type);
9102 return MM_ERROR_PLAYER_NO_OP;
9105 LOGD("sorting is required");
9106 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9107 player->need_audio_dec_sorting = TRUE;
9109 player->need_video_dec_sorting = TRUE;
9112 LOGD("update %s codec_type to %d", attr_name, codec_type);
9113 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9116 return MM_ERROR_NONE;
9120 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9122 mmplayer_t *player = (mmplayer_t *)hplayer;
9123 GstElement *rg_vol_element = NULL;
9127 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9129 player->sound.rg_enable = enabled;
9131 /* just hold rgvolume enable value if pipeline is not ready */
9132 if (!player->pipeline || !player->pipeline->audiobin) {
9133 LOGD("pipeline is not ready. holding rgvolume enable value");
9134 return MM_ERROR_NONE;
9137 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9139 if (!rg_vol_element) {
9140 LOGD("rgvolume element is not created");
9141 return MM_ERROR_PLAYER_INTERNAL;
9145 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9147 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9151 return MM_ERROR_NONE;
9155 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9157 mmplayer_t *player = (mmplayer_t *)hplayer;
9158 GstElement *rg_vol_element = NULL;
9159 gboolean enable = FALSE;
9163 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9164 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9166 /* just hold enable_rg value if pipeline is not ready */
9167 if (!player->pipeline || !player->pipeline->audiobin) {
9168 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9169 *enabled = player->sound.rg_enable;
9170 return MM_ERROR_NONE;
9173 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9175 if (!rg_vol_element) {
9176 LOGD("rgvolume element is not created");
9177 return MM_ERROR_PLAYER_INTERNAL;
9180 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9181 *enabled = (bool)enable;
9185 return MM_ERROR_NONE;
9189 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9191 mmplayer_t *player = (mmplayer_t *)hplayer;
9192 MMHandleType attrs = 0;
9194 int ret = MM_ERROR_NONE;
9198 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9200 attrs = MMPLAYER_GET_ATTRS(player);
9201 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9203 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9205 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9206 return MM_ERROR_PLAYER_INTERNAL;
9209 player->video_roi.scale_x = scale_x;
9210 player->video_roi.scale_y = scale_y;
9211 player->video_roi.scale_width = scale_width;
9212 player->video_roi.scale_height = scale_height;
9214 /* check video sinkbin is created */
9215 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9216 return MM_ERROR_NONE;
9218 if (!gst_video_overlay_set_video_roi_area(
9219 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9220 scale_x, scale_y, scale_width, scale_height))
9221 ret = MM_ERROR_PLAYER_INTERNAL;
9223 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9224 scale_x, scale_y, scale_width, scale_height);
9232 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9234 mmplayer_t *player = (mmplayer_t *)hplayer;
9235 int ret = MM_ERROR_NONE;
9239 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9240 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9242 *scale_x = player->video_roi.scale_x;
9243 *scale_y = player->video_roi.scale_y;
9244 *scale_width = player->video_roi.scale_width;
9245 *scale_height = player->video_roi.scale_height;
9247 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9248 *scale_x, *scale_y, *scale_width, *scale_height);
9254 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9256 mmplayer_t *player = (mmplayer_t *)hplayer;
9260 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9262 player->client_pid = pid;
9264 LOGD("client pid[%d] %p", pid, player);
9268 return MM_ERROR_NONE;
9272 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9274 mmplayer_t *player = (mmplayer_t *)hplayer;
9275 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9276 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9280 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9281 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9284 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9286 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9288 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9289 return MM_ERROR_NONE;
9291 /* in case of audio codec default type is HW */
9293 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9294 if (player->ini.support_audio_effect)
9295 return MM_ERROR_NONE;
9296 elem_id = MMPLAYER_A_FILTER;
9298 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9299 if (player->ini.support_replaygain_control)
9300 return MM_ERROR_NONE;
9301 elem_id = MMPLAYER_A_RGVOL;
9303 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9304 if (player->ini.support_pitch_control)
9305 return MM_ERROR_NONE;
9306 elem_id = MMPLAYER_A_PITCH;
9308 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9309 if (player->ini.support_audio_effect)
9310 return MM_ERROR_NONE;
9312 /* default case handling is not required */
9315 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9316 LOGW("audio control option [%d] is not available", opt);
9319 /* setting pcm exporting option is allowed before READY state */
9320 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9321 return MM_ERROR_PLAYER_INVALID_STATE;
9323 /* check whether the audio filter exist or not after READY state,
9324 because the sw codec could be added during auto-plugging in some cases */
9325 if (!player->pipeline ||
9326 !player->pipeline->audiobin ||
9327 !player->pipeline->audiobin[elem_id].gst) {
9328 LOGW("there is no audio elem [%d]", elem_id);
9333 LOGD("audio control opt %d, available %d", opt, *available);
9337 return MM_ERROR_NONE;
9341 __mmplayer_update_duration_value(mmplayer_t *player)
9343 gboolean ret = FALSE;
9344 gint64 dur_nsec = 0;
9345 LOGD("try to update duration");
9347 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9348 player->duration = dur_nsec;
9349 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9353 if (player->duration < 0) {
9354 LOGW("duration is Non-Initialized !!!");
9355 player->duration = 0;
9358 /* update streaming service type */
9359 player->streaming_type = _mmplayer_get_stream_service_type(player);
9361 /* check duration is OK */
9362 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9363 /* FIXIT : find another way to get duration here. */
9364 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9370 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9372 /* update audio params
9373 NOTE : We need original audio params and it can be only obtained from src pad of audio
9374 decoder. Below code only valid when we are not using 'resampler' just before
9375 'audioconverter'. */
9376 GstCaps *caps_a = NULL;
9378 gint samplerate = 0, channels = 0;
9379 GstStructure *p = NULL;
9380 GstElement *aconv = NULL;
9382 LOGD("try to update audio attrs");
9384 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9386 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9387 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9388 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9389 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9391 LOGE("there is no audio converter");
9395 pad = gst_element_get_static_pad(aconv, "sink");
9398 LOGW("failed to get pad from audio converter");
9402 caps_a = gst_pad_get_current_caps(pad);
9404 LOGW("not ready to get audio caps");
9405 gst_object_unref(pad);
9409 p = gst_caps_get_structure(caps_a, 0);
9410 gst_structure_get_int(p, "rate", &samplerate);
9411 gst_structure_get_int(p, "channels", &channels);
9413 mm_player_set_attribute((MMHandleType)player, NULL,
9414 "content_audio_samplerate", samplerate,
9415 "content_audio_channels", channels, NULL);
9417 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9419 gst_caps_unref(caps_a);
9420 gst_object_unref(pad);
9426 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9428 LOGD("try to update video attrs");
9430 GstCaps *caps_v = NULL;
9434 GstStructure *p = NULL;
9436 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9437 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9439 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9441 LOGD("no videosink sink pad");
9445 caps_v = gst_pad_get_current_caps(pad);
9446 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9447 if (!caps_v && player->v_stream_caps) {
9448 caps_v = player->v_stream_caps;
9449 gst_caps_ref(caps_v);
9453 LOGD("no negotiated caps from videosink");
9454 gst_object_unref(pad);
9458 p = gst_caps_get_structure(caps_v, 0);
9459 gst_structure_get_int(p, "width", &width);
9460 gst_structure_get_int(p, "height", &height);
9462 mm_player_set_attribute((MMHandleType)player, NULL,
9463 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9465 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9467 SECURE_LOGD("width : %d height : %d", width, height);
9469 gst_caps_unref(caps_v);
9470 gst_object_unref(pad);
9473 mm_player_set_attribute((MMHandleType)player, NULL,
9474 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9475 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9482 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9484 gboolean ret = FALSE;
9485 guint64 data_size = 0;
9489 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9490 if (!player->duration)
9493 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9494 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9495 if (stat(path, &sb) == 0)
9496 data_size = (guint64)sb.st_size;
9498 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9499 data_size = player->http_content_size;
9502 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9505 guint64 bitrate = 0;
9506 guint64 msec_dur = 0;
9508 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9510 bitrate = data_size * 8 * 1000 / msec_dur;
9511 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9512 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9513 mm_player_set_attribute((MMHandleType)player, NULL,
9514 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9517 LOGD("player duration is less than 0");
9521 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9522 if (player->total_bitrate) {
9523 mm_player_set_attribute((MMHandleType)player, NULL,
9524 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9533 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9535 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9536 data->uri_type = uri_type;
9540 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9542 int ret = MM_ERROR_PLAYER_INVALID_URI;
9544 char *buffer = NULL;
9545 char *seperator = strchr(path, ',');
9546 char ext[100] = {0,}, size[100] = {0,};
9549 if ((buffer = strstr(path, "ext="))) {
9550 buffer += strlen("ext=");
9552 if (strlen(buffer)) {
9553 strncpy(ext, buffer, 99);
9555 if ((seperator = strchr(ext, ','))
9556 || (seperator = strchr(ext, ' '))
9557 || (seperator = strchr(ext, '\0'))) {
9558 seperator[0] = '\0';
9563 if ((buffer = strstr(path, "size="))) {
9564 buffer += strlen("size=");
9566 if (strlen(buffer) > 0) {
9567 strncpy(size, buffer, 99);
9569 if ((seperator = strchr(size, ','))
9570 || (seperator = strchr(size, ' '))
9571 || (seperator = strchr(size, '\0'))) {
9572 seperator[0] = '\0';
9575 mem_size = atoi(size);
9580 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9582 if (mem_size && param) {
9583 if (data->input_mem.buf)
9584 free(data->input_mem.buf);
9585 data->input_mem.buf = malloc(mem_size);
9587 if (data->input_mem.buf) {
9588 memcpy(data->input_mem.buf, param, mem_size);
9589 data->input_mem.len = mem_size;
9590 ret = MM_ERROR_NONE;
9592 LOGE("failed to alloc mem %d", mem_size);
9593 ret = MM_ERROR_PLAYER_INTERNAL;
9596 data->input_mem.offset = 0;
9597 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9604 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9606 gchar *location = NULL;
9609 int ret = MM_ERROR_NONE;
9611 if ((path = strstr(uri, "file://"))) {
9612 location = g_filename_from_uri(uri, NULL, &err);
9613 if (!location || (err != NULL)) {
9614 LOGE("Invalid URI '%s' for filesrc: %s", path,
9615 (err != NULL) ? err->message : "unknown error");
9619 MMPLAYER_FREEIF(location);
9621 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9622 return MM_ERROR_PLAYER_INVALID_URI;
9624 LOGD("path from uri: %s", location);
9627 path = (location != NULL) ? (location) : ((char *)uri);
9630 ret = _mmplayer_exist_file_path(path);
9632 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9633 if (ret == MM_ERROR_NONE) {
9634 if (_mmplayer_is_sdp_file(path)) {
9635 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9636 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9637 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9639 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9640 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9642 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9643 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9645 LOGE("invalid uri, could not play..");
9646 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9649 MMPLAYER_FREEIF(location);
9654 static mmplayer_video_decoded_data_info_t *
9655 __mmplayer_create_stream_from_pad(GstPad *pad)
9657 GstCaps *caps = NULL;
9658 GstStructure *structure = NULL;
9659 unsigned int fourcc = 0;
9660 const gchar *string_format = NULL;
9661 mmplayer_video_decoded_data_info_t *stream = NULL;
9663 MMPixelFormatType format;
9666 caps = gst_pad_get_current_caps(pad);
9668 LOGE("Caps is NULL.");
9673 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9675 structure = gst_caps_get_structure(caps, 0);
9676 gst_structure_get_int(structure, "width", &width);
9677 gst_structure_get_int(structure, "height", &height);
9678 string_format = gst_structure_get_string(structure, "format");
9681 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9682 format = _mmplayer_get_pixtype(fourcc);
9683 gst_video_info_from_caps(&info, caps);
9684 gst_caps_unref(caps);
9687 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9688 LOGE("Wrong condition!!");
9692 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9694 LOGE("failed to alloc mem for video data");
9698 stream->width = width;
9699 stream->height = height;
9700 stream->format = format;
9701 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9707 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9709 unsigned int pitch = 0;
9710 unsigned int size = 0;
9712 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9715 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9716 bo = gst_tizen_memory_get_bos(mem, index);
9718 stream->bo[index] = tbm_bo_ref(bo);
9720 LOGE("failed to get bo for index %d", index);
9723 for (index = 0; index < stream->plane_num; index++) {
9724 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9725 stream->stride[index] = pitch;
9727 stream->elevation[index] = size / pitch;
9729 stream->elevation[index] = stream->height;
9734 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9736 if (stream->format == MM_PIXEL_FORMAT_I420) {
9737 int ret = TBM_SURFACE_ERROR_NONE;
9738 tbm_surface_h surface;
9739 tbm_surface_info_s info;
9741 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9743 ret = tbm_surface_get_info(surface, &info);
9744 if (ret != TBM_SURFACE_ERROR_NONE) {
9745 tbm_surface_destroy(surface);
9749 tbm_surface_destroy(surface);
9750 stream->stride[0] = info.planes[0].stride;
9751 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9752 stream->stride[1] = info.planes[1].stride;
9753 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9754 stream->stride[2] = info.planes[2].stride;
9755 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9756 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9757 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9758 stream->stride[0] = stream->width * 4;
9759 stream->elevation[0] = stream->height;
9760 stream->bo_size = stream->stride[0] * stream->height;
9762 LOGE("Not support format %d", stream->format);
9770 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9772 tbm_bo_handle thandle;
9774 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9775 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9776 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9780 unsigned char *src = NULL;
9781 unsigned char *dest = NULL;
9782 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9784 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9786 LOGE("fail to gst_memory_map");
9790 if (!mapinfo.data) {
9791 LOGE("data pointer is wrong");
9795 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9796 if (!stream->bo[0]) {
9797 LOGE("Fail to tbm_bo_alloc!!");
9801 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9803 LOGE("thandle pointer is wrong");
9807 if (stream->format == MM_PIXEL_FORMAT_I420) {
9808 src_stride[0] = GST_ROUND_UP_4(stream->width);
9809 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9810 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9811 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9814 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9815 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9817 for (i = 0; i < 3; i++) {
9818 src = mapinfo.data + src_offset[i];
9819 dest = thandle.ptr + dest_offset[i];
9824 for (j = 0; j < stream->height >> k; j++) {
9825 memcpy(dest, src, stream->width>>k);
9826 src += src_stride[i];
9827 dest += stream->stride[i];
9830 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9831 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9833 LOGE("Not support format %d", stream->format);
9837 tbm_bo_unmap(stream->bo[0]);
9838 gst_memory_unmap(mem, &mapinfo);
9844 tbm_bo_unmap(stream->bo[0]);
9847 gst_memory_unmap(mem, &mapinfo);
9853 __mmplayer_set_pause_state(mmplayer_t *player)
9855 if (player->sent_bos)
9858 /* rtsp case, get content attrs by GstMessage */
9859 if (MMPLAYER_IS_RTSP_STREAMING(player))
9862 /* it's first time to update all content attrs. */
9863 _mmplayer_update_content_attrs(player, ATTR_ALL);
9867 __mmplayer_set_playing_state(mmplayer_t *player)
9869 gchar *audio_codec = NULL;
9871 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9872 /* initialize because auto resume is done well. */
9873 player->resumed_by_rewind = FALSE;
9874 player->playback_rate = 1.0;
9877 if (player->sent_bos)
9880 /* try to get content metadata */
9882 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9883 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9884 * legacy mmfw-player api
9886 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9888 if ((player->cmd == MMPLAYER_COMMAND_START)
9889 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9890 __mmplayer_handle_missed_plugin(player);
9893 /* check audio codec field is set or not
9894 * we can get it from typefinder or codec's caps.
9896 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9898 /* The codec format can't be sent for audio only case like amr, mid etc.
9899 * Because, parser don't make related TAG.
9900 * So, if it's not set yet, fill it with found data.
9903 if (g_strrstr(player->type, "audio/midi"))
9904 audio_codec = "MIDI";
9905 else if (g_strrstr(player->type, "audio/x-amr"))
9906 audio_codec = "AMR";
9907 else if (g_strrstr(player->type, "audio/mpeg")
9908 && !g_strrstr(player->type, "mpegversion=(int)1"))
9909 audio_codec = "AAC";
9911 audio_codec = "unknown";
9913 if (mm_player_set_attribute((MMHandleType)player, NULL,
9914 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9915 LOGE("failed to set attribute");
9917 LOGD("set audio codec type with caps");