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 /* store it as it's sink element */
1151 __mmplayer_add_sink(player, fakesink, FALSE);
1153 gst_bin_add(GST_BIN(pipeline), fakesink);
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");
1162 gst_object_unref(GST_OBJECT(fakesink));
1166 if (strstr(name, "video")) {
1167 if (player->v_stream_caps) {
1168 gst_caps_unref(player->v_stream_caps);
1169 player->v_stream_caps = NULL;
1171 if (player->ini.set_dump_element_flag)
1172 __mmplayer_add_dump_buffer_probe(player, fakesink);
1175 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1176 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1180 gst_object_unref(GST_OBJECT(sinkpad));
1187 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1189 GstElement *pipeline = NULL;
1190 GstElement *concat = NULL;
1193 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1195 concat = gst_element_factory_make("concat", NULL);
1197 LOGE("failed to create concat");
1201 LOGD("Create concat [%d] element", elem_idx);
1203 player->pipeline->mainbin[elem_idx].id = elem_idx;
1204 player->pipeline->mainbin[elem_idx].gst = concat;
1206 gst_element_set_state(concat, GST_STATE_PAUSED);
1208 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1209 gst_bin_add(GST_BIN(pipeline), concat);
1216 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1218 GstElement *pipeline = NULL;
1219 GstElement *selector = NULL;
1220 GstPad *srcpad = NULL;
1223 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1225 selector = gst_element_factory_make("input-selector", NULL);
1227 LOGE("failed to create input-selector");
1230 g_object_set(selector, "sync-streams", TRUE, NULL);
1232 player->pipeline->mainbin[elem_idx].id = elem_idx;
1233 player->pipeline->mainbin[elem_idx].gst = selector;
1235 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1237 srcpad = gst_element_get_static_pad(selector, "src");
1239 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1240 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1241 __mmplayer_gst_selector_blocked, NULL, NULL);
1242 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1243 __mmplayer_gst_selector_event_probe, player, NULL);
1245 gst_element_set_state(selector, GST_STATE_PAUSED);
1247 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1248 gst_bin_add(GST_BIN(pipeline), selector);
1250 gst_object_unref(GST_OBJECT(srcpad));
1257 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1259 mmplayer_t *player = (mmplayer_t *)data;
1260 GstElement *combiner = NULL;
1261 GstCaps *caps = NULL;
1262 GstStructure *str = NULL;
1263 const gchar *name = NULL;
1264 GstPad *sinkpad = NULL;
1265 gboolean first_track = FALSE;
1266 gboolean caps_ret = TRUE;
1268 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1269 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1272 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1273 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1275 LOGD("pad-added signal handling");
1277 /* get mimetype from caps */
1278 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1282 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1284 LOGD("detected mimetype : %s", name);
1287 if (strstr(name, "video")) {
1289 gchar *caps_str = NULL;
1291 caps_str = gst_caps_to_string(caps);
1292 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1293 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1294 player->set_mode.video_zc = true;
1296 MMPLAYER_FREEIF(caps_str);
1298 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1299 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1301 LOGD("surface type : %d", stype);
1303 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1304 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1308 /* in case of exporting video frame, it requires the 360 video filter.
1309 * it will be handled in _no_more_pads(). */
1310 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1311 __mmplayer_gst_make_fakesink(player, pad, name);
1315 if (MMPLAYER_USE_DECODEBIN(player)) {
1316 LOGD("video selector is required");
1317 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1319 LOGD("video concat is required");
1320 elem_idx = MMPLAYER_M_V_CONCAT;
1322 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1323 } else if (strstr(name, "audio")) {
1324 gint samplerate = 0;
1327 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1328 if (player->build_audio_offload)
1329 player->no_more_pad = TRUE; /* remove state holder */
1330 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1334 gst_structure_get_int(str, "rate", &samplerate);
1335 gst_structure_get_int(str, "channels", &channels);
1337 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1338 __mmplayer_gst_make_fakesink(player, pad, name);
1341 if (MMPLAYER_USE_DECODEBIN(player)) {
1342 LOGD("audio selector is required");
1343 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1345 LOGD("audio concat is required");
1346 elem_idx = MMPLAYER_M_A_CONCAT;
1348 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1350 } else if (strstr(name, "text")) {
1351 if (MMPLAYER_USE_DECODEBIN(player)) {
1352 LOGD("text selector is required");
1353 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1355 LOGD("text concat is required");
1356 elem_idx = MMPLAYER_M_T_CONCAT;
1358 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1360 LOGE("invalid caps info");
1364 /* check selector and create it */
1365 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1366 if (MMPLAYER_USE_DECODEBIN(player))
1367 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1369 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1375 LOGD("Combiner element is already created.");
1379 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1381 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1383 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1384 LOGE("failed to link combiner");
1385 gst_object_unref(GST_OBJECT(combiner));
1390 if (MMPLAYER_USE_DECODEBIN(player)) {
1391 LOGD("this track will be activated");
1392 g_object_set(combiner, "active-pad", sinkpad, NULL);
1396 if (MMPLAYER_USE_DECODEBIN(player)) {
1397 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1399 /* apply the text track information */
1400 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1401 mm_player_set_attribute((MMHandleType)player, NULL,
1402 "content_text_track_num", player->track[stream_type].total_track_num,
1403 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1404 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1411 gst_caps_unref(caps);
1414 gst_object_unref(GST_OBJECT(sinkpad));
1422 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1424 GstPad *srcpad = NULL;
1427 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1429 LOGD("type %d", type);
1432 LOGD("there is no %d track", type);
1436 srcpad = gst_element_get_static_pad(combiner, "src");
1438 LOGE("failed to get srcpad from combiner");
1442 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1444 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1446 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1447 if (player->track[type].block_id) {
1448 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1449 player->track[type].block_id = 0;
1453 gst_object_unref(GST_OBJECT(srcpad));
1462 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1464 gint active_index = 0;
1467 MMPLAYER_RETURN_IF_FAIL(player);
1469 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1471 /* change track to active pad */
1472 active_index = player->track[type].active_track_index;
1473 if ((active_index != DEFAULT_TRACK_INDEX) &&
1474 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1475 LOGW("failed to change %d type track to %d", type, active_index);
1476 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1480 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1481 mm_player_set_attribute((MMHandleType)player, NULL,
1482 "content_text_track_num", player->track[type].total_track_num,
1483 "current_text_track_index", player->track[type].active_track_index, NULL);
1490 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1493 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1495 if (!audio_selector) {
1496 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1498 /* in case the source is changed, output can be changed. */
1499 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1500 LOGD("remove previous audiobin if it exist");
1502 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1503 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1505 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1506 MMPLAYER_FREEIF(player->pipeline->audiobin);
1509 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1510 _mmplayer_pipeline_complete(NULL, player);
1515 /* apply the audio track information */
1516 if (MMPLAYER_USE_DECODEBIN(player))
1517 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1519 /* create audio sink path */
1520 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1521 LOGE("failed to create audio sink path");
1530 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1533 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1535 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1536 LOGD("text path is not supported");
1540 /* apply the text track information */
1541 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1543 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1544 player->has_closed_caption = TRUE;
1546 /* create text decode path */
1547 player->no_more_pad = TRUE;
1549 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1550 LOGE("failed to create text sink path");
1559 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1561 gint64 dur_bytes = 0L;
1564 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1565 player->pipeline->mainbin && player->streamer, FALSE);
1567 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1568 LOGE("fail to get duration.");
1570 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1571 * use file information was already set on Q2 when it was created. */
1572 _mm_player_streaming_set_queue2(player->streamer,
1573 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1574 TRUE, /* use_buffering */
1575 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1576 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1583 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1585 mmplayer_t *player = NULL;
1586 GstElement *video_selector = NULL;
1587 GstElement *audio_selector = NULL;
1588 GstElement *text_selector = NULL;
1591 player = (mmplayer_t *)data;
1593 LOGD("no-more-pad signal handling");
1595 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1596 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1597 LOGW("player is shutting down");
1601 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1602 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1603 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1604 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1605 LOGE("failed to set queue2 buffering");
1610 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1611 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1612 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1614 if (!video_selector && !audio_selector && !text_selector) {
1615 LOGW("there is no selector");
1616 player->no_more_pad = TRUE;
1620 /* create video path followed by video-select */
1621 if (video_selector && !audio_selector && !text_selector)
1622 player->no_more_pad = TRUE;
1624 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1627 /* create audio path followed by audio-select */
1628 if (audio_selector && !text_selector)
1629 player->no_more_pad = TRUE;
1631 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1634 /* create text path followed by text-select */
1635 __mmplayer_create_text_sink_path(player, text_selector);
1638 _mmplayer_set_reconfigure_state(player, FALSE);
1643 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1645 gboolean ret = FALSE;
1646 GstElement *pipeline = NULL;
1647 GstPad *sinkpad = NULL;
1650 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1651 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1653 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1655 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1657 LOGE("failed to get pad from sinkbin");
1663 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1664 LOGE("failed to link sinkbin for reusing");
1665 goto EXIT; /* exit either pass or fail */
1669 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1670 LOGE("failed to set state(READY) to sinkbin");
1675 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1676 LOGE("failed to add sinkbin to pipeline");
1681 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1682 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1687 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1688 LOGE("failed to set state(PAUSED) to sinkbin");
1697 gst_object_unref(GST_OBJECT(sinkpad));
1705 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1707 mmplayer_t *player = NULL;
1708 GstCaps *caps = NULL;
1709 gchar *caps_str = NULL;
1710 GstStructure *str = NULL;
1711 const gchar *name = NULL;
1712 GstElement *sinkbin = NULL;
1713 gboolean reusing = FALSE;
1714 gboolean caps_ret = TRUE;
1715 gchar *sink_pad_name = "sink";
1718 player = (mmplayer_t *)data;
1721 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1722 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1723 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1725 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1729 gst_caps_unref(caps);
1730 caps = gst_caps_ref(ref_caps);
1733 caps_str = gst_caps_to_string(caps);
1735 LOGD("detected mimetype : %s", name);
1737 if (strstr(name, "audio")) {
1738 if (player->pipeline->audiobin == NULL) {
1739 const gchar *audio_format = gst_structure_get_string(str, "format");
1741 LOGD("original audio format %s", audio_format);
1742 mm_player_set_attribute((MMHandleType)player, NULL,
1743 "content_audio_format", audio_format, strlen(audio_format), NULL);
1746 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1747 LOGE("failed to create audiobin. continuing without audio");
1751 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1752 LOGD("creating audiobin success");
1755 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1756 LOGD("reusing audiobin");
1757 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1759 } else if (strstr(name, "video")) {
1760 /* 1. zero copy is updated at _decode_pad_added()
1761 * 2. NULL surface type is handled in _decode_pad_added() */
1762 LOGD("zero copy %d", player->set_mode.video_zc);
1763 if (player->pipeline->videobin == NULL) {
1764 int surface_type = 0;
1765 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1766 LOGD("display_surface_type (%d)", surface_type);
1768 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1769 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1770 LOGE("failed to acquire video overlay resource");
1774 player->interrupted_by_resource = FALSE;
1776 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1777 LOGE("failed to create videobin. continuing without video");
1781 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1782 LOGD("creating videosink bin success");
1785 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1786 LOGD("re-using videobin");
1787 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1789 } else if (strstr(name, "text")) {
1790 if (player->pipeline->textbin == NULL) {
1791 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1792 LOGE("failed to create text sink bin. continuing without text");
1796 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1797 player->textsink_linked = 1;
1798 LOGD("creating textsink bin success");
1800 if (!player->textsink_linked) {
1801 LOGD("re-using textbin");
1803 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1804 player->textsink_linked = 1;
1806 /* linked textbin exist which means that the external subtitle path exist already */
1807 LOGW("ignoring internal subtitle since external subtitle is available");
1810 sink_pad_name = "text_sink";
1812 LOGW("unknown mime type %s, ignoring it", name);
1816 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1819 LOGD("[handle: %p] success to create and link sink bin", player);
1821 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1822 * streaming task. if the task blocked, then buffer will not flow to the next element
1823 *(autoplugging element). so this is special hack for streaming. please try to remove it
1825 /* dec stream count. we can remove fakesink if it's zero */
1826 if (player->num_dynamic_pad)
1827 player->num_dynamic_pad--;
1829 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1831 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1832 _mmplayer_pipeline_complete(NULL, player);
1836 MMPLAYER_FREEIF(caps_str);
1839 gst_caps_unref(caps);
1845 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1847 int required_angle = 0; /* Angle required for straight view */
1848 int rotation_angle = 0;
1850 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1851 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1853 /* Counter clockwise */
1854 switch (orientation) {
1859 required_angle = 270;
1862 required_angle = 180;
1865 required_angle = 90;
1869 rotation_angle = display_angle + required_angle;
1870 if (rotation_angle >= 360)
1871 rotation_angle -= 360;
1873 /* check if supported or not */
1874 if (rotation_angle % 90) {
1875 LOGD("not supported rotation angle = %d", rotation_angle);
1879 switch (rotation_angle) {
1881 *value = MM_DISPLAY_ROTATION_NONE;
1884 *value = MM_DISPLAY_ROTATION_90;
1887 *value = MM_DISPLAY_ROTATION_180;
1890 *value = MM_DISPLAY_ROTATION_270;
1894 LOGD("setting rotation property value : %d", *value);
1900 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1902 int display_rotation = 0;
1903 gchar *org_orient = NULL;
1904 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1907 LOGE("cannot get content attribute");
1908 return MM_ERROR_PLAYER_INTERNAL;
1911 if (display_angle) {
1912 /* update user rotation */
1913 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1915 /* Counter clockwise */
1916 switch (display_rotation) {
1917 case MM_DISPLAY_ROTATION_NONE:
1920 case MM_DISPLAY_ROTATION_90:
1921 *display_angle = 90;
1923 case MM_DISPLAY_ROTATION_180:
1924 *display_angle = 180;
1926 case MM_DISPLAY_ROTATION_270:
1927 *display_angle = 270;
1930 LOGW("wrong angle type : %d", display_rotation);
1933 LOGD("check user angle: %d", *display_angle);
1937 /* Counter clockwise */
1938 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1941 if (!strcmp(org_orient, "rotate-90"))
1943 else if (!strcmp(org_orient, "rotate-180"))
1945 else if (!strcmp(org_orient, "rotate-270"))
1948 LOGD("original rotation is %s", org_orient);
1950 LOGD("content_video_orientation get fail");
1953 LOGD("check orientation: %d", *orientation);
1956 return MM_ERROR_NONE;
1959 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1961 int rotation_value = 0;
1962 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1963 int display_angle = 0;
1966 /* check video sinkbin is created */
1967 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1970 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1972 /* get rotation value to set */
1973 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1974 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1975 LOGD("set video param : rotate %d", rotation_value);
1978 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1980 MMHandleType attrs = 0;
1984 /* check video sinkbin is created */
1985 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1988 attrs = MMPLAYER_GET_ATTRS(player);
1989 MMPLAYER_RETURN_IF_FAIL(attrs);
1991 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1992 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1993 LOGD("set video param : visible %d", visible);
1996 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1998 MMHandleType attrs = 0;
1999 int display_method = 0;
2002 /* check video sinkbin is created */
2003 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2006 attrs = MMPLAYER_GET_ATTRS(player);
2007 MMPLAYER_RETURN_IF_FAIL(attrs);
2009 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2010 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2011 LOGD("set video param : method %d", display_method);
2014 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2016 MMHandleType attrs = 0;
2020 /* check video sinkbin is created */
2021 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2024 attrs = MMPLAYER_GET_ATTRS(player);
2025 MMPLAYER_RETURN_IF_FAIL(attrs);
2027 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2028 MMPLAYER_RETURN_IF_FAIL(handle);
2030 gst_video_overlay_set_video_roi_area(
2031 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2032 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2033 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2034 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2037 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2039 MMHandleType attrs = 0;
2044 int win_roi_width = 0;
2045 int win_roi_height = 0;
2048 /* check video sinkbin is created */
2049 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2052 attrs = MMPLAYER_GET_ATTRS(player);
2053 MMPLAYER_RETURN_IF_FAIL(attrs);
2055 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2056 MMPLAYER_RETURN_IF_FAIL(handle);
2058 /* It should be set after setting window */
2059 mm_attrs_multiple_get(attrs, NULL,
2060 "display_win_roi_x", &win_roi_x,
2061 "display_win_roi_y", &win_roi_y,
2062 "display_win_roi_width", &win_roi_width,
2063 "display_win_roi_height", &win_roi_height, NULL);
2065 /* After setting window handle, set display roi area */
2066 gst_video_overlay_set_display_roi_area(
2067 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2068 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2069 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2070 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2073 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2075 MMHandleType attrs = 0;
2078 /* check video sinkbin is created */
2079 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2082 attrs = MMPLAYER_GET_ATTRS(player);
2083 MMPLAYER_RETURN_IF_FAIL(attrs);
2085 /* common case if using overlay surface */
2086 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2087 MMPLAYER_RETURN_IF_FAIL(handle);
2089 /* default is using wl_surface_id */
2090 LOGD("set video param : wl_surface_id %d", handle);
2091 gst_video_overlay_set_wl_window_wl_surface_id(
2092 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2097 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2099 gboolean update_all_param = FALSE;
2103 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2104 LOGW("videosink is not ready yet");
2105 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2108 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2109 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2110 return MM_ERROR_PLAYER_INTERNAL;
2113 LOGD("param_name : %s", param_name);
2114 if (!g_strcmp0(param_name, "update_all_param"))
2115 update_all_param = TRUE;
2117 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2118 __mmplayer_video_param_set_display_overlay(player);
2119 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2120 __mmplayer_video_param_set_display_method(player);
2121 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2122 __mmplayer_video_param_set_display_visible(player);
2123 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2124 __mmplayer_video_param_set_display_rotation(player);
2125 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2126 __mmplayer_video_param_set_roi_area(player);
2127 if (update_all_param)
2128 __mmplayer_video_param_set_video_roi_area(player);
2132 return MM_ERROR_NONE;
2135 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2137 gboolean disable_overlay = FALSE;
2140 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2141 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2142 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2144 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2145 LOGW("Display control is not supported");
2146 return MM_ERROR_PLAYER_INTERNAL;
2149 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2151 if (disable == (bool)disable_overlay) {
2152 LOGE("It's the same with current setting: (%d)", disable);
2153 return MM_ERROR_NONE;
2157 LOGE("disable overlay");
2158 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2160 /* release overlay resource */
2161 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2162 LOGE("failed to release overlay resource");
2163 return MM_ERROR_PLAYER_INTERNAL;
2166 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2167 LOGE("failed to acquire video overlay resource");
2168 return MM_ERROR_PLAYER_INTERNAL;
2170 player->interrupted_by_resource = FALSE;
2172 LOGD("enable overlay");
2173 __mmplayer_video_param_set_display_overlay(player);
2174 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2178 return MM_ERROR_NONE;
2182 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2184 int ret = MM_ERROR_NONE;
2185 mmplayer_t *player = (mmplayer_t *)hplayer;
2188 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2190 if (MMPLAYER_USE_DECODEBIN(player)) {
2191 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2196 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2197 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2198 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2200 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2202 /* release decoder resource */
2203 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2204 LOGE("failed to release video decoder resources");
2205 return MM_ERROR_PLAYER_INTERNAL;
2207 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2209 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2213 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2220 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2222 GList *bucket = element_bucket;
2223 mmplayer_gst_element_t *element = NULL;
2224 mmplayer_gst_element_t *prv_element = NULL;
2225 GstElement *tee_element = NULL;
2226 gint successful_link_count = 0;
2230 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2232 prv_element = (mmplayer_gst_element_t *)bucket->data;
2233 bucket = bucket->next;
2235 for (; bucket; bucket = bucket->next) {
2236 element = (mmplayer_gst_element_t *)bucket->data;
2238 if (element && element->gst) {
2239 if (prv_element && prv_element->gst) {
2240 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2242 prv_element->gst = tee_element;
2244 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2245 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2246 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2250 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2251 LOGD("linking [%s] to [%s] success",
2252 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2253 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2254 successful_link_count++;
2255 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2256 LOGD("keep audio-tee element for next audio pipeline branch");
2257 tee_element = prv_element->gst;
2260 LOGD("linking [%s] to [%s] failed",
2261 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2262 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2268 prv_element = element;
2273 return successful_link_count;
2277 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2279 GList *bucket = element_bucket;
2280 mmplayer_gst_element_t *element = NULL;
2281 int successful_add_count = 0;
2285 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2286 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2288 for (; bucket; bucket = bucket->next) {
2289 element = (mmplayer_gst_element_t *)bucket->data;
2291 if (element && element->gst) {
2292 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2293 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2294 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2295 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2298 successful_add_count++;
2304 return successful_add_count;
2308 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2310 mmplayer_t *player = (mmplayer_t *)data;
2311 GstCaps *caps = NULL;
2312 GstStructure *str = NULL;
2314 gboolean caps_ret = TRUE;
2318 MMPLAYER_RETURN_IF_FAIL(pad);
2319 MMPLAYER_RETURN_IF_FAIL(unused);
2320 MMPLAYER_RETURN_IF_FAIL(data);
2322 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2326 LOGD("name = %s", name);
2328 if (strstr(name, "audio")) {
2329 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2331 if (player->audio_stream_changed_cb) {
2332 LOGE("call the audio stream changed cb");
2333 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2335 } else if (strstr(name, "video")) {
2336 if ((name = gst_structure_get_string(str, "format")))
2337 player->set_mode.video_zc = name[0] == 'S';
2339 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2340 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2342 LOGW("invalid caps info");
2347 gst_caps_unref(caps);
2355 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2360 MMPLAYER_RETURN_IF_FAIL(player);
2362 if (player->audio_stream_buff_list) {
2363 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2364 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2367 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2368 __mmplayer_audio_stream_send_data(player, tmp);
2370 MMPLAYER_FREEIF(tmp->pcm_data);
2371 MMPLAYER_FREEIF(tmp);
2374 g_list_free(player->audio_stream_buff_list);
2375 player->audio_stream_buff_list = NULL;
2382 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2384 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2387 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2389 audio_stream.bitrate = a_buffer->bitrate;
2390 audio_stream.channel = a_buffer->channel;
2391 audio_stream.channel_mask = a_buffer->channel_mask;
2392 audio_stream.data_size = a_buffer->data_size;
2393 audio_stream.data = a_buffer->pcm_data;
2394 audio_stream.pcm_format = a_buffer->pcm_format;
2396 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2398 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2404 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2406 mmplayer_t *player = (mmplayer_t *)data;
2407 const gchar *pcm_format = NULL;
2410 guint64 channel_mask = 0;
2411 void *a_data = NULL;
2413 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2414 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2418 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2420 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2421 a_data = mapinfo.data;
2422 a_size = mapinfo.size;
2424 GstCaps *caps = gst_pad_get_current_caps(pad);
2425 GstStructure *structure = gst_caps_get_structure(caps, 0);
2427 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2429 pcm_format = gst_structure_get_string(structure, "format");
2430 gst_structure_get_int(structure, "rate", &rate);
2431 gst_structure_get_int(structure, "channels", &channel);
2432 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2433 gst_caps_unref(GST_CAPS(caps));
2435 /* In case of the sync is false, use buffer list. *
2436 * The num of buffer list depends on the num of audio channels */
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;
2441 if (channel_mask == tmp->channel_mask) {
2443 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2445 if (tmp->data_size + a_size < tmp->buff_size) {
2446 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2447 tmp->data_size += a_size;
2449 /* send data to client */
2450 __mmplayer_audio_stream_send_data(player, tmp);
2452 if (a_size > tmp->buff_size) {
2453 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2454 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2455 if (tmp->pcm_data == NULL) {
2456 LOGE("failed to realloc data.");
2459 tmp->buff_size = a_size;
2461 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2462 memcpy(tmp->pcm_data, a_data, a_size);
2463 tmp->data_size = a_size;
2468 LOGE("data is empty in list.");
2474 /* create new audio stream data for newly found audio channel */
2475 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2476 if (a_buffer == NULL) {
2477 LOGE("failed to alloc data.");
2480 a_buffer->bitrate = rate;
2481 a_buffer->channel = channel;
2482 a_buffer->channel_mask = channel_mask;
2483 a_buffer->data_size = a_size;
2484 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2486 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2487 /* If sync is FALSE, use buffer list to reduce the IPC. */
2488 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2489 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2490 if (a_buffer->pcm_data == NULL) {
2491 LOGE("failed to alloc data.");
2492 MMPLAYER_FREEIF(a_buffer);
2495 memcpy(a_buffer->pcm_data, a_data, a_size);
2497 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2499 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2501 /* If sync is TRUE, send data directly. */
2502 a_buffer->pcm_data = a_data;
2503 __mmplayer_audio_stream_send_data(player, a_buffer);
2504 MMPLAYER_FREEIF(a_buffer);
2508 gst_buffer_unmap(buffer, &mapinfo);
2513 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2515 mmplayer_t *player = (mmplayer_t *)data;
2516 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2517 GstPad *sinkpad = NULL;
2518 GstElement *queue = NULL, *sink = NULL;
2521 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2523 queue = gst_element_factory_make("queue", NULL);
2524 if (queue == NULL) {
2525 LOGD("fail make queue");
2529 sink = gst_element_factory_make("fakesink", NULL);
2531 LOGD("fail make fakesink");
2535 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2537 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2538 LOGW("failed to link queue & sink");
2542 sinkpad = gst_element_get_static_pad(queue, "sink");
2544 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2545 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2549 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2551 gst_object_unref(sinkpad);
2552 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2553 g_object_set(sink, "sync", TRUE, NULL);
2554 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2556 /* keep the first sink reference only */
2557 if (!audiobin[MMPLAYER_A_SINK].gst) {
2558 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2559 audiobin[MMPLAYER_A_SINK].gst = sink;
2563 _mmplayer_add_signal_connection(player,
2565 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2567 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2570 __mmplayer_add_sink(player, sink, FALSE);
2572 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2573 LOGE("failed to sync state");
2577 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2578 LOGE("failed to sync state");
2586 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2588 gst_object_unref(GST_OBJECT(queue));
2592 gst_object_unref(GST_OBJECT(sink));
2596 gst_object_unref(GST_OBJECT(sinkpad));
2604 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2606 mmplayer_t *player = (mmplayer_t *)data;
2609 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2611 player->no_more_pad = TRUE;
2612 _mmplayer_pipeline_complete(NULL, player);
2619 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2621 #define MAX_PROPS_LEN 128
2622 mmplayer_gst_element_t *audiobin = NULL;
2623 gint latency_mode = 0;
2624 gchar *stream_type = NULL;
2625 gchar *latency = NULL;
2627 gchar stream_props[MAX_PROPS_LEN] = {0,};
2628 GstStructure *props = NULL;
2631 * It should be set after player creation through attribute.
2632 * But, it can not be changed during playing.
2635 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2637 audiobin = player->pipeline->audiobin;
2639 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2640 if (player->sound.mute) {
2641 LOGD("mute enabled");
2642 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2645 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2646 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2649 snprintf(stream_props, sizeof(stream_props) - 1,
2650 "props,application.process.id.origin=%d", player->client_pid);
2652 snprintf(stream_props, sizeof(stream_props) - 1,
2653 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2654 stream_type, stream_id, player->client_pid);
2656 props = gst_structure_from_string(stream_props, NULL);
2657 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2658 LOGI("props result[%s].", stream_props);
2659 gst_structure_free(props);
2661 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2663 switch (latency_mode) {
2664 case AUDIO_LATENCY_MODE_LOW:
2665 latency = g_strdup("low");
2667 case AUDIO_LATENCY_MODE_MID:
2668 latency = g_strdup("mid");
2670 case AUDIO_LATENCY_MODE_HIGH:
2671 latency = g_strdup("high");
2674 latency = g_strdup("mid");
2678 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2680 LOGD("audiosink property - latency=%s", latency);
2682 MMPLAYER_FREEIF(latency);
2688 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2690 mmplayer_gst_element_t *audiobin = NULL;
2693 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2694 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2696 audiobin = player->pipeline->audiobin;
2698 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2699 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2700 LOGE("failed to create media stream info");
2701 return MM_ERROR_PLAYER_INTERNAL;
2704 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2706 if (player->video360_yaw_radians <= M_PI &&
2707 player->video360_yaw_radians >= -M_PI &&
2708 player->video360_pitch_radians <= M_PI_2 &&
2709 player->video360_pitch_radians >= -M_PI_2) {
2710 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2711 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2712 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2713 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2714 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2715 "source-orientation-y", player->video360_metadata.init_view_heading,
2716 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2720 return MM_ERROR_NONE;
2724 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2726 mmplayer_gst_element_t *audiobin = NULL;
2727 GstPad *sink_pad = NULL;
2728 GstCaps *acaps = NULL;
2730 int pitch_control = 0;
2731 double pitch_value = 1.0;
2734 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2735 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2737 audiobin = player->pipeline->audiobin;
2739 LOGD("make element for normal audio playback");
2741 /* audio bin structure for playback. {} means optional.
2742 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2744 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2745 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2748 /* for pitch control */
2749 mm_attrs_multiple_get(player->attrs, NULL,
2750 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2751 MM_PLAYER_PITCH_VALUE, &pitch_value,
2754 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2755 if (pitch_control && (player->videodec_linked == 0)) {
2756 GstElementFactory *factory;
2758 factory = gst_element_factory_find("pitch");
2760 gst_object_unref(factory);
2763 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2766 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2767 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2769 LOGW("there is no pitch element");
2774 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2776 /* replaygain volume */
2777 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2778 if (player->sound.rg_enable)
2779 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2781 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2784 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2786 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2787 /* currently, only openalsink uses volume element */
2788 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2789 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2791 if (player->sound.mute) {
2792 LOGD("mute enabled");
2793 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2797 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2799 /* audio effect element. if audio effect is enabled */
2800 if ((strcmp(player->ini.audioeffect_element, ""))
2802 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2803 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2805 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2807 if ((!player->bypass_audio_effect)
2808 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2809 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2810 if (!_mmplayer_audio_effect_custom_apply(player))
2811 LOGI("apply audio effect(custom) setting success");
2815 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2816 && (player->set_mode.rich_audio)) {
2817 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2821 /* create audio sink */
2822 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2823 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2824 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2826 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2827 if (player->is_360_feature_enabled &&
2828 player->is_content_spherical &&
2830 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2831 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2832 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2834 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2836 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2838 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2839 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2840 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2841 gst_caps_unref(acaps);
2843 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2845 player->is_openal_plugin_used = TRUE;
2847 if (player->is_360_feature_enabled && player->is_content_spherical)
2848 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2849 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2852 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2853 (player->videodec_linked && player->ini.use_system_clock)) {
2854 LOGD("system clock will be used.");
2855 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2858 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2859 __mmplayer_gst_set_pulsesink_property(player);
2860 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2861 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2866 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2867 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2869 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2870 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2871 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2872 gst_object_unref(GST_OBJECT(sink_pad));
2874 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2877 return MM_ERROR_NONE;
2879 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2881 return MM_ERROR_PLAYER_INTERNAL;
2885 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2887 mmplayer_gst_element_t *audiobin = NULL;
2888 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2890 gchar *dst_format = NULL;
2892 int dst_samplerate = 0;
2893 int dst_channels = 0;
2894 GstCaps *caps = NULL;
2895 char *caps_str = NULL;
2898 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2899 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2901 audiobin = player->pipeline->audiobin;
2903 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2905 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2907 [case 1] extract interleave audio pcm without playback
2908 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2909 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2911 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2913 [case 2] deinterleave for each channel without playback
2914 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2915 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2917 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2918 - fakesink (sync or not)
2921 [case 3] [case 1(sync only)] + playback
2922 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2924 * src - ... - tee - queue1 - playback path
2925 - queue2 - [case1 pipeline with sync]
2927 [case 4] [case 2(sync only)] + playback
2928 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2930 * src - ... - tee - queue1 - playback path
2931 - queue2 - [case2 pipeline with sync]
2935 /* 1. create tee and playback path
2936 'tee' should be added at first to copy the decoded stream
2938 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2939 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2940 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2942 /* tee - path 1 : for playback path */
2943 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2944 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2946 /* tee - path 2 : for extract path */
2947 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2948 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2951 /* if there is tee, 'tee - path 2' is linked here */
2953 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2956 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2958 /* 2. decide the extract pcm format */
2959 mm_attrs_multiple_get(player->attrs, NULL,
2960 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2961 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2962 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2965 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2966 dst_format, dst_len, dst_samplerate, dst_channels);
2968 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2969 mm_attrs_multiple_get(player->attrs, NULL,
2970 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2971 "content_audio_samplerate", &dst_samplerate,
2972 "content_audio_channels", &dst_channels,
2975 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2976 dst_format, dst_len, dst_samplerate, dst_channels);
2978 /* If there is no enough information, set it to platform default value. */
2979 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2980 LOGD("set platform default format");
2981 dst_format = DEFAULT_PCM_OUT_FORMAT;
2983 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2984 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2987 /* 3. create capsfilter */
2988 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2989 caps = gst_caps_new_simple("audio/x-raw",
2990 "format", G_TYPE_STRING, dst_format,
2991 "rate", G_TYPE_INT, dst_samplerate,
2992 "channels", G_TYPE_INT, dst_channels,
2995 caps_str = gst_caps_to_string(caps);
2996 LOGD("new caps : %s", caps_str);
2998 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3001 gst_caps_unref(caps);
3002 MMPLAYER_FREEIF(caps_str);
3004 /* 4-1. create deinterleave to extract pcm for each channel */
3005 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3006 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3007 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3009 /* audiosink will be added after getting signal for each channel */
3010 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3011 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3012 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3013 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3014 player->no_more_pad = FALSE;
3016 /* 4-2. create fakesink to extract interleaved pcm */
3017 LOGD("add audio fakesink for interleaved audio");
3018 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3019 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3020 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3021 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3023 _mmplayer_add_signal_connection(player,
3024 G_OBJECT(audiobin[extract_sink_id].gst),
3025 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3027 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3030 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3034 return MM_ERROR_NONE;
3036 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3038 return MM_ERROR_PLAYER_INTERNAL;
3042 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3044 int ret = MM_ERROR_NONE;
3045 mmplayer_gst_element_t *audiobin = NULL;
3046 GList *element_bucket = NULL;
3049 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3050 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3052 audiobin = player->pipeline->audiobin;
3054 if (player->build_audio_offload) { /* skip all the audio filters */
3055 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3057 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3058 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3059 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3061 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3065 /* FIXME: need to mention the supportable condition at API reference */
3066 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3067 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3069 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3071 if (ret != MM_ERROR_NONE)
3074 LOGD("success to make audio bin element");
3075 *bucket = element_bucket;
3078 return MM_ERROR_NONE;
3081 LOGE("failed to make audio bin element");
3082 g_list_free(element_bucket);
3086 return MM_ERROR_PLAYER_INTERNAL;
3090 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3092 mmplayer_gst_element_t *first_element = NULL;
3093 mmplayer_gst_element_t *audiobin = NULL;
3095 GstPad *ghostpad = NULL;
3096 GList *element_bucket = NULL;
3100 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3103 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3105 LOGE("failed to allocate memory for audiobin");
3106 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3110 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3111 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3112 if (!audiobin[MMPLAYER_A_BIN].gst) {
3113 LOGE("failed to create audiobin");
3118 player->pipeline->audiobin = audiobin;
3120 /* create audio filters and audiosink */
3121 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3124 /* adding created elements to bin */
3125 LOGD("adding created elements to bin");
3126 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3129 /* linking elements in the bucket by added order. */
3130 LOGD("Linking elements in the bucket by added order.");
3131 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3134 /* get first element's sinkpad for creating ghostpad */
3135 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3136 if (!first_element) {
3137 LOGE("failed to get first elem");
3141 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3143 LOGE("failed to get pad from first element of audiobin");
3147 ghostpad = gst_ghost_pad_new("sink", pad);
3149 LOGE("failed to create ghostpad");
3153 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3154 LOGE("failed to add ghostpad to audiobin");
3158 gst_object_unref(pad);
3160 g_list_free(element_bucket);
3163 return MM_ERROR_NONE;
3166 LOGD("ERROR : releasing audiobin");
3169 gst_object_unref(GST_OBJECT(pad));
3172 gst_object_unref(GST_OBJECT(ghostpad));
3175 g_list_free(element_bucket);
3177 /* release element which are not added to bin */
3178 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3179 /* NOTE : skip bin */
3180 if (audiobin[i].gst) {
3181 GstObject *parent = NULL;
3182 parent = gst_element_get_parent(audiobin[i].gst);
3185 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3186 audiobin[i].gst = NULL;
3188 gst_object_unref(GST_OBJECT(parent));
3192 /* release audiobin with it's children */
3193 if (audiobin[MMPLAYER_A_BIN].gst)
3194 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3196 MMPLAYER_FREEIF(audiobin);
3198 player->pipeline->audiobin = NULL;
3200 return MM_ERROR_PLAYER_INTERNAL;
3204 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3206 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3210 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3212 int ret = MM_ERROR_NONE;
3214 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3215 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3217 MMPLAYER_VIDEO_BO_LOCK(player);
3219 if (player->video_bo_list) {
3220 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3221 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3222 if (tmp && tmp->bo == bo) {
3224 LOGD("release bo %p", bo);
3225 tbm_bo_unref(tmp->bo);
3226 MMPLAYER_VIDEO_BO_UNLOCK(player);
3227 MMPLAYER_VIDEO_BO_SIGNAL(player);
3232 /* hw codec is running or the list was reset for DRC. */
3233 LOGW("there is no bo list.");
3235 MMPLAYER_VIDEO_BO_UNLOCK(player);
3237 LOGW("failed to find bo %p", bo);
3241 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3247 tbm_bo_unref(tmp->bo);
3252 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3255 MMPLAYER_RETURN_IF_FAIL(player);
3257 MMPLAYER_VIDEO_BO_LOCK(player);
3258 if (player->video_bo_list) {
3259 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3260 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3261 player->video_bo_list = NULL;
3263 player->video_bo_size = 0;
3264 MMPLAYER_VIDEO_BO_UNLOCK(player);
3271 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3274 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3275 gboolean ret = TRUE;
3277 /* check DRC, if it is, destroy the prev bo list to create again */
3278 if (player->video_bo_size != size) {
3279 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3280 __mmplayer_video_stream_destroy_bo_list(player);
3281 player->video_bo_size = size;
3284 MMPLAYER_VIDEO_BO_LOCK(player);
3286 if ((!player->video_bo_list) ||
3287 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3289 /* create bo list */
3291 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3293 if (player->video_bo_list) {
3294 /* if bo list did not created all, try it again. */
3295 idx = g_list_length(player->video_bo_list);
3296 LOGD("bo list exist(len: %d)", idx);
3299 for (; idx < player->ini.num_of_video_bo; idx++) {
3300 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3302 LOGE("Fail to alloc bo_info.");
3305 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3307 LOGE("Fail to tbm_bo_alloc.");
3308 MMPLAYER_FREEIF(bo_info);
3311 bo_info->used = FALSE;
3312 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3315 /* update video num buffers */
3316 LOGD("video_num_buffers : %d", idx);
3317 mm_player_set_attribute((MMHandleType)player, NULL,
3318 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3319 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3323 MMPLAYER_VIDEO_BO_UNLOCK(player);
3329 /* get bo from list*/
3330 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3331 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3332 if (tmp && (tmp->used == FALSE)) {
3333 LOGD("found bo %p to use", tmp->bo);
3335 MMPLAYER_VIDEO_BO_UNLOCK(player);
3336 return tbm_bo_ref(tmp->bo);
3340 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3341 MMPLAYER_VIDEO_BO_UNLOCK(player);
3345 if (player->ini.video_bo_timeout <= 0) {
3346 MMPLAYER_VIDEO_BO_WAIT(player);
3348 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3349 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3356 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3358 mmplayer_t *player = (mmplayer_t *)data;
3360 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3362 /* send prerolled pkt */
3363 player->video_stream_prerolled = false;
3365 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3367 /* not to send prerolled pkt again */
3368 player->video_stream_prerolled = true;
3372 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3374 mmplayer_t *player = (mmplayer_t *)data;
3375 mmplayer_video_decoded_data_info_t *stream = NULL;
3376 GstMemory *mem = NULL;
3379 MMPLAYER_RETURN_IF_FAIL(player);
3380 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3382 if (player->video_stream_prerolled) {
3383 player->video_stream_prerolled = false;
3384 LOGD("skip the prerolled pkt not to send it again");
3388 /* clear stream data structure */
3389 stream = __mmplayer_create_stream_from_pad(pad);
3391 LOGE("failed to alloc stream");
3395 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3397 /* set size and timestamp */
3398 mem = gst_buffer_peek_memory(buffer, 0);
3399 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3400 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3402 /* check zero-copy */
3403 if (player->set_mode.video_zc &&
3404 player->set_mode.video_export &&
3405 gst_is_tizen_memory(mem)) {
3406 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3407 stream->internal_buffer = gst_buffer_ref(buffer);
3408 } else { /* sw codec */
3409 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3412 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3416 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3417 LOGE("failed to send video decoded data.");
3424 LOGE("release video stream resource.");
3425 if (gst_is_tizen_memory(mem)) {
3427 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3429 tbm_bo_unref(stream->bo[i]);
3432 /* unref gst buffer */
3433 if (stream->internal_buffer)
3434 gst_buffer_unref(stream->internal_buffer);
3437 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3439 MMPLAYER_FREEIF(stream);
3444 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3446 mmplayer_gst_element_t *videobin = NULL;
3449 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3451 videobin = player->pipeline->videobin;
3453 /* Set spatial media metadata and/or user settings to the element.
3455 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3456 "projection-type", player->video360_metadata.projection_type, NULL);
3458 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3459 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3461 if (player->video360_metadata.full_pano_width_pixels &&
3462 player->video360_metadata.full_pano_height_pixels &&
3463 player->video360_metadata.cropped_area_image_width &&
3464 player->video360_metadata.cropped_area_image_height) {
3465 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3466 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3467 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3468 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3469 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3470 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3471 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3475 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3476 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3477 "horizontal-fov", player->video360_horizontal_fov,
3478 "vertical-fov", player->video360_vertical_fov, NULL);
3481 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3482 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3483 "zoom", 1.0f / player->video360_zoom, NULL);
3486 if (player->video360_yaw_radians <= M_PI &&
3487 player->video360_yaw_radians >= -M_PI &&
3488 player->video360_pitch_radians <= M_PI_2 &&
3489 player->video360_pitch_radians >= -M_PI_2) {
3490 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3491 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3492 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3493 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3494 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3495 "pose-yaw", player->video360_metadata.init_view_heading,
3496 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3499 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3500 "passthrough", !player->is_video360_enabled, NULL);
3507 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3509 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3510 GList *element_bucket = NULL;
3513 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3515 /* create video360 filter */
3516 if (player->is_360_feature_enabled && player->is_content_spherical) {
3517 LOGD("create video360 element");
3518 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3519 __mmplayer_gst_set_video360_property(player);
3523 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3524 LOGD("skip creating the videoconv and rotator");
3525 return MM_ERROR_NONE;
3528 /* in case of sw codec & overlay surface type, except 360 playback.
3529 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3530 LOGD("create video converter: %s", video_csc);
3531 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3534 *bucket = element_bucket;
3536 return MM_ERROR_NONE;
3538 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3539 g_list_free(element_bucket);
3543 return MM_ERROR_PLAYER_INTERNAL;
3547 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3549 gchar *factory_name = NULL;
3551 switch (surface_type) {
3552 case MM_DISPLAY_SURFACE_OVERLAY:
3553 if (strlen(player->ini.videosink_element_overlay) > 0)
3554 factory_name = player->ini.videosink_element_overlay;
3556 case MM_DISPLAY_SURFACE_REMOTE:
3557 case MM_DISPLAY_SURFACE_NULL:
3558 if (strlen(player->ini.videosink_element_fake) > 0)
3559 factory_name = player->ini.videosink_element_fake;
3562 LOGE("unidentified surface type");
3566 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3567 return factory_name;
3571 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3573 gchar *factory_name = NULL;
3574 mmplayer_gst_element_t *videobin = NULL;
3579 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3581 videobin = player->pipeline->videobin;
3582 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3584 attrs = MMPLAYER_GET_ATTRS(player);
3586 LOGE("cannot get content attribute");
3587 return MM_ERROR_PLAYER_INTERNAL;
3590 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3591 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3592 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3593 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3594 "use-tbm", use_tbm, NULL);
3597 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3598 return MM_ERROR_PLAYER_INTERNAL;
3600 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3603 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3604 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3607 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3609 LOGD("disable last-sample");
3610 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3613 if (player->set_mode.video_export) {
3615 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3616 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3617 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3619 _mmplayer_add_signal_connection(player,
3620 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3621 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3623 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3626 _mmplayer_add_signal_connection(player,
3627 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3628 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3630 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3634 if (videobin[MMPLAYER_V_SINK].gst) {
3635 GstPad *sink_pad = NULL;
3636 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3638 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3639 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3640 gst_object_unref(GST_OBJECT(sink_pad));
3642 LOGE("failed to get sink pad from videosink");
3646 return MM_ERROR_NONE;
3651 * - video overlay surface(arm/x86) : tizenwlsink
3654 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3657 GList *element_bucket = NULL;
3658 mmplayer_gst_element_t *first_element = NULL;
3659 mmplayer_gst_element_t *videobin = NULL;
3660 gchar *videosink_factory_name = NULL;
3663 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3666 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3668 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3670 player->pipeline->videobin = videobin;
3673 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3674 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3675 if (!videobin[MMPLAYER_V_BIN].gst) {
3676 LOGE("failed to create videobin");
3680 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3683 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3684 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3686 /* additional setting for sink plug-in */
3687 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3688 LOGE("failed to set video property");
3692 /* store it as it's sink element */
3693 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3695 /* adding created elements to bin */
3696 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3697 LOGE("failed to add elements");
3701 /* Linking elements in the bucket by added order */
3702 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3703 LOGE("failed to link elements");
3707 /* get first element's sinkpad for creating ghostpad */
3708 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3709 if (!first_element) {
3710 LOGE("failed to get first element from bucket");
3714 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3716 LOGE("failed to get pad from first element");
3720 /* create ghostpad */
3721 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3722 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3723 LOGE("failed to add ghostpad to videobin");
3726 gst_object_unref(pad);
3728 /* done. free allocated variables */
3729 g_list_free(element_bucket);
3733 return MM_ERROR_NONE;
3736 LOGE("ERROR : releasing videobin");
3737 g_list_free(element_bucket);
3740 gst_object_unref(GST_OBJECT(pad));
3742 /* release videobin with it's children */
3743 if (videobin[MMPLAYER_V_BIN].gst)
3744 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3746 MMPLAYER_FREEIF(videobin);
3747 player->pipeline->videobin = NULL;
3749 return MM_ERROR_PLAYER_INTERNAL;
3753 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3755 GList *element_bucket = NULL;
3756 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3758 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3759 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3760 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3761 "signal-handoffs", FALSE,
3764 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3765 _mmplayer_add_signal_connection(player,
3766 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3767 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3769 G_CALLBACK(__mmplayer_update_subtitle),
3772 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3773 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3775 if (!player->play_subtitle) {
3776 LOGD("add textbin sink as sink element of whole pipeline.");
3777 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3780 /* adding created elements to bin */
3781 LOGD("adding created elements to bin");
3782 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3783 LOGE("failed to add elements");
3784 g_list_free(element_bucket);
3788 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3789 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3790 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3792 /* linking elements in the bucket by added order. */
3793 LOGD("Linking elements in the bucket by added order.");
3794 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3795 LOGE("failed to link elements");
3796 g_list_free(element_bucket);
3800 /* done. free allocated variables */
3801 g_list_free(element_bucket);
3803 if (textbin[MMPLAYER_T_QUEUE].gst) {
3805 GstPad *ghostpad = NULL;
3807 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3809 LOGE("failed to get sink pad of text queue");
3813 ghostpad = gst_ghost_pad_new("text_sink", pad);
3814 gst_object_unref(pad);
3817 LOGE("failed to create ghostpad of textbin");
3821 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3822 LOGE("failed to add ghostpad to textbin");
3823 gst_object_unref(ghostpad);
3828 return MM_ERROR_NONE;
3832 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3833 LOGE("remove textbin sink from sink list");
3834 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3837 /* release element at __mmplayer_gst_create_text_sink_bin */
3838 return MM_ERROR_PLAYER_INTERNAL;
3842 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3844 mmplayer_gst_element_t *textbin = NULL;
3845 GList *element_bucket = NULL;
3846 int surface_type = 0;
3851 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3854 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3856 LOGE("failed to allocate memory for textbin");
3857 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3861 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3862 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3863 if (!textbin[MMPLAYER_T_BIN].gst) {
3864 LOGE("failed to create textbin");
3869 player->pipeline->textbin = textbin;
3872 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3873 LOGD("surface type for subtitle : %d", surface_type);
3874 switch (surface_type) {
3875 case MM_DISPLAY_SURFACE_OVERLAY:
3876 case MM_DISPLAY_SURFACE_NULL:
3877 case MM_DISPLAY_SURFACE_REMOTE:
3878 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3879 LOGE("failed to make plain text elements");
3890 return MM_ERROR_NONE;
3894 LOGD("ERROR : releasing textbin");
3896 g_list_free(element_bucket);
3898 /* release signal */
3899 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3901 /* release element which are not added to bin */
3902 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3903 /* NOTE : skip bin */
3904 if (textbin[i].gst) {
3905 GstObject *parent = NULL;
3906 parent = gst_element_get_parent(textbin[i].gst);
3909 gst_object_unref(GST_OBJECT(textbin[i].gst));
3910 textbin[i].gst = NULL;
3912 gst_object_unref(GST_OBJECT(parent));
3917 /* release textbin with it's children */
3918 if (textbin[MMPLAYER_T_BIN].gst)
3919 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3921 MMPLAYER_FREEIF(textbin);
3922 player->pipeline->textbin = NULL;
3925 return MM_ERROR_PLAYER_INTERNAL;
3929 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3931 mmplayer_gst_element_t *mainbin = NULL;
3932 mmplayer_gst_element_t *textbin = NULL;
3933 MMHandleType attrs = 0;
3934 GstElement *subsrc = NULL;
3935 GstElement *subparse = NULL;
3936 gchar *subtitle_uri = NULL;
3937 const gchar *charset = NULL;
3943 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3945 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3947 mainbin = player->pipeline->mainbin;
3949 attrs = MMPLAYER_GET_ATTRS(player);
3951 LOGE("cannot get content attribute");
3952 return MM_ERROR_PLAYER_INTERNAL;
3955 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3956 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3957 LOGE("subtitle uri is not proper filepath.");
3958 return MM_ERROR_PLAYER_INVALID_URI;
3961 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3962 LOGE("failed to get storage info of subtitle path");
3963 return MM_ERROR_PLAYER_INVALID_URI;
3966 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3968 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3969 player->subtitle_language_list = NULL;
3970 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3972 /* create the subtitle source */
3973 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3975 LOGE("failed to create filesrc element");
3978 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3980 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3981 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3983 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3984 LOGW("failed to add queue");
3985 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3986 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3987 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3992 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3994 LOGE("failed to create subparse element");
3998 charset = _mmplayer_get_charset(subtitle_uri);
4000 LOGD("detected charset is %s", charset);
4001 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4004 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4005 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4007 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4008 LOGW("failed to add subparse");
4009 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4010 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4011 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4015 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4016 LOGW("failed to link subsrc and subparse");
4020 player->play_subtitle = TRUE;
4021 player->adjust_subtitle_pos = 0;
4023 LOGD("play subtitle using subtitle file");
4025 if (player->pipeline->textbin == NULL) {
4026 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4027 LOGE("failed to create text sink bin. continuing without text");
4031 textbin = player->pipeline->textbin;
4033 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4034 LOGW("failed to add textbin");
4036 /* release signal */
4037 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4039 /* release textbin with it's children */
4040 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4041 MMPLAYER_FREEIF(player->pipeline->textbin);
4042 player->pipeline->textbin = textbin = NULL;
4046 LOGD("link text input selector and textbin ghost pad");
4048 player->textsink_linked = 1;
4049 player->external_text_idx = 0;
4050 LOGI("textsink is linked");
4052 textbin = player->pipeline->textbin;
4053 LOGD("text bin has been created. reuse it.");
4054 player->external_text_idx = 1;
4057 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4058 LOGW("failed to link subparse and textbin");
4062 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4064 LOGE("failed to get sink pad from textsink to probe data");
4068 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4069 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4071 gst_object_unref(pad);
4074 /* create dot. for debugging */
4075 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4078 return MM_ERROR_NONE;
4081 /* release text pipeline resource */
4082 player->textsink_linked = 0;
4084 /* release signal */
4085 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4087 if (player->pipeline->textbin) {
4088 LOGE("remove textbin");
4090 /* release textbin with it's children */
4091 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4092 MMPLAYER_FREEIF(player->pipeline->textbin);
4093 player->pipeline->textbin = NULL;
4097 /* release subtitle elem */
4098 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4099 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4101 return MM_ERROR_PLAYER_INTERNAL;
4105 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4107 mmplayer_t *player = (mmplayer_t *)data;
4108 MMMessageParamType msg = {0, };
4109 GstClockTime duration = 0;
4110 gpointer text = NULL;
4111 guint text_size = 0;
4112 gboolean ret = TRUE;
4113 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4117 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4118 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4120 if (player->is_subtitle_force_drop) {
4121 LOGW("subtitle is dropped forcedly.");
4125 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4126 text = mapinfo.data;
4127 text_size = mapinfo.size;
4129 if (player->set_mode.subtitle_off) {
4130 LOGD("subtitle is OFF.");
4134 if (!text || (text_size == 0)) {
4135 LOGD("There is no subtitle to be displayed.");
4139 msg.data = (void *)text;
4141 duration = GST_BUFFER_DURATION(buffer);
4143 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4144 if (player->duration > GST_BUFFER_PTS(buffer))
4145 duration = player->duration - GST_BUFFER_PTS(buffer);
4148 LOGI("subtitle duration is invalid, subtitle duration change "
4149 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4151 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4153 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4155 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4156 gst_buffer_unmap(buffer, &mapinfo);
4163 static GstPadProbeReturn
4164 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4166 mmplayer_t *player = (mmplayer_t *)u_data;
4167 GstClockTime cur_timestamp = 0;
4168 gint64 adjusted_timestamp = 0;
4169 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4171 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4173 if (player->set_mode.subtitle_off) {
4174 LOGD("subtitle is OFF.");
4178 if (player->adjust_subtitle_pos == 0) {
4179 LOGD("nothing to do");
4183 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4184 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4186 if (adjusted_timestamp < 0) {
4187 LOGD("adjusted_timestamp under zero");
4192 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4193 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4194 GST_TIME_ARGS(cur_timestamp),
4195 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4197 return GST_PAD_PROBE_OK;
4201 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4205 /* check player and subtitlebin are created */
4206 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4207 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4209 if (position == 0) {
4210 LOGD("nothing to do");
4212 return MM_ERROR_NONE;
4215 /* check current position */
4216 player->adjust_subtitle_pos = position;
4218 LOGD("save adjust_subtitle_pos in player");
4222 return MM_ERROR_NONE;
4226 * This function is to create audio or video pipeline for playing.
4228 * @param player [in] handle of player
4230 * @return This function returns zero on success.
4235 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4237 int ret = MM_ERROR_NONE;
4238 mmplayer_gst_element_t *mainbin = NULL;
4239 MMHandleType attrs = 0;
4242 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4244 /* get profile attribute */
4245 attrs = MMPLAYER_GET_ATTRS(player);
4247 LOGE("failed to get content attribute");
4251 /* create pipeline handles */
4252 if (player->pipeline) {
4253 LOGE("pipeline should be released before create new one");
4257 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4259 /* create mainbin */
4260 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4261 if (mainbin == NULL)
4264 /* create pipeline */
4265 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4266 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4267 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4268 LOGE("failed to create pipeline");
4273 player->pipeline->mainbin = mainbin;
4275 /* create the source and decoder elements */
4276 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4277 ret = _mmplayer_gst_build_es_pipeline(player);
4279 if (MMPLAYER_USE_DECODEBIN(player))
4280 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4282 ret = _mmplayer_gst_build_pipeline_with_src(player);
4285 if (ret != MM_ERROR_NONE) {
4286 LOGE("failed to create some elements");
4290 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4291 if (__mmplayer_check_subtitle(player)
4292 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4293 LOGE("failed to create text pipeline");
4296 ret = _mmplayer_gst_add_bus_watch(player);
4297 if (ret != MM_ERROR_NONE) {
4298 LOGE("failed to add bus watch");
4303 return MM_ERROR_NONE;
4306 _mmplayer_bus_watcher_remove(player);
4307 __mmplayer_gst_destroy_pipeline(player);
4308 return MM_ERROR_PLAYER_INTERNAL;
4312 __mmplayer_reset_gapless_state(mmplayer_t *player)
4315 MMPLAYER_RETURN_IF_FAIL(player
4317 && player->pipeline->audiobin
4318 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4320 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4327 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4330 int ret = MM_ERROR_NONE;
4334 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4336 /* cleanup stuffs */
4337 MMPLAYER_FREEIF(player->type);
4338 player->no_more_pad = FALSE;
4339 player->num_dynamic_pad = 0;
4341 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4342 player->subtitle_language_list = NULL;
4343 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4345 MMPLAYER_RECONFIGURE_LOCK(player);
4346 __mmplayer_reset_gapless_state(player);
4347 MMPLAYER_RECONFIGURE_UNLOCK(player);
4349 if (player->streamer) {
4350 _mm_player_streaming_initialize(player->streamer, FALSE);
4351 _mm_player_streaming_destroy(player->streamer);
4352 player->streamer = NULL;
4355 /* cleanup unlinked mime type */
4356 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4357 MMPLAYER_FREEIF(player->unlinked_video_mime);
4358 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4360 /* cleanup running stuffs */
4361 _mmplayer_cancel_eos_timer(player);
4363 /* cleanup gst stuffs */
4364 if (player->pipeline) {
4365 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4366 GstTagList *tag_list = player->pipeline->tag_list;
4368 /* first we need to disconnect all signal hander */
4369 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4372 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4373 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4374 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4375 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4376 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4377 gst_object_unref(bus);
4379 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4380 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4381 if (ret != MM_ERROR_NONE) {
4382 LOGE("fail to change state to NULL");
4383 return MM_ERROR_PLAYER_INTERNAL;
4386 LOGW("succeeded in changing state to NULL");
4388 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4391 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4392 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4394 MMPLAYER_FREEIF(audiobin);
4395 MMPLAYER_FREEIF(videobin);
4396 MMPLAYER_FREEIF(textbin);
4397 MMPLAYER_FREEIF(mainbin);
4401 gst_tag_list_unref(tag_list);
4403 MMPLAYER_FREEIF(player->pipeline);
4405 MMPLAYER_FREEIF(player->album_art);
4407 if (player->type_caps) {
4408 gst_caps_unref(player->type_caps);
4409 player->type_caps = NULL;
4412 if (player->v_stream_caps) {
4413 gst_caps_unref(player->v_stream_caps);
4414 player->v_stream_caps = NULL;
4417 if (player->a_stream_caps) {
4418 gst_caps_unref(player->a_stream_caps);
4419 player->a_stream_caps = NULL;
4422 if (player->s_stream_caps) {
4423 gst_caps_unref(player->s_stream_caps);
4424 player->s_stream_caps = NULL;
4426 _mmplayer_track_destroy(player);
4428 if (player->sink_elements)
4429 g_list_free(player->sink_elements);
4430 player->sink_elements = NULL;
4432 if (player->bufmgr) {
4433 tbm_bufmgr_deinit(player->bufmgr);
4434 player->bufmgr = NULL;
4437 LOGW("finished destroy pipeline");
4445 __mmplayer_gst_realize(mmplayer_t *player)
4448 int ret = MM_ERROR_NONE;
4452 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4454 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4456 ret = __mmplayer_gst_create_pipeline(player);
4458 LOGE("failed to create pipeline");
4462 /* set pipeline state to READY */
4463 /* NOTE : state change to READY must be performed sync. */
4464 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4465 ret = _mmplayer_gst_set_state(player,
4466 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4468 if (ret != MM_ERROR_NONE) {
4469 /* return error if failed to set state */
4470 LOGE("failed to set READY state");
4474 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4476 /* create dot before error-return. for debugging */
4477 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4485 __mmplayer_gst_unrealize(mmplayer_t *player)
4487 int ret = MM_ERROR_NONE;
4491 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4493 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4494 MMPLAYER_PRINT_STATE(player);
4496 /* release miscellaneous information */
4497 __mmplayer_release_misc(player);
4499 /* destroy pipeline */
4500 ret = __mmplayer_gst_destroy_pipeline(player);
4501 if (ret != MM_ERROR_NONE) {
4502 LOGE("failed to destroy pipeline");
4506 /* release miscellaneous information.
4507 these info needs to be released after pipeline is destroyed. */
4508 __mmplayer_release_misc_post(player);
4510 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4518 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4523 LOGW("set_message_callback is called with invalid player handle");
4524 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4527 player->msg_cb = callback;
4528 player->msg_cb_param = user_param;
4530 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4534 return MM_ERROR_NONE;
4538 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4540 int ret = MM_ERROR_NONE;
4545 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4546 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4547 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4549 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4551 if (strstr(uri, "es_buff://")) {
4552 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4553 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4554 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4555 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4557 tmp = g_ascii_strdown(uri, strlen(uri));
4558 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4559 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4561 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4563 } else if (strstr(uri, "mms://")) {
4564 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4565 } else if ((path = strstr(uri, "mem://"))) {
4566 ret = __mmplayer_set_mem_uri(data, path, param);
4568 ret = __mmplayer_set_file_uri(data, uri);
4571 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4572 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4573 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4574 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4576 /* dump parse result */
4577 SECURE_LOGW("incoming uri : %s", uri);
4578 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4579 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4587 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4590 mmplayer_t *player = NULL;
4591 MMMessageParamType msg = {0, };
4593 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4598 LOGE("user_data is null");
4602 player = (mmplayer_t *)user_data;
4604 if (!player->pipeline || !player->attrs) {
4605 LOGW("not initialized");
4609 LOGD("cmd lock player, cmd state : %d", player->cmd);
4610 MMPLAYER_CMD_LOCK(player);
4611 LOGD("cmd locked player");
4613 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4614 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4615 LOGW("player already destroyed");
4616 MMPLAYER_CMD_UNLOCK(player);
4620 player->interrupted_by_resource = TRUE;
4622 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4624 /* get last play position */
4625 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4626 msg.union_type = MM_MSG_UNION_TIME;
4627 msg.time.elapsed = pos;
4628 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4630 LOGW("failed to get play position.");
4633 LOGD("video resource conflict so, resource will be freed by unrealizing");
4634 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4635 LOGE("failed to unrealize");
4637 MMPLAYER_CMD_UNLOCK(player);
4639 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4640 player->hw_resource[res_idx] = NULL;
4644 return TRUE; /* release all the resources */
4648 __mmplayer_initialize_video_roi(mmplayer_t *player)
4650 player->video_roi.scale_x = 0.0;
4651 player->video_roi.scale_y = 0.0;
4652 player->video_roi.scale_width = 1.0;
4653 player->video_roi.scale_height = 1.0;
4657 _mmplayer_create_player(MMHandleType handle)
4659 int ret = MM_ERROR_PLAYER_INTERNAL;
4660 bool enabled = false;
4662 mmplayer_t *player = MM_PLAYER_CAST(handle);
4666 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4668 /* initialize player state */
4669 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4670 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4671 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4672 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4674 /* check current state */
4675 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4677 /* construct attributes */
4678 player->attrs = _mmplayer_construct_attribute(handle);
4680 if (!player->attrs) {
4681 LOGE("Failed to construct attributes");
4685 /* initialize gstreamer with configured parameter */
4686 if (!__mmplayer_init_gstreamer(player)) {
4687 LOGE("Initializing gstreamer failed");
4688 _mmplayer_deconstruct_attribute(handle);
4692 /* create lock. note that g_tread_init() has already called in gst_init() */
4693 g_mutex_init(&player->fsink_lock);
4695 /* create update tag lock */
4696 g_mutex_init(&player->update_tag_lock);
4698 /* create gapless play mutex */
4699 g_mutex_init(&player->gapless_play_thread_mutex);
4701 /* create gapless play cond */
4702 g_cond_init(&player->gapless_play_thread_cond);
4704 /* create gapless play thread */
4705 player->gapless_play_thread =
4706 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4707 if (!player->gapless_play_thread) {
4708 LOGE("failed to create gapless play thread");
4709 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4710 g_mutex_clear(&player->gapless_play_thread_mutex);
4711 g_cond_clear(&player->gapless_play_thread_cond);
4715 player->bus_msg_q = g_queue_new();
4716 if (!player->bus_msg_q) {
4717 LOGE("failed to create queue for bus_msg");
4718 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4722 ret = _mmplayer_initialize_video_capture(player);
4723 if (ret != MM_ERROR_NONE) {
4724 LOGW("video capture is not supported");
4725 /* do not handle as error for headless profile */
4728 /* initialize resource manager */
4729 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4730 __resource_release_cb, player, &player->resource_manager)
4731 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4732 LOGE("failed to create resource manager");
4733 ret = MM_ERROR_PLAYER_INTERNAL;
4737 /* create video bo lock and cond */
4738 g_mutex_init(&player->video_bo_mutex);
4739 g_cond_init(&player->video_bo_cond);
4741 /* create subtitle info lock and cond */
4742 g_mutex_init(&player->subtitle_info_mutex);
4743 g_cond_init(&player->subtitle_info_cond);
4745 player->streaming_type = STREAMING_SERVICE_NONE;
4747 /* give default value of audio effect setting */
4748 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4749 player->sound.rg_enable = false;
4750 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4752 player->play_subtitle = FALSE;
4753 player->has_closed_caption = FALSE;
4754 player->pending_resume = FALSE;
4755 if (player->ini.dump_element_keyword[0][0] == '\0')
4756 player->ini.set_dump_element_flag = FALSE;
4758 player->ini.set_dump_element_flag = TRUE;
4760 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4761 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4762 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4764 /* Set video360 settings to their defaults for just-created player.
4767 player->is_360_feature_enabled = FALSE;
4768 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4769 LOGI("spherical feature info: %d", enabled);
4771 player->is_360_feature_enabled = TRUE;
4773 LOGE("failed to get spherical feature info");
4776 player->is_content_spherical = FALSE;
4777 player->is_video360_enabled = TRUE;
4778 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4779 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4780 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4781 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4782 player->video360_zoom = 1.0f;
4783 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4784 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4786 __mmplayer_initialize_video_roi(player);
4788 /* set player state to null */
4789 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4790 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4794 return MM_ERROR_NONE;
4798 g_mutex_clear(&player->fsink_lock);
4799 /* free update tag lock */
4800 g_mutex_clear(&player->update_tag_lock);
4801 g_queue_free(player->bus_msg_q);
4802 player->bus_msg_q = NULL;
4803 /* free gapless play thread */
4804 if (player->gapless_play_thread) {
4805 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4806 player->gapless_play_thread_exit = TRUE;
4807 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4808 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4810 g_thread_join(player->gapless_play_thread);
4811 player->gapless_play_thread = NULL;
4813 g_mutex_clear(&player->gapless_play_thread_mutex);
4814 g_cond_clear(&player->gapless_play_thread_cond);
4817 /* release attributes */
4818 _mmplayer_deconstruct_attribute(handle);
4826 __mmplayer_init_gstreamer(mmplayer_t *player)
4828 static gboolean initialized = FALSE;
4829 static const int max_argc = 50;
4831 gchar **argv = NULL;
4832 gchar **argv2 = NULL;
4838 LOGD("gstreamer already initialized.");
4843 argc = malloc(sizeof(int));
4844 argv = malloc(sizeof(gchar *) * max_argc);
4845 argv2 = malloc(sizeof(gchar *) * max_argc);
4847 if (!argc || !argv || !argv2)
4850 memset(argv, 0, sizeof(gchar *) * max_argc);
4851 memset(argv2, 0, sizeof(gchar *) * max_argc);
4855 argv[0] = g_strdup("mmplayer");
4858 for (i = 0; i < 5; i++) {
4859 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4860 if (strlen(player->ini.gst_param[i]) > 0) {
4861 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4866 /* we would not do fork for scanning plugins */
4867 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4870 /* check disable registry scan */
4871 if (player->ini.skip_rescan) {
4872 argv[*argc] = g_strdup("--gst-disable-registry-update");
4876 /* check disable segtrap */
4877 if (player->ini.disable_segtrap) {
4878 argv[*argc] = g_strdup("--gst-disable-segtrap");
4882 LOGD("initializing gstreamer with following parameter");
4883 LOGD("argc : %d", *argc);
4886 for (i = 0; i < arg_count; i++) {
4888 LOGD("argv[%d] : %s", i, argv2[i]);
4891 /* initializing gstreamer */
4892 if (!gst_init_check(argc, &argv, &err)) {
4893 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4900 for (i = 0; i < arg_count; i++) {
4902 LOGD("release - argv[%d] : %s", i, argv2[i]);
4904 MMPLAYER_FREEIF(argv2[i]);
4907 MMPLAYER_FREEIF(argv);
4908 MMPLAYER_FREEIF(argv2);
4909 MMPLAYER_FREEIF(argc);
4919 for (i = 0; i < arg_count; i++) {
4920 LOGD("free[%d] : %s", i, argv2[i]);
4921 MMPLAYER_FREEIF(argv2[i]);
4924 MMPLAYER_FREEIF(argv);
4925 MMPLAYER_FREEIF(argv2);
4926 MMPLAYER_FREEIF(argc);
4932 __mmplayer_check_async_state_transition(mmplayer_t *player)
4934 GstState element_state = GST_STATE_VOID_PENDING;
4935 GstState element_pending_state = GST_STATE_VOID_PENDING;
4936 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4937 GstElement *element = NULL;
4938 gboolean async = FALSE;
4940 /* check player handle */
4941 MMPLAYER_RETURN_IF_FAIL(player &&
4943 player->pipeline->mainbin &&
4944 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4947 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4949 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4950 LOGD("don't need to check the pipeline state");
4954 MMPLAYER_PRINT_STATE(player);
4956 /* wait for state transition */
4957 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4958 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4960 if (ret == GST_STATE_CHANGE_FAILURE) {
4961 LOGE(" [%s] state : %s pending : %s",
4962 GST_ELEMENT_NAME(element),
4963 gst_element_state_get_name(element_state),
4964 gst_element_state_get_name(element_pending_state));
4966 /* dump state of all element */
4967 _mmplayer_dump_pipeline_state(player);
4972 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4977 _mmplayer_destroy(MMHandleType handle)
4979 mmplayer_t *player = MM_PLAYER_CAST(handle);
4983 /* check player handle */
4984 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4986 /* destroy can called at anytime */
4987 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4989 /* check async state transition */
4990 __mmplayer_check_async_state_transition(player);
4992 /* release gapless play thread */
4993 if (player->gapless_play_thread) {
4994 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4995 player->gapless_play_thread_exit = TRUE;
4996 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4997 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4999 LOGD("waiting for gapless play thread exit");
5000 g_thread_join(player->gapless_play_thread);
5001 g_mutex_clear(&player->gapless_play_thread_mutex);
5002 g_cond_clear(&player->gapless_play_thread_cond);
5003 LOGD("gapless play thread released");
5006 _mmplayer_release_video_capture(player);
5008 /* release miscellaneous information */
5009 __mmplayer_release_misc(player);
5011 /* release pipeline */
5012 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5013 LOGE("failed to destroy pipeline");
5014 return MM_ERROR_PLAYER_INTERNAL;
5017 __mmplayer_destroy_hw_resource(player);
5019 g_queue_free(player->bus_msg_q);
5021 /* release subtitle info lock and cond */
5022 g_mutex_clear(&player->subtitle_info_mutex);
5023 g_cond_clear(&player->subtitle_info_cond);
5025 __mmplayer_release_dump_list(player->dump_list);
5027 /* release miscellaneous information.
5028 these info needs to be released after pipeline is destroyed. */
5029 __mmplayer_release_misc_post(player);
5031 /* release attributes */
5032 _mmplayer_deconstruct_attribute(handle);
5034 if (player->uri_info.uri_list) {
5035 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5036 player->uri_info.uri_list = NULL;
5040 g_mutex_clear(&player->fsink_lock);
5043 g_mutex_clear(&player->update_tag_lock);
5045 /* release video bo lock and cond */
5046 g_mutex_clear(&player->video_bo_mutex);
5047 g_cond_clear(&player->video_bo_cond);
5051 return MM_ERROR_NONE;
5055 _mmplayer_realize(MMHandleType hplayer)
5057 mmplayer_t *player = (mmplayer_t *)hplayer;
5058 int ret = MM_ERROR_NONE;
5061 MMHandleType attrs = 0;
5065 /* check player handle */
5066 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5068 /* check current state */
5069 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5071 attrs = MMPLAYER_GET_ATTRS(player);
5073 LOGE("fail to get attributes.");
5074 return MM_ERROR_PLAYER_INTERNAL;
5076 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5077 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5079 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5080 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5082 if (ret != MM_ERROR_NONE) {
5083 LOGE("failed to parse profile");
5088 if (uri && (strstr(uri, "es_buff://"))) {
5089 if (strstr(uri, "es_buff://push_mode"))
5090 player->es_player_push_mode = TRUE;
5092 player->es_player_push_mode = FALSE;
5095 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5096 LOGW("mms protocol is not supported format.");
5097 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5100 if (MMPLAYER_IS_STREAMING(player))
5101 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5103 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5105 player->smooth_streaming = FALSE;
5106 player->videodec_linked = 0;
5107 player->audiodec_linked = 0;
5108 player->textsink_linked = 0;
5109 player->is_external_subtitle_present = FALSE;
5110 player->is_external_subtitle_added_now = FALSE;
5111 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5112 player->video360_metadata.is_spherical = -1;
5113 player->is_openal_plugin_used = FALSE;
5114 player->subtitle_language_list = NULL;
5115 player->is_subtitle_force_drop = FALSE;
5117 _mmplayer_track_initialize(player);
5118 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5120 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5121 gint prebuffer_ms = 0, rebuffer_ms = 0;
5123 player->streamer = _mm_player_streaming_create();
5124 _mm_player_streaming_initialize(player->streamer, TRUE);
5126 mm_attrs_multiple_get(player->attrs, NULL,
5127 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5128 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5130 if (prebuffer_ms > 0) {
5131 prebuffer_ms = MAX(prebuffer_ms, 1000);
5132 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5135 if (rebuffer_ms > 0) {
5136 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5137 rebuffer_ms = MAX(rebuffer_ms, 1000);
5138 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5141 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5142 player->streamer->buffering_req.rebuffer_time);
5145 /* realize pipeline */
5146 ret = __mmplayer_gst_realize(player);
5147 if (ret != MM_ERROR_NONE)
5148 LOGE("fail to realize the player.");
5150 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5158 _mmplayer_unrealize(MMHandleType hplayer)
5160 mmplayer_t *player = (mmplayer_t *)hplayer;
5161 int ret = MM_ERROR_NONE;
5162 int rm_ret = MM_ERROR_NONE;
5163 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5167 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5169 MMPLAYER_CMD_UNLOCK(player);
5170 _mmplayer_bus_watcher_remove(player);
5171 /* destroy the gst bus msg thread which is created during realize.
5172 this funct have to be called before getting cmd lock. */
5173 _mmplayer_bus_msg_thread_destroy(player);
5174 MMPLAYER_CMD_LOCK(player);
5176 /* check current state */
5177 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5179 /* check async state transition */
5180 __mmplayer_check_async_state_transition(player);
5182 /* unrealize pipeline */
5183 ret = __mmplayer_gst_unrealize(player);
5185 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5186 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5187 if (rm_ret != MM_ERROR_NONE)
5188 LOGE("failed to release [%d] resources", res_idx);
5191 player->interrupted_by_resource = FALSE;
5198 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5200 mmplayer_t *player = (mmplayer_t *)hplayer;
5202 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5204 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5208 _mmplayer_get_state(MMHandleType hplayer, int *state)
5210 mmplayer_t *player = (mmplayer_t *)hplayer;
5212 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5214 *state = MMPLAYER_CURRENT_STATE(player);
5216 return MM_ERROR_NONE;
5220 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5222 GstElement *vol_element = NULL;
5223 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5226 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5227 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5229 /* check pipeline handle */
5230 if (!player->pipeline || !player->pipeline->audiobin) {
5231 LOGD("'%s' will be applied when audiobin is created", prop_name);
5233 /* NOTE : stored value will be used in create_audiobin
5234 * returning MM_ERROR_NONE here makes application to able to
5235 * set audio volume or mute at anytime.
5237 return MM_ERROR_NONE;
5240 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5241 volume_elem_id = MMPLAYER_A_SINK;
5243 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5245 LOGE("failed to get vol element %d", volume_elem_id);
5246 return MM_ERROR_PLAYER_INTERNAL;
5249 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5251 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5252 LOGE("there is no '%s' property", prop_name);
5253 return MM_ERROR_PLAYER_INTERNAL;
5256 if (!strcmp(prop_name, "volume")) {
5257 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5258 } else if (!strcmp(prop_name, "mute")) {
5259 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5261 LOGE("invalid property %s", prop_name);
5262 return MM_ERROR_PLAYER_INTERNAL;
5265 return MM_ERROR_NONE;
5269 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5271 int ret = MM_ERROR_NONE;
5272 mmplayer_t *player = (mmplayer_t *)hplayer;
5275 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5277 LOGD("volume = %f", volume);
5279 /* invalid factor range or not */
5280 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5281 LOGE("Invalid volume value");
5282 return MM_ERROR_INVALID_ARGUMENT;
5285 player->sound.volume = volume;
5287 ret = __mmplayer_gst_set_volume_property(player, "volume");
5294 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5296 mmplayer_t *player = (mmplayer_t *)hplayer;
5300 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5301 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5303 *volume = player->sound.volume;
5305 LOGD("current vol = %f", *volume);
5308 return MM_ERROR_NONE;
5312 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5314 int ret = MM_ERROR_NONE;
5315 mmplayer_t *player = (mmplayer_t *)hplayer;
5318 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5320 LOGD("mute = %d", mute);
5322 player->sound.mute = mute;
5324 ret = __mmplayer_gst_set_volume_property(player, "mute");
5331 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5333 mmplayer_t *player = (mmplayer_t *)hplayer;
5337 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5338 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5340 *mute = player->sound.mute;
5342 LOGD("current mute = %d", *mute);
5346 return MM_ERROR_NONE;
5350 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5352 mmplayer_t *player = (mmplayer_t *)hplayer;
5356 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5358 player->audio_stream_changed_cb = callback;
5359 player->audio_stream_changed_cb_user_param = user_param;
5360 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5364 return MM_ERROR_NONE;
5368 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5370 mmplayer_t *player = (mmplayer_t *)hplayer;
5374 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5376 player->audio_decoded_cb = callback;
5377 player->audio_decoded_cb_user_param = user_param;
5378 player->audio_extract_opt = opt;
5379 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5383 return MM_ERROR_NONE;
5387 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5389 mmplayer_t *player = (mmplayer_t *)hplayer;
5393 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5395 if (callback && !player->bufmgr)
5396 player->bufmgr = tbm_bufmgr_init(-1);
5398 player->set_mode.video_export = (callback) ? true : false;
5399 player->video_decoded_cb = callback;
5400 player->video_decoded_cb_user_param = user_param;
5402 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5406 return MM_ERROR_NONE;
5410 _mmplayer_start(MMHandleType hplayer)
5412 mmplayer_t *player = (mmplayer_t *)hplayer;
5413 gint ret = MM_ERROR_NONE;
5417 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5419 /* check current state */
5420 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5422 /* start pipeline */
5423 ret = _mmplayer_gst_start(player);
5424 if (ret != MM_ERROR_NONE)
5425 LOGE("failed to start player.");
5427 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5428 LOGD("force playing start even during buffering");
5429 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5437 /* NOTE: post "not supported codec message" to application
5438 * when one codec is not found during AUTOPLUGGING in MSL.
5439 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5440 * And, if any codec is not found, don't send message here.
5441 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5444 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5446 MMMessageParamType msg_param;
5447 memset(&msg_param, 0, sizeof(MMMessageParamType));
5448 gboolean post_msg_direct = FALSE;
5452 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5454 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5455 player->not_supported_codec, player->can_support_codec);
5457 if (player->not_found_demuxer) {
5458 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5459 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5461 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5462 MMPLAYER_FREEIF(msg_param.data);
5464 return MM_ERROR_NONE;
5467 if (player->not_supported_codec) {
5468 if (player->can_support_codec) {
5469 // There is one codec to play
5470 post_msg_direct = TRUE;
5472 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5473 post_msg_direct = TRUE;
5476 if (post_msg_direct) {
5477 MMMessageParamType msg_param;
5478 memset(&msg_param, 0, sizeof(MMMessageParamType));
5480 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5481 LOGW("not found AUDIO codec, posting error code to application.");
5483 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5484 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5485 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5486 LOGW("not found VIDEO codec, posting error code to application.");
5488 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5489 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5492 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5494 MMPLAYER_FREEIF(msg_param.data);
5496 return MM_ERROR_NONE;
5498 // no any supported codec case
5499 LOGW("not found any codec, posting error code to application.");
5501 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5502 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5503 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5505 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5506 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5509 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5511 MMPLAYER_FREEIF(msg_param.data);
5517 return MM_ERROR_NONE;
5520 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5522 GstState element_state = GST_STATE_VOID_PENDING;
5523 GstState element_pending_state = GST_STATE_VOID_PENDING;
5524 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5525 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5527 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5529 MMPLAYER_RECONFIGURE_LOCK(player);
5530 if (!player->gapless.reconfigure) {
5531 MMPLAYER_RECONFIGURE_UNLOCK(player);
5535 LOGI("reconfigure is under process");
5536 MMPLAYER_RECONFIGURE_WAIT(player);
5537 MMPLAYER_RECONFIGURE_UNLOCK(player);
5538 LOGI("reconfigure is completed.");
5540 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5541 &element_state, &element_pending_state, timeout * GST_SECOND);
5542 if (result == GST_STATE_CHANGE_FAILURE)
5543 LOGW("failed to get pipeline state in %d sec", timeout);
5548 /* NOTE : it should be able to call 'stop' anytime*/
5550 _mmplayer_stop(MMHandleType hplayer)
5552 mmplayer_t *player = (mmplayer_t *)hplayer;
5553 int ret = MM_ERROR_NONE;
5557 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5559 /* check current state */
5560 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5562 /* need to wait till the rebuilding pipeline is completed */
5563 __mmplayer_check_pipeline_reconfigure_state(player);
5564 MMPLAYER_RECONFIGURE_LOCK(player);
5565 __mmplayer_reset_gapless_state(player);
5566 MMPLAYER_RECONFIGURE_UNLOCK(player);
5568 /* NOTE : application should not wait for EOS after calling STOP */
5569 _mmplayer_cancel_eos_timer(player);
5572 player->seek_state = MMPLAYER_SEEK_NONE;
5575 ret = _mmplayer_gst_stop(player);
5577 if (ret != MM_ERROR_NONE)
5578 LOGE("failed to stop player.");
5586 _mmplayer_pause(MMHandleType hplayer)
5588 mmplayer_t *player = (mmplayer_t *)hplayer;
5589 gint64 pos_nsec = 0;
5590 gboolean async = FALSE;
5591 gint ret = MM_ERROR_NONE;
5595 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5597 /* check current state */
5598 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5600 /* check pipeline reconfigure state */
5601 __mmplayer_check_pipeline_reconfigure_state(player);
5603 switch (MMPLAYER_CURRENT_STATE(player)) {
5604 case MM_PLAYER_STATE_READY:
5606 /* check prepare async or not.
5607 * In the case of streaming playback, it's recommended to avoid blocking wait.
5609 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5610 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5612 /* Changing back sync of rtspsrc to async */
5613 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5614 LOGD("async prepare working mode for rtsp");
5620 case MM_PLAYER_STATE_PLAYING:
5622 /* NOTE : store current point to overcome some bad operation
5623 *(returning zero when getting current position in paused state) of some
5626 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5627 LOGW("getting current position failed in paused");
5629 player->last_position = pos_nsec;
5631 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5632 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5633 This causes problem is position calculation during normal pause resume scenarios also.
5634 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5635 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5636 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5637 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5643 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5644 LOGD("doing async pause in case of ms buff src");
5648 /* pause pipeline */
5649 ret = _mmplayer_gst_pause(player, async);
5650 if (ret != MM_ERROR_NONE) {
5651 LOGE("failed to pause player. ret : 0x%x", ret);
5652 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5656 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5657 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5658 LOGE("failed to update display_rotation");
5662 return MM_ERROR_NONE;
5665 /* in case of streaming, pause could take long time.*/
5667 _mmplayer_abort_pause(MMHandleType hplayer)
5669 mmplayer_t *player = (mmplayer_t *)hplayer;
5670 int ret = MM_ERROR_NONE;
5674 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5676 player->pipeline->mainbin,
5677 MM_ERROR_PLAYER_NOT_INITIALIZED);
5679 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5680 LOGD("set the videobin state to READY");
5681 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5682 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5686 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5687 LOGD("set the audiobin state to READY");
5688 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5689 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5693 LOGD("set the pipeline state to READY");
5694 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5695 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5697 if (ret != MM_ERROR_NONE) {
5698 LOGE("fail to change state to READY");
5699 return MM_ERROR_PLAYER_INTERNAL;
5702 LOGD("succeeded in changing state to READY");
5707 _mmplayer_resume(MMHandleType hplayer)
5709 mmplayer_t *player = (mmplayer_t *)hplayer;
5710 int ret = MM_ERROR_NONE;
5711 gboolean async = FALSE;
5715 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5717 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5718 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5719 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5723 /* Changing back sync mode rtspsrc to async */
5724 LOGD("async resume for rtsp case");
5728 /* check current state */
5729 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5731 ret = _mmplayer_gst_resume(player, async);
5732 if (ret != MM_ERROR_NONE)
5733 LOGE("failed to resume player.");
5735 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5736 LOGD("force resume even during buffering");
5737 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5746 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5748 mmplayer_t *player = (mmplayer_t *)hplayer;
5749 gint64 pos_nsec = 0;
5750 int ret = MM_ERROR_NONE;
5752 signed long long start = 0, stop = 0;
5753 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5756 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5757 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5759 /* The sound of video is not supported under 0.0 and over 2.0. */
5760 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5761 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5764 _mmplayer_set_mute(hplayer, mute);
5766 if (player->playback_rate == rate)
5767 return MM_ERROR_NONE;
5769 /* If the position is reached at start potion during fast backward, EOS is posted.
5770 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5772 player->playback_rate = rate;
5774 current_state = MMPLAYER_CURRENT_STATE(player);
5776 if (current_state != MM_PLAYER_STATE_PAUSED)
5777 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5779 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5781 if ((current_state == MM_PLAYER_STATE_PAUSED)
5782 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5783 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5784 pos_nsec = player->last_position;
5789 stop = GST_CLOCK_TIME_NONE;
5791 start = GST_CLOCK_TIME_NONE;
5795 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5796 player->playback_rate,
5798 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5799 GST_SEEK_TYPE_SET, start,
5800 GST_SEEK_TYPE_SET, stop)) {
5801 LOGE("failed to set speed playback");
5802 return MM_ERROR_PLAYER_SEEK;
5805 LOGD("succeeded to set speed playback as %0.1f", rate);
5809 return MM_ERROR_NONE;;
5813 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5815 mmplayer_t *player = (mmplayer_t *)hplayer;
5816 int ret = MM_ERROR_NONE;
5820 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5822 /* check pipeline reconfigure state */
5823 __mmplayer_check_pipeline_reconfigure_state(player);
5825 ret = _mmplayer_gst_set_position(player, position, FALSE);
5833 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5835 mmplayer_t *player = (mmplayer_t *)hplayer;
5836 int ret = MM_ERROR_NONE;
5838 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5839 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5841 if (g_strrstr(player->type, "video/mpegts"))
5842 __mmplayer_update_duration_value(player);
5844 *duration = player->duration;
5849 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5851 mmplayer_t *player = (mmplayer_t *)hplayer;
5852 int ret = MM_ERROR_NONE;
5854 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5856 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5862 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5864 mmplayer_t *player = (mmplayer_t *)hplayer;
5865 int ret = MM_ERROR_NONE;
5869 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5871 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5879 __mmplayer_is_midi_type(gchar *str_caps)
5881 if ((g_strrstr(str_caps, "audio/midi")) ||
5882 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5883 (g_strrstr(str_caps, "application/x-smaf")) ||
5884 (g_strrstr(str_caps, "audio/x-imelody")) ||
5885 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5886 (g_strrstr(str_caps, "audio/xmf")) ||
5887 (g_strrstr(str_caps, "audio/mxmf"))) {
5896 __mmplayer_is_only_mp3_type(gchar *str_caps)
5898 if (g_strrstr(str_caps, "application/x-id3") ||
5899 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5905 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5907 GstStructure *caps_structure = NULL;
5908 gint samplerate = 0;
5912 MMPLAYER_RETURN_IF_FAIL(player && caps);
5914 caps_structure = gst_caps_get_structure(caps, 0);
5916 /* set stream information */
5917 gst_structure_get_int(caps_structure, "rate", &samplerate);
5918 gst_structure_get_int(caps_structure, "channels", &channels);
5920 mm_player_set_attribute((MMHandleType)player, NULL,
5921 "content_audio_samplerate", samplerate,
5922 "content_audio_channels", channels, NULL);
5924 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5928 __mmplayer_update_content_type_info(mmplayer_t *player)
5931 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5933 if (__mmplayer_is_midi_type(player->type)) {
5934 player->bypass_audio_effect = TRUE;
5938 if (!player->streamer) {
5939 LOGD("no need to check streaming type");
5943 if (g_strrstr(player->type, "application/x-hls")) {
5944 /* If it can't know exact type when it parses uri because of redirection case,
5945 * it will be fixed by typefinder or when doing autoplugging.
5947 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5948 player->streamer->is_adaptive_streaming = TRUE;
5949 } else if (g_strrstr(player->type, "application/dash+xml")) {
5950 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5951 player->streamer->is_adaptive_streaming = TRUE;
5954 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5955 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5956 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5958 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5959 if (player->streamer->is_adaptive_streaming)
5960 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5962 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5966 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5971 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5972 GstCaps *caps, gpointer data)
5974 mmplayer_t *player = (mmplayer_t *)data;
5978 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5980 /* store type string */
5981 if (player->type_caps) {
5982 gst_caps_unref(player->type_caps);
5983 player->type_caps = NULL;
5986 player->type_caps = gst_caps_copy(caps);
5987 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5989 MMPLAYER_FREEIF(player->type);
5990 player->type = gst_caps_to_string(caps);
5992 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5993 player, player->type, probability, gst_caps_get_size(caps));
5995 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5996 (g_strrstr(player->type, "audio/x-raw-int"))) {
5997 LOGE("not support media format");
5999 if (player->msg_posted == FALSE) {
6000 MMMessageParamType msg_param;
6001 memset(&msg_param, 0, sizeof(MMMessageParamType));
6003 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6004 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6006 /* don't post more if one was sent already */
6007 player->msg_posted = TRUE;
6012 __mmplayer_update_content_type_info(player);
6014 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6017 pad = gst_element_get_static_pad(tf, "src");
6019 LOGE("fail to get typefind src pad.");
6023 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6024 gboolean async = FALSE;
6025 LOGE("failed to autoplug %s", player->type);
6027 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6029 if (async && player->msg_posted == FALSE)
6030 __mmplayer_handle_missed_plugin(player);
6032 gst_object_unref(GST_OBJECT(pad));
6039 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6041 GstElement *decodebin = NULL;
6045 /* create decodebin */
6046 decodebin = gst_element_factory_make("decodebin", NULL);
6049 LOGE("fail to create decodebin");
6053 /* raw pad handling signal */
6054 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6055 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6057 /* no-more-pad pad handling signal */
6058 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6059 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6061 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6062 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6064 /* This signal is emitted when a pad for which there is no further possible
6065 decoding is added to the decodebin.*/
6066 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6067 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6069 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6070 before looking for any elements that can handle that stream.*/
6071 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6072 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6074 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6075 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6076 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6078 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6079 before looking for any elements that can handle that stream.*/
6080 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6081 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6083 /* This signal is emitted once decodebin has finished decoding all the data.*/
6084 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6085 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6087 /* This signal is emitted when a element is added to the bin.*/
6088 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6089 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6096 __mmplayer_gst_make_queue2(mmplayer_t *player)
6098 GstElement *queue2 = NULL;
6099 gint64 dur_bytes = 0L;
6100 mmplayer_gst_element_t *mainbin = NULL;
6101 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6104 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6106 mainbin = player->pipeline->mainbin;
6108 queue2 = gst_element_factory_make("queue2", "queue2");
6110 LOGE("failed to create buffering queue element");
6114 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6115 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6117 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6119 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6120 * skip the pull mode(file or ring buffering) setting. */
6121 if (dur_bytes > 0) {
6122 if (!g_strrstr(player->type, "video/mpegts")) {
6123 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6124 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6130 _mm_player_streaming_set_queue2(player->streamer,
6134 (guint64)dur_bytes); /* no meaning at the moment */
6140 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6142 mmplayer_gst_element_t *mainbin = NULL;
6143 GstElement *decodebin = NULL;
6144 GstElement *queue2 = NULL;
6145 GstPad *sinkpad = NULL;
6146 GstPad *qsrcpad = NULL;
6149 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6151 mainbin = player->pipeline->mainbin;
6153 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6155 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6156 LOGW("need to check: muxed buffer is not null");
6159 queue2 = __mmplayer_gst_make_queue2(player);
6161 LOGE("failed to make queue2");
6165 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6166 LOGE("failed to add buffering queue");
6170 sinkpad = gst_element_get_static_pad(queue2, "sink");
6171 qsrcpad = gst_element_get_static_pad(queue2, "src");
6173 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6174 LOGE("failed to link [%s:%s]-[%s:%s]",
6175 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6179 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6180 LOGE("failed to sync queue2 state with parent");
6184 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6185 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6189 gst_object_unref(GST_OBJECT(sinkpad));
6193 /* create decodebin */
6194 decodebin = _mmplayer_gst_make_decodebin(player);
6196 LOGE("failed to make decodebin");
6200 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6201 LOGE("failed to add decodebin");
6205 /* to force caps on the decodebin element and avoid reparsing stuff by
6206 * typefind. It also avoids a deadlock in the way typefind activates pads in
6207 * the state change */
6208 g_object_set(decodebin, "sink-caps", caps, NULL);
6210 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6212 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6213 LOGE("failed to link [%s:%s]-[%s:%s]",
6214 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6218 gst_object_unref(GST_OBJECT(sinkpad));
6220 gst_object_unref(GST_OBJECT(qsrcpad));
6223 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6224 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6226 /* set decodebin property about buffer in streaming playback. *
6227 * in case of HLS/DASH, it does not need to have big buffer *
6228 * because it is kind of adaptive streaming. */
6229 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6230 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6231 gint high_percent = 0;
6233 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6234 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6236 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6238 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6240 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6241 "high-percent", high_percent,
6242 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6243 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6244 "max-size-buffers", 0, NULL); // disable or automatic
6247 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6248 LOGE("failed to sync decodebin state with parent");
6259 gst_object_unref(GST_OBJECT(sinkpad));
6262 gst_object_unref(GST_OBJECT(qsrcpad));
6265 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6266 * You need to explicitly set elements to the NULL state before
6267 * dropping the final reference, to allow them to clean up.
6269 gst_element_set_state(queue2, GST_STATE_NULL);
6271 /* And, it still has a parent "player".
6272 * You need to let the parent manage the object instead of unreffing the object directly.
6274 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6275 gst_object_unref(queue2);
6280 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6281 * You need to explicitly set elements to the NULL state before
6282 * dropping the final reference, to allow them to clean up.
6284 gst_element_set_state(decodebin, GST_STATE_NULL);
6286 /* And, it still has a parent "player".
6287 * You need to let the parent manage the object instead of unreffing the object directly.
6290 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6291 gst_object_unref(decodebin);
6299 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6303 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6304 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6306 LOGD("class : %s, mime : %s", factory_class, mime);
6308 /* add missing plugin */
6309 /* NOTE : msl should check missing plugin for image mime type.
6310 * Some motion jpeg clips can have playable audio track.
6311 * So, msl have to play audio after displaying popup written video format not supported.
6313 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6314 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6315 LOGD("not found demuxer");
6316 player->not_found_demuxer = TRUE;
6317 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6323 if (!g_strrstr(factory_class, "Demuxer")) {
6324 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6325 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6326 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6328 /* check that clip have multi tracks or not */
6329 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6330 LOGD("video plugin is already linked");
6332 LOGW("add VIDEO to missing plugin");
6333 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6334 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6336 } else if (g_str_has_prefix(mime, "audio")) {
6337 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6338 LOGD("audio plugin is already linked");
6340 LOGW("add AUDIO to missing plugin");
6341 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6342 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6350 return MM_ERROR_NONE;
6354 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6356 mmplayer_t *player = (mmplayer_t *)data;
6360 MMPLAYER_RETURN_IF_FAIL(player);
6362 /* remove fakesink. */
6363 if (!_mmplayer_gst_remove_fakesink(player,
6364 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6365 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6366 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6367 * source element are not same. To overcome this situation, this function will called
6368 * several places and several times. Therefore, this is not an error case.
6373 LOGD("[handle: %p] pipeline has completely constructed", player);
6375 if ((player->msg_posted == FALSE) &&
6376 (player->cmd >= MMPLAYER_COMMAND_START))
6377 __mmplayer_handle_missed_plugin(player);
6379 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6383 __mmplayer_check_profile(void)
6386 static int profile_tv = -1;
6388 if (__builtin_expect(profile_tv != -1, 1))
6391 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6392 switch (*profileName) {
6407 __mmplayer_get_next_uri(mmplayer_t *player)
6409 mmplayer_parse_profile_t profile;
6411 guint num_of_list = 0;
6414 num_of_list = g_list_length(player->uri_info.uri_list);
6415 uri_idx = player->uri_info.uri_idx;
6417 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6418 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6419 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6421 LOGW("next uri does not exist");
6425 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6426 LOGE("failed to parse profile");
6430 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6431 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6432 LOGW("uri type is not supported(%d)", profile.uri_type);
6436 LOGD("success to find next uri %d", uri_idx);
6440 if (!uri || uri_idx == num_of_list) {
6441 LOGE("failed to find next uri");
6445 player->uri_info.uri_idx = uri_idx;
6446 if (mm_player_set_attribute((MMHandleType)player, NULL,
6447 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6448 LOGE("failed to set attribute");
6452 SECURE_LOGD("next playback uri: %s", uri);
6457 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6459 #define REPEAT_COUNT_INFINITE -1
6460 #define REPEAT_COUNT_MIN 2
6461 #define ORIGINAL_URI_ONLY 1
6463 MMHandleType attrs = 0;
6467 guint num_of_uri = 0;
6468 int profile_tv = -1;
6472 LOGD("checking for gapless play option");
6474 if (player->build_audio_offload) {
6475 LOGE("offload path is not supportable.");
6479 if (player->pipeline->textbin) {
6480 LOGE("subtitle path is enabled. gapless play is not supported.");
6484 attrs = MMPLAYER_GET_ATTRS(player);
6486 LOGE("fail to get attributes.");
6490 mm_attrs_multiple_get(player->attrs, NULL,
6491 "content_video_found", &video,
6492 "profile_play_count", &count,
6493 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6495 /* gapless playback is not supported in case of video at TV profile. */
6496 profile_tv = __mmplayer_check_profile();
6497 if (profile_tv && video) {
6498 LOGW("not support video gapless playback");
6502 /* check repeat count in case of audio */
6504 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6505 LOGW("gapless is disabled");
6509 num_of_uri = g_list_length(player->uri_info.uri_list);
6511 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6513 if (num_of_uri == ORIGINAL_URI_ONLY) {
6514 /* audio looping path */
6515 if (count >= REPEAT_COUNT_MIN) {
6516 /* decrease play count */
6517 /* we succeeded to rewind. update play count and then wait for next EOS */
6519 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6520 } else if (count != REPEAT_COUNT_INFINITE) {
6521 LOGD("there is no next uri and no repeat");
6524 LOGD("looping cnt %d", count);
6526 /* gapless playback path */
6527 if (!__mmplayer_get_next_uri(player)) {
6528 LOGE("failed to get next uri");
6535 LOGE("unable to play gapless path. EOS will be posted soon");
6540 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6542 GstPad *sinkpad = g_value_get_object (item);
6543 GstElement *element = GST_ELEMENT(user_data);
6544 if (!sinkpad || !element) {
6545 LOGE("invalid parameter");
6549 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6550 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6554 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6556 mmplayer_gst_element_t *sinkbin = NULL;
6557 main_element_id_e concatId = MMPLAYER_M_NUM;
6558 main_element_id_e sinkId = MMPLAYER_M_NUM;
6559 gboolean send_notice = FALSE;
6560 GstElement *element;
6564 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6566 LOGD("type %d", type);
6569 case MM_PLAYER_TRACK_TYPE_AUDIO:
6570 concatId = MMPLAYER_M_A_CONCAT;
6571 sinkId = MMPLAYER_A_BIN;
6572 sinkbin = player->pipeline->audiobin;
6574 case MM_PLAYER_TRACK_TYPE_VIDEO:
6575 concatId = MMPLAYER_M_V_CONCAT;
6576 sinkId = MMPLAYER_V_BIN;
6577 sinkbin = player->pipeline->videobin;
6580 case MM_PLAYER_TRACK_TYPE_TEXT:
6581 concatId = MMPLAYER_M_T_CONCAT;
6582 sinkId = MMPLAYER_T_BIN;
6583 sinkbin = player->pipeline->textbin;
6586 LOGE("requested type is not supportable");
6591 element = player->pipeline->mainbin[concatId].gst;
6595 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6596 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6597 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6598 if (srcpad && sinkpad) {
6599 /* after getting drained signal there is no data flows, so no need to do pad_block */
6600 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6601 gst_pad_unlink(srcpad, sinkpad);
6603 /* send custom event to sink pad to handle it at video sink */
6605 LOGD("send custom event to sinkpad");
6606 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6607 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6608 gst_pad_send_event(sinkpad, event);
6611 gst_object_unref(srcpad);
6612 gst_object_unref(sinkpad);
6615 LOGD("release concat request pad");
6616 /* release and unref requests pad from the selector */
6617 iter = gst_element_iterate_sink_pads(element);
6618 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6619 gst_iterator_resync(iter);
6620 gst_iterator_free(iter);
6626 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6628 mmplayer_track_t *selector = &player->track[type];
6629 mmplayer_gst_element_t *sinkbin = NULL;
6630 main_element_id_e selectorId = MMPLAYER_M_NUM;
6631 main_element_id_e sinkId = MMPLAYER_M_NUM;
6632 GstPad *srcpad = NULL;
6633 GstPad *sinkpad = NULL;
6634 gboolean send_notice = FALSE;
6637 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6639 LOGD("type %d", type);
6642 case MM_PLAYER_TRACK_TYPE_AUDIO:
6643 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6644 sinkId = MMPLAYER_A_BIN;
6645 sinkbin = player->pipeline->audiobin;
6647 case MM_PLAYER_TRACK_TYPE_VIDEO:
6648 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6649 sinkId = MMPLAYER_V_BIN;
6650 sinkbin = player->pipeline->videobin;
6653 case MM_PLAYER_TRACK_TYPE_TEXT:
6654 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6655 sinkId = MMPLAYER_T_BIN;
6656 sinkbin = player->pipeline->textbin;
6659 LOGE("requested type is not supportable");
6664 if (player->pipeline->mainbin[selectorId].gst) {
6667 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6669 if (selector->event_probe_id != 0)
6670 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6671 selector->event_probe_id = 0;
6673 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6674 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6676 if (srcpad && sinkpad) {
6677 /* after getting drained signal there is no data flows, so no need to do pad_block */
6678 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6679 gst_pad_unlink(srcpad, sinkpad);
6681 /* send custom event to sink pad to handle it at video sink */
6683 LOGD("send custom event to sinkpad");
6684 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6685 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6686 gst_pad_send_event(sinkpad, event);
6690 gst_object_unref(sinkpad);
6693 gst_object_unref(srcpad);
6696 LOGD("selector release");
6698 /* release and unref requests pad from the selector */
6699 for (n = 0; n < selector->streams->len; n++) {
6700 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6701 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6704 g_ptr_array_set_size(selector->streams, 0);
6706 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6707 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6709 player->pipeline->mainbin[selectorId].gst = NULL;
6717 __mmplayer_deactivate_old_path(mmplayer_t *player)
6720 MMPLAYER_RETURN_IF_FAIL(player);
6722 if (MMPLAYER_USE_DECODEBIN(player)) {
6723 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6724 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6725 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6726 LOGE("deactivate selector error");
6730 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6731 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6732 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6733 LOGE("deactivate concat error");
6738 _mmplayer_track_destroy(player);
6739 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6741 if (player->streamer) {
6742 _mm_player_streaming_initialize(player->streamer, FALSE);
6743 _mm_player_streaming_destroy(player->streamer);
6744 player->streamer = NULL;
6747 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6753 if (!player->msg_posted) {
6754 MMMessageParamType msg = {0,};
6757 msg.code = MM_ERROR_PLAYER_INTERNAL;
6758 LOGE("gapless_uri_play> deactivate error");
6760 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6761 player->msg_posted = TRUE;
6767 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6769 int result = MM_ERROR_NONE;
6770 mmplayer_t *player = (mmplayer_t *)hplayer;
6773 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6774 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6776 if (mm_player_set_attribute(hplayer, NULL,
6777 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6778 LOGE("failed to set attribute");
6779 result = MM_ERROR_PLAYER_INTERNAL;
6781 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6782 LOGE("failed to add the original uri in the uri list.");
6790 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6792 mmplayer_t *player = (mmplayer_t *)hplayer;
6793 guint num_of_list = 0;
6797 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6798 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6800 if (player->pipeline && player->pipeline->textbin) {
6801 LOGE("subtitle path is enabled.");
6802 return MM_ERROR_PLAYER_INVALID_STATE;
6805 num_of_list = g_list_length(player->uri_info.uri_list);
6807 if (is_first_path) {
6808 if (num_of_list == 0) {
6809 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6810 SECURE_LOGD("add original path : %s", uri);
6812 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6813 player->uri_info.uri_list = g_list_prepend(
6814 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6815 SECURE_LOGD("change original path : %s", uri);
6818 MMHandleType attrs = 0;
6819 attrs = MMPLAYER_GET_ATTRS(player);
6821 if (num_of_list == 0) {
6822 char *original_uri = NULL;
6825 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6827 if (!original_uri) {
6828 LOGE("there is no original uri.");
6829 return MM_ERROR_PLAYER_INVALID_STATE;
6832 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6833 player->uri_info.uri_idx = 0;
6835 SECURE_LOGD("add original path at first : %s", original_uri);
6839 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6840 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6844 return MM_ERROR_NONE;
6848 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6850 mmplayer_t *player = (mmplayer_t *)hplayer;
6851 char *next_uri = NULL;
6852 guint num_of_list = 0;
6855 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6857 num_of_list = g_list_length(player->uri_info.uri_list);
6859 if (num_of_list > 0) {
6860 gint uri_idx = player->uri_info.uri_idx;
6862 if (uri_idx < num_of_list - 1)
6867 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6868 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6870 *uri = g_strdup(next_uri);
6874 return MM_ERROR_NONE;
6878 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6879 GstCaps *caps, gpointer data)
6881 mmplayer_t *player = (mmplayer_t *)data;
6882 const gchar *klass = NULL;
6883 const gchar *mime = NULL;
6884 gchar *caps_str = NULL;
6886 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6887 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6888 caps_str = gst_caps_to_string(caps);
6890 LOGW("unknown type of caps : %s from %s",
6891 caps_str, GST_ELEMENT_NAME(elem));
6893 MMPLAYER_FREEIF(caps_str);
6895 /* There is no available codec. */
6896 __mmplayer_check_not_supported_codec(player, klass, mime);
6900 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6901 GstCaps *caps, gpointer data)
6903 mmplayer_t *player = (mmplayer_t *)data;
6904 const char *mime = NULL;
6905 gboolean ret = TRUE;
6907 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6908 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6910 if (g_str_has_prefix(mime, "audio")) {
6911 GstStructure *caps_structure = NULL;
6912 gint samplerate = 0;
6914 gchar *caps_str = NULL;
6916 caps_structure = gst_caps_get_structure(caps, 0);
6917 gst_structure_get_int(caps_structure, "rate", &samplerate);
6918 gst_structure_get_int(caps_structure, "channels", &channels);
6920 if ((channels > 0 && samplerate == 0)) {
6921 LOGD("exclude audio...");
6925 caps_str = gst_caps_to_string(caps);
6926 /* set it directly because not sent by TAG */
6927 if (g_strrstr(caps_str, "mobile-xmf"))
6928 mm_player_set_attribute((MMHandleType)player, NULL,
6929 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6931 MMPLAYER_FREEIF(caps_str);
6932 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6933 LOGD("already video linked");
6936 LOGD("found new stream");
6943 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6945 gboolean ret = FALSE;
6946 GDBusConnection *conn = NULL;
6948 GVariant *result = NULL;
6949 const gchar *dbus_device_type = NULL;
6950 const gchar *dbus_ret = NULL;
6953 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6955 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6960 result = g_dbus_connection_call_sync(conn,
6961 "org.pulseaudio.Server",
6962 "/org/pulseaudio/StreamManager",
6963 "org.pulseaudio.StreamManager",
6964 "GetCurrentMediaRoutingPath",
6965 g_variant_new("(s)", "out"),
6966 G_VARIANT_TYPE("(ss)"),
6967 G_DBUS_CALL_FLAGS_NONE,
6971 if (!result || err) {
6972 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6977 /* device type is listed in stream-map.json at mmfw-sysconf */
6978 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6980 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6981 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6984 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6985 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6986 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6987 LOGD("audio offload is supportable");
6993 LOGD("audio offload is not supportable");
6996 g_variant_unref(result);
6998 g_object_unref(conn);
7003 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7005 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7006 gint64 position = 0;
7008 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7009 player->pipeline && player->pipeline->mainbin);
7011 MMPLAYER_CMD_LOCK(player);
7012 current_state = MMPLAYER_CURRENT_STATE(player);
7014 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7015 LOGW("getting current position failed in paused");
7017 _mmplayer_unrealize((MMHandleType)player);
7018 _mmplayer_realize((MMHandleType)player);
7020 _mmplayer_set_position((MMHandleType)player, position);
7022 /* async not to be blocked in streaming case */
7023 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7025 _mmplayer_pause((MMHandleType)player);
7027 if (current_state == MM_PLAYER_STATE_PLAYING)
7028 _mmplayer_start((MMHandleType)player);
7029 MMPLAYER_CMD_UNLOCK(player);
7031 LOGD("rebuilding audio pipeline is completed.");
7034 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7036 mmplayer_t *player = (mmplayer_t *)user_data;
7037 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7038 gboolean is_supportable = FALSE;
7040 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7041 LOGW("failed to get device type");
7043 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7045 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7046 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7047 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7048 LOGD("ignore this dev connected info");
7052 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7053 if (player->build_audio_offload == is_supportable) {
7054 LOGD("keep current pipeline without re-building");
7058 /* rebuild pipeline */
7059 LOGD("re-build pipeline - offload: %d", is_supportable);
7060 player->build_audio_offload = FALSE;
7061 __mmplayer_rebuild_audio_pipeline(player);
7067 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7069 unsigned int id = 0;
7071 if (player->audio_device_cb_id != 0) {
7072 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7076 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7077 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7078 LOGD("added device connected cb (%u)", id);
7079 player->audio_device_cb_id = id;
7081 LOGW("failed to add device connected cb");
7088 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7090 mmplayer_t *player = (mmplayer_t *)hplayer;
7093 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7094 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7096 *activated = player->build_audio_offload;
7098 LOGD("offload activated : %d", (int)*activated);
7101 return MM_ERROR_NONE;
7105 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7108 this function need to be updated according to the supported media format
7109 @see player->ini.audio_offload_media_format */
7111 if (__mmplayer_is_only_mp3_type(player->type)) {
7112 LOGD("offload supportable media format type");
7120 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7122 gboolean ret = FALSE;
7123 GstElementFactory *factory = NULL;
7126 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7128 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7129 if (!__mmplayer_is_offload_supported_type(player))
7132 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7133 LOGD("there is no audio offload sink");
7137 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7138 LOGW("there is no audio device type to support offload");
7142 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7144 LOGW("there is no installed audio offload sink element");
7147 gst_object_unref(factory);
7149 if (_mmplayer_acquire_hw_resource(player,
7150 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7151 LOGE("failed to acquire audio offload decoder resource");
7155 if (!__mmplayer_add_audio_device_connected_cb(player))
7158 if (!__mmplayer_is_audio_offload_device_type(player))
7161 LOGD("audio offload can be built");
7166 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7172 static GstAutoplugSelectResult
7173 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7175 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7176 int audio_offload = 0;
7178 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7179 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7181 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7182 LOGD("expose audio path to build offload output path");
7183 player->build_audio_offload = TRUE;
7184 /* update codec info */
7185 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7186 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7187 player->audiodec_linked = 1;
7189 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7193 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7194 And need to consider the multi-track audio content.
7195 There is no HW audio decoder in public. */
7197 /* set stream information */
7198 if (!player->audiodec_linked)
7199 _mmplayer_set_audio_attrs(player, caps);
7201 /* update codec info */
7202 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7203 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7204 player->audiodec_linked = 1;
7206 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7208 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7209 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7211 /* mark video decoder for acquire */
7212 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7213 LOGW("video decoder resource is already acquired, skip it.");
7214 ret = GST_AUTOPLUG_SELECT_SKIP;
7218 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7219 LOGE("failed to acquire video decoder resource");
7220 ret = GST_AUTOPLUG_SELECT_SKIP;
7223 player->interrupted_by_resource = FALSE;
7226 /* update codec info */
7227 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7228 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7229 player->videodec_linked = 1;
7237 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7238 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7240 #define DEFAULT_IDX 0xFFFF
7241 #define MIN_FACTORY_NUM 2
7242 mmplayer_t *player = (mmplayer_t *)data;
7243 GValueArray *new_factories = NULL;
7244 GValue val = { 0, };
7245 GstElementFactory *factory = NULL;
7246 const gchar *klass = NULL;
7247 gchar *factory_name = NULL;
7248 guint hw_dec_idx = DEFAULT_IDX;
7249 guint first_sw_dec_idx = DEFAULT_IDX;
7250 guint last_sw_dec_idx = DEFAULT_IDX;
7251 guint new_pos = DEFAULT_IDX;
7252 guint rm_pos = DEFAULT_IDX;
7253 int audio_codec_type;
7254 int video_codec_type;
7255 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7257 if (factories->n_values < MIN_FACTORY_NUM)
7260 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7261 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7264 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7266 for (int i = 0 ; i < factories->n_values ; i++) {
7267 gchar *hw_dec_info = NULL;
7268 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7270 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7272 LOGW("failed to get factory object");
7275 klass = gst_element_factory_get_klass(factory);
7276 factory_name = GST_OBJECT_NAME(factory);
7279 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7281 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7282 if (!player->need_audio_dec_sorting) {
7283 LOGD("sorting is not required");
7286 codec_type = audio_codec_type;
7287 hw_dec_info = player->ini.audiocodec_element_hw;
7288 sw_dec_info = player->ini.audiocodec_element_sw;
7289 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7290 if (!player->need_video_dec_sorting) {
7291 LOGD("sorting is not required");
7294 codec_type = video_codec_type;
7295 hw_dec_info = player->ini.videocodec_element_hw;
7296 sw_dec_info = player->ini.videocodec_element_sw;
7301 if (g_strrstr(factory_name, hw_dec_info)) {
7304 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7305 if (strstr(factory_name, sw_dec_info[j])) {
7306 last_sw_dec_idx = i;
7307 if (first_sw_dec_idx == DEFAULT_IDX) {
7308 first_sw_dec_idx = i;
7313 if (first_sw_dec_idx == DEFAULT_IDX)
7314 LOGW("unknown codec %s", factory_name);
7318 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7321 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7322 if (hw_dec_idx < first_sw_dec_idx)
7324 new_pos = first_sw_dec_idx;
7325 rm_pos = hw_dec_idx + 1;
7326 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7327 if (last_sw_dec_idx < hw_dec_idx)
7329 new_pos = last_sw_dec_idx + 1;
7330 rm_pos = hw_dec_idx;
7335 /* change position - insert H/W decoder according to the new position */
7336 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7338 LOGW("failed to get factory object");
7341 new_factories = g_value_array_copy(factories);
7342 g_value_init (&val, G_TYPE_OBJECT);
7343 g_value_set_object (&val, factory);
7344 g_value_array_insert(new_factories, new_pos, &val);
7345 g_value_unset (&val);
7346 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7348 for (int i = 0 ; i < new_factories->n_values ; i++) {
7349 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7351 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7352 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7354 LOGE("[Re-arranged] failed to get factory object");
7357 return new_factories;
7361 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7362 GstCaps *caps, GstElementFactory *factory, gpointer data)
7364 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7365 mmplayer_t *player = (mmplayer_t *)data;
7367 gchar *factory_name = NULL;
7368 gchar *caps_str = NULL;
7369 const gchar *klass = NULL;
7372 factory_name = GST_OBJECT_NAME(factory);
7373 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7374 caps_str = gst_caps_to_string(caps);
7376 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7378 /* store type string */
7379 if (player->type == NULL) {
7380 player->type = gst_caps_to_string(caps);
7381 __mmplayer_update_content_type_info(player);
7384 /* filtering exclude keyword */
7385 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7386 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7387 LOGW("skipping [%s] by exclude keyword [%s]",
7388 factory_name, player->ini.exclude_element_keyword[idx]);
7390 result = GST_AUTOPLUG_SELECT_SKIP;
7395 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7396 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7397 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7398 factory_name, player->ini.unsupported_codec_keyword[idx]);
7399 result = GST_AUTOPLUG_SELECT_SKIP;
7404 /* exclude webm format */
7405 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7406 * because webm format is not supportable.
7407 * If webm is disabled in "autoplug-continue", there is no state change
7408 * failure or error because the decodebin will expose the pad directly.
7409 * It make MSL invoke _prepare_async_callback.
7410 * So, we need to disable webm format in "autoplug-select" */
7411 if (caps_str && strstr(caps_str, "webm")) {
7412 LOGW("webm is not supported");
7413 result = GST_AUTOPLUG_SELECT_SKIP;
7417 /* check factory class for filtering */
7418 /* NOTE : msl don't need to use image plugins.
7419 * So, those plugins should be skipped for error handling.
7421 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7422 LOGD("skipping [%s] by not required", factory_name);
7423 result = GST_AUTOPLUG_SELECT_SKIP;
7427 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7428 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7429 // TO CHECK : subtitle if needed, add subparse exception.
7430 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7431 result = GST_AUTOPLUG_SELECT_SKIP;
7435 if (g_strrstr(factory_name, "mpegpsdemux")) {
7436 LOGD("skipping PS container - not support");
7437 result = GST_AUTOPLUG_SELECT_SKIP;
7441 if (g_strrstr(factory_name, "mssdemux"))
7442 player->smooth_streaming = TRUE;
7444 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7445 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7448 GstStructure *str = NULL;
7449 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7451 /* don't make video because of not required */
7452 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7453 (!player->set_mode.video_export)) {
7454 LOGD("no need video decoding, expose pad");
7455 result = GST_AUTOPLUG_SELECT_EXPOSE;
7459 /* get w/h for omx state-tune */
7460 /* FIXME: deprecated? */
7461 str = gst_caps_get_structure(caps, 0);
7462 gst_structure_get_int(str, "width", &width);
7465 if (player->v_stream_caps) {
7466 gst_caps_unref(player->v_stream_caps);
7467 player->v_stream_caps = NULL;
7470 player->v_stream_caps = gst_caps_copy(caps);
7471 LOGD("take caps for video state tune");
7472 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7476 if (g_strrstr(klass, "Codec/Decoder")) {
7477 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7478 if (result != GST_AUTOPLUG_SELECT_TRY) {
7479 LOGW("skip add decoder");
7485 MMPLAYER_FREEIF(caps_str);
7491 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7494 int ret = MM_ERROR_NONE;
7495 mmplayer_t *player = (mmplayer_t *)data;
7496 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7497 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7498 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7501 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7503 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7505 if (MMPLAYER_USE_DECODEBIN(player))
7508 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7511 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst, GST_STATE_NULL, FALSE, timeout);
7512 if (ret != MM_ERROR_NONE) {
7513 LOGE("fail to change state to NULL");
7517 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL, FALSE, timeout);
7518 if (ret != MM_ERROR_NONE) {
7519 LOGE("fail to change state to NULL");
7523 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7524 LOGE("failed to remove video concat");
7527 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7528 LOGE("failed to remove videobin");
7531 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7532 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7533 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7535 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7536 MMPLAYER_FREEIF(player->pipeline->videobin);
7538 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7539 if (ret != MM_ERROR_NONE)
7540 LOGE("failed to release overlay resources");
7542 player->videodec_linked = 0;
7544 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7549 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7551 mmplayer_t *player = (mmplayer_t *)data;
7554 MMPLAYER_RETURN_IF_FAIL(player);
7556 LOGD("got about to finish signal");
7558 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7559 LOGW("Fail to get cmd lock");
7563 if (!__mmplayer_verify_gapless_play_path(player)) {
7564 LOGD("decoding is finished.");
7565 MMPLAYER_CMD_UNLOCK(player);
7569 _mmplayer_set_reconfigure_state(player, TRUE);
7570 MMPLAYER_CMD_UNLOCK(player);
7572 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7573 __mmplayer_deactivate_old_path(player);
7579 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7581 mmplayer_t *player = (mmplayer_t *)data;
7582 GstIterator *iter = NULL;
7583 GValue item = { 0, };
7585 gboolean done = FALSE;
7586 gboolean is_all_drained = TRUE;
7589 MMPLAYER_RETURN_IF_FAIL(player);
7591 LOGD("got drained signal");
7593 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7594 LOGW("Fail to get cmd lock");
7598 if (!__mmplayer_verify_gapless_play_path(player)) {
7599 LOGD("decoding is finished.");
7600 MMPLAYER_CMD_UNLOCK(player);
7604 _mmplayer_set_reconfigure_state(player, TRUE);
7605 MMPLAYER_CMD_UNLOCK(player);
7607 /* check decodebin src pads whether they received EOS or not */
7608 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7611 switch (gst_iterator_next(iter, &item)) {
7612 case GST_ITERATOR_OK:
7613 pad = g_value_get_object(&item);
7614 if (pad && !GST_PAD_IS_EOS(pad)) {
7615 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7616 is_all_drained = FALSE;
7619 g_value_reset(&item);
7621 case GST_ITERATOR_RESYNC:
7622 gst_iterator_resync(iter);
7624 case GST_ITERATOR_ERROR:
7625 case GST_ITERATOR_DONE:
7630 g_value_unset(&item);
7631 gst_iterator_free(iter);
7633 if (!is_all_drained) {
7634 LOGD("Wait util the all pads get EOS.");
7639 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7640 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7642 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7643 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7644 __mmplayer_deactivate_old_path(player);
7650 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7652 mmplayer_t *player = (mmplayer_t *)data;
7653 const gchar *klass = NULL;
7654 gchar *factory_name = NULL;
7656 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7657 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7659 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7661 if (__mmplayer_add_dump_buffer_probe(player, element))
7662 LOGD("add buffer probe");
7664 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7665 gchar *selected = NULL;
7666 selected = g_strdup(GST_ELEMENT_NAME(element));
7667 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7669 /* update codec info */
7670 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7671 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7672 player->audiodec_linked = 1;
7673 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7674 /* update codec info */
7675 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7676 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7677 player->videodec_linked = 1;
7680 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7681 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7682 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7684 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7685 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7687 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7688 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7689 "max-video-width", player->adaptive_info.limit.width,
7690 "max-video-height", player->adaptive_info.limit.height, NULL);
7692 } else if (g_strrstr(klass, "Demuxer")) {
7694 LOGD("plugged element is demuxer. take it");
7696 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7697 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7698 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7699 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7700 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7703 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7704 int surface_type = 0;
7706 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7709 // to support trust-zone only
7710 if (g_strrstr(factory_name, "asfdemux")) {
7711 LOGD("set file-location %s", player->profile.uri);
7712 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7713 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7714 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7715 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7716 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7717 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7718 (__mmplayer_is_only_mp3_type(player->type))) {
7719 LOGD("[mpegaudioparse] set streaming pull mode.");
7720 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7722 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7723 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7724 } else if (g_strrstr(factory_name, "omxdec_h264")) {
7725 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7726 if (video_parse && (g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7727 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7728 LOGD("Send SPS and PPS Insertion every IDR frame");
7732 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7733 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7734 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7736 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7737 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7739 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7740 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7741 (MMPLAYER_IS_DASH_STREAMING(player))) {
7742 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7743 _mm_player_streaming_set_multiqueue(player->streamer, element);
7744 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7753 __mmplayer_release_misc(mmplayer_t *player)
7756 bool cur_mode = player->set_mode.rich_audio;
7759 MMPLAYER_RETURN_IF_FAIL(player);
7761 player->sent_bos = FALSE;
7762 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7764 player->seek_state = MMPLAYER_SEEK_NONE;
7766 player->total_bitrate = 0;
7767 player->total_maximum_bitrate = 0;
7769 player->not_found_demuxer = 0;
7771 player->last_position = 0;
7772 player->duration = 0;
7773 player->http_content_size = 0;
7774 player->not_supported_codec = MISSING_PLUGIN_NONE;
7775 player->can_support_codec = FOUND_PLUGIN_NONE;
7776 player->pending_seek.is_pending = false;
7777 player->pending_seek.pos = 0;
7778 player->msg_posted = FALSE;
7779 player->has_many_types = FALSE;
7780 player->is_subtitle_force_drop = FALSE;
7781 player->play_subtitle = FALSE;
7782 player->adjust_subtitle_pos = 0;
7783 player->has_closed_caption = FALSE;
7784 player->set_mode.video_export = false;
7785 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7786 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7788 player->set_mode.rich_audio = cur_mode;
7790 if (player->audio_device_cb_id > 0 &&
7791 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7792 LOGW("failed to remove audio device_connected_callback");
7793 player->audio_device_cb_id = 0;
7795 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7796 player->bitrate[i] = 0;
7797 player->maximum_bitrate[i] = 0;
7800 /* free memory related to audio effect */
7801 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7803 if (player->adaptive_info.var_list) {
7804 g_list_free_full(player->adaptive_info.var_list, g_free);
7805 player->adaptive_info.var_list = NULL;
7808 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7809 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7810 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7812 /* Reset video360 settings to their defaults in case if the pipeline is to be
7815 player->video360_metadata.is_spherical = -1;
7816 player->is_openal_plugin_used = FALSE;
7818 player->is_content_spherical = FALSE;
7819 player->is_video360_enabled = TRUE;
7820 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7821 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7822 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7823 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7824 player->video360_zoom = 1.0f;
7825 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7826 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7828 player->sound.rg_enable = false;
7830 __mmplayer_initialize_video_roi(player);
7835 __mmplayer_release_misc_post(mmplayer_t *player)
7837 gchar *original_uri = NULL;
7840 /* player->pipeline is already released before. */
7841 MMPLAYER_RETURN_IF_FAIL(player);
7843 player->video_decoded_cb = NULL;
7844 player->video_decoded_cb_user_param = NULL;
7845 player->video_stream_prerolled = false;
7847 player->audio_decoded_cb = NULL;
7848 player->audio_decoded_cb_user_param = NULL;
7849 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7851 player->audio_stream_changed_cb = NULL;
7852 player->audio_stream_changed_cb_user_param = NULL;
7854 mm_player_set_attribute((MMHandleType)player, NULL,
7855 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7857 /* clean found audio decoders */
7858 if (player->audio_decoders) {
7859 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7860 player->audio_decoders = NULL;
7863 /* clean the uri list except original uri */
7864 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7866 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7867 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7868 g_list_free_full(tmp, (GDestroyNotify)g_free);
7871 LOGW("failed to get original uri info");
7873 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7874 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7875 MMPLAYER_FREEIF(original_uri);
7878 /* clear the audio stream buffer list */
7879 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7881 /* clear the video stream bo list */
7882 __mmplayer_video_stream_destroy_bo_list(player);
7883 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7885 if (player->profile.input_mem.buf) {
7886 free(player->profile.input_mem.buf);
7887 player->profile.input_mem.buf = NULL;
7889 player->profile.input_mem.len = 0;
7890 player->profile.input_mem.offset = 0;
7892 player->uri_info.uri_idx = 0;
7897 __mmplayer_check_subtitle(mmplayer_t *player)
7899 MMHandleType attrs = 0;
7900 char *subtitle_uri = NULL;
7904 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7906 /* get subtitle attribute */
7907 attrs = MMPLAYER_GET_ATTRS(player);
7911 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7912 if (!subtitle_uri || !strlen(subtitle_uri))
7915 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7916 player->is_external_subtitle_present = TRUE;
7924 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7926 MMPLAYER_RETURN_IF_FAIL(player);
7928 if (player->eos_timer) {
7929 LOGD("cancel eos timer");
7930 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7931 player->eos_timer = 0;
7938 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7942 MMPLAYER_RETURN_IF_FAIL(player);
7943 MMPLAYER_RETURN_IF_FAIL(sink);
7946 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7948 player->sink_elements = g_list_append(player->sink_elements, sink);
7954 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7958 MMPLAYER_RETURN_IF_FAIL(player);
7959 MMPLAYER_RETURN_IF_FAIL(sink);
7961 player->sink_elements = g_list_remove(player->sink_elements, sink);
7967 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7968 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7970 mmplayer_signal_item_t *item = NULL;
7973 MMPLAYER_RETURN_IF_FAIL(player);
7975 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7976 LOGE("invalid signal type [%d]", type);
7980 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7982 LOGE("cannot connect signal [%s]", signal);
7987 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7988 player->signals[type] = g_list_append(player->signals[type], item);
7994 /* NOTE : be careful with calling this api. please refer to below glib comment
7995 * glib comment : Note that there is a bug in GObject that makes this function much
7996 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7997 * will no longer be called, but, the signal handler is not currently disconnected.
7998 * If the instance is itself being freed at the same time than this doesn't matter,
7999 * since the signal will automatically be removed, but if instance persists,
8000 * then the signal handler will leak. You should not remove the signal yourself
8001 * because in a future versions of GObject, the handler will automatically be
8004 * It's possible to work around this problem in a way that will continue to work
8005 * with future versions of GObject by checking that the signal handler is still
8006 * connected before disconnected it:
8008 * if (g_signal_handler_is_connected(instance, id))
8009 * g_signal_handler_disconnect(instance, id);
8012 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8014 GList *sig_list = NULL;
8015 mmplayer_signal_item_t *item = NULL;
8019 MMPLAYER_RETURN_IF_FAIL(player);
8021 LOGD("release signals type : %d", type);
8023 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8024 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8025 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8026 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8027 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8028 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8032 sig_list = player->signals[type];
8034 for (; sig_list; sig_list = sig_list->next) {
8035 item = sig_list->data;
8037 if (item && item->obj) {
8038 if (g_signal_handler_is_connected(item->obj, item->sig))
8039 g_signal_handler_disconnect(item->obj, item->sig);
8042 MMPLAYER_FREEIF(item);
8045 g_list_free(player->signals[type]);
8046 player->signals[type] = NULL;
8054 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8056 mmplayer_t *player = 0;
8057 int prev_display_surface_type = 0;
8061 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8063 player = MM_PLAYER_CAST(handle);
8065 /* check video sinkbin is created */
8066 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8067 LOGW("Videosink is already created");
8068 return MM_ERROR_NONE;
8071 LOGD("videosink element is not yet ready");
8073 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8074 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8076 return MM_ERROR_INVALID_ARGUMENT;
8079 /* load previous attributes */
8080 if (player->attrs) {
8081 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8082 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8083 if (prev_display_surface_type == surface_type) {
8084 LOGD("incoming display surface type is same as previous one, do nothing..");
8086 return MM_ERROR_NONE;
8089 LOGE("failed to load attributes");
8091 return MM_ERROR_PLAYER_INTERNAL;
8094 /* videobin is not created yet, so we just set attributes related to display surface */
8095 LOGD("store display attribute for given surface type(%d)", surface_type);
8096 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8097 "display_overlay", wl_surface_id, NULL);
8100 return MM_ERROR_NONE;
8103 /* Note : if silent is true, then subtitle would not be displayed. :*/
8105 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8107 mmplayer_t *player = (mmplayer_t *)hplayer;
8111 /* check player handle */
8112 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8114 player->set_mode.subtitle_off = silent;
8116 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8120 return MM_ERROR_NONE;
8124 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8126 mmplayer_gst_element_t *mainbin = NULL;
8127 mmplayer_gst_element_t *textbin = NULL;
8128 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8129 GstState current_state = GST_STATE_VOID_PENDING;
8130 GstState element_state = GST_STATE_VOID_PENDING;
8131 GstState element_pending_state = GST_STATE_VOID_PENDING;
8133 GstEvent *event = NULL;
8134 int result = MM_ERROR_NONE;
8136 GstClock *curr_clock = NULL;
8137 GstClockTime base_time, start_time, curr_time;
8142 /* check player handle */
8143 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8145 player->pipeline->mainbin &&
8146 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8148 mainbin = player->pipeline->mainbin;
8149 textbin = player->pipeline->textbin;
8151 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8153 // sync clock with current pipeline
8154 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8155 curr_time = gst_clock_get_time(curr_clock);
8157 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8158 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8160 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8161 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8163 if (current_state > GST_STATE_READY) {
8164 // sync state with current pipeline
8165 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8166 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8167 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8169 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8170 if (GST_STATE_CHANGE_FAILURE == ret) {
8171 LOGE("fail to state change.");
8172 result = MM_ERROR_PLAYER_INTERNAL;
8176 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8177 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8180 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8181 gst_object_unref(curr_clock);
8184 // seek to current position
8185 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8186 result = MM_ERROR_PLAYER_INVALID_STATE;
8187 LOGE("gst_element_query_position failed, invalid state");
8191 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8192 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);
8194 _mmplayer_gst_send_event_to_sink(player, event);
8196 result = MM_ERROR_PLAYER_INTERNAL;
8197 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8201 /* sync state with current pipeline */
8202 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8203 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8204 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8206 return MM_ERROR_NONE;
8209 /* release text pipeline resource */
8210 player->textsink_linked = 0;
8212 /* release signal */
8213 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8215 /* release textbin with it's children */
8216 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8217 MMPLAYER_FREEIF(player->pipeline->textbin);
8218 player->pipeline->textbin = NULL;
8220 /* release subtitle elem */
8221 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8222 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8228 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8230 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8231 GstState current_state = GST_STATE_VOID_PENDING;
8233 MMHandleType attrs = 0;
8234 mmplayer_gst_element_t *mainbin = NULL;
8235 mmplayer_gst_element_t *textbin = NULL;
8237 gchar *subtitle_uri = NULL;
8238 int result = MM_ERROR_NONE;
8239 const gchar *charset = NULL;
8243 /* check player handle */
8244 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8246 player->pipeline->mainbin &&
8247 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8248 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8250 mainbin = player->pipeline->mainbin;
8251 textbin = player->pipeline->textbin;
8253 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8254 if (current_state < GST_STATE_READY) {
8255 result = MM_ERROR_PLAYER_INVALID_STATE;
8256 LOGE("Pipeline is not in proper state");
8260 attrs = MMPLAYER_GET_ATTRS(player);
8262 LOGE("cannot get content attribute");
8263 result = MM_ERROR_PLAYER_INTERNAL;
8267 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8268 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8269 LOGE("subtitle uri is not proper filepath");
8270 result = MM_ERROR_PLAYER_INVALID_URI;
8274 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8275 LOGE("failed to get storage info of subtitle path");
8276 result = MM_ERROR_PLAYER_INVALID_URI;
8280 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8281 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8283 if (!strcmp(filepath, subtitle_uri)) {
8284 LOGD("subtitle path is not changed");
8287 if (mm_player_set_attribute((MMHandleType)player, NULL,
8288 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8289 LOGE("failed to set attribute");
8294 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8295 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8296 player->subtitle_language_list = NULL;
8297 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8299 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8300 if (ret != GST_STATE_CHANGE_SUCCESS) {
8301 LOGE("failed to change state of textbin to READY");
8302 result = MM_ERROR_PLAYER_INTERNAL;
8306 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8307 if (ret != GST_STATE_CHANGE_SUCCESS) {
8308 LOGE("failed to change state of subparse to READY");
8309 result = MM_ERROR_PLAYER_INTERNAL;
8313 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8314 if (ret != GST_STATE_CHANGE_SUCCESS) {
8315 LOGE("failed to change state of filesrc to READY");
8316 result = MM_ERROR_PLAYER_INTERNAL;
8320 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8322 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8324 charset = _mmplayer_get_charset(filepath);
8326 LOGD("detected charset is %s", charset);
8327 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8330 result = _mmplayer_sync_subtitle_pipeline(player);
8337 /* API to switch between external subtitles */
8339 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8341 int result = MM_ERROR_NONE;
8342 mmplayer_t *player = (mmplayer_t *)hplayer;
8347 /* check player handle */
8348 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8350 /* filepath can be null in idle state */
8352 /* check file path */
8353 if ((path = strstr(filepath, "file://")))
8354 result = _mmplayer_exist_file_path(path + 7);
8356 result = _mmplayer_exist_file_path(filepath);
8358 if (result != MM_ERROR_NONE) {
8359 LOGE("invalid subtitle path 0x%X", result);
8360 return result; /* file not found or permission denied */
8364 if (!player->pipeline) {
8366 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8367 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8368 LOGE("failed to set attribute");
8369 return MM_ERROR_PLAYER_INTERNAL;
8372 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8373 /* check filepath */
8374 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8376 if (!__mmplayer_check_subtitle(player)) {
8377 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8378 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8379 LOGE("failed to set attribute");
8380 return MM_ERROR_PLAYER_INTERNAL;
8383 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8384 LOGE("fail to create text pipeline");
8385 return MM_ERROR_PLAYER_INTERNAL;
8388 result = _mmplayer_sync_subtitle_pipeline(player);
8390 result = __mmplayer_change_external_subtitle_language(player, filepath);
8393 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8394 player->is_external_subtitle_added_now = TRUE;
8396 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8397 if (!player->subtitle_language_list) {
8398 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8399 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8400 LOGW("subtitle language list is not updated yet");
8402 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8410 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8412 guint active_idx = 0;
8413 GstStream *stream = NULL;
8414 GList *streams = NULL;
8415 GstCaps *caps = NULL;
8418 LOGD("Switching Streams... type: %d, index: %d", type, index);
8420 player->track[type].active_track_index = index;
8422 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8423 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8424 LOGD("track type:%d, total: %d, active: %d", i,
8425 player->track[i].total_track_num, player->track[i].active_track_index);
8426 if (player->track[i].total_track_num > 0 &&
8427 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8428 active_idx = player->track[i].active_track_index;
8429 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8430 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8431 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8433 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8434 caps = gst_stream_get_caps(stream);
8436 _mmplayer_set_audio_attrs(player, caps);
8437 gst_caps_unref(caps);
8444 LOGD("send select stream event");
8445 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8446 gst_event_new_select_streams(streams));
8447 g_list_free(streams);
8451 return MM_ERROR_NONE;
8455 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8457 int result = MM_ERROR_NONE;
8458 gchar *change_pad_name = NULL;
8459 GstPad *sinkpad = NULL;
8460 mmplayer_gst_element_t *mainbin = NULL;
8461 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8462 GstCaps *caps = NULL;
8463 gint total_track_num = 0;
8467 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8468 MM_ERROR_PLAYER_NOT_INITIALIZED);
8470 LOGD("Change Track(%d) to %d", type, index);
8472 mainbin = player->pipeline->mainbin;
8474 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8475 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8476 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8477 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8479 /* Changing Video Track is not supported. */
8480 LOGE("Track Type Error");
8484 if (mainbin[elem_idx].gst == NULL) {
8485 result = MM_ERROR_PLAYER_NO_OP;
8486 LOGD("Req track doesn't exist");
8490 total_track_num = player->track[type].total_track_num;
8491 if (total_track_num <= 0) {
8492 result = MM_ERROR_PLAYER_NO_OP;
8493 LOGD("Language list is not available");
8497 if ((index < 0) || (index >= total_track_num)) {
8498 result = MM_ERROR_INVALID_ARGUMENT;
8499 LOGD("Not a proper index : %d", index);
8503 /*To get the new pad from the selector*/
8504 change_pad_name = g_strdup_printf("sink_%u", index);
8505 if (change_pad_name == NULL) {
8506 result = MM_ERROR_PLAYER_INTERNAL;
8507 LOGD("Pad does not exists");
8511 LOGD("new active pad name: %s", change_pad_name);
8513 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8514 if (sinkpad == NULL) {
8515 LOGD("sinkpad is NULL");
8516 result = MM_ERROR_PLAYER_INTERNAL;
8520 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8521 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8523 caps = gst_pad_get_current_caps(sinkpad);
8524 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8527 gst_object_unref(sinkpad);
8529 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8530 _mmplayer_set_audio_attrs(player, caps);
8533 gst_caps_unref(caps);
8536 MMPLAYER_FREEIF(change_pad_name);
8541 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8543 int result = MM_ERROR_NONE;
8544 mmplayer_t *player = NULL;
8545 mmplayer_gst_element_t *mainbin = NULL;
8547 gint current_active_index = 0;
8549 GstState current_state = GST_STATE_VOID_PENDING;
8554 player = (mmplayer_t *)hplayer;
8555 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8557 if (!player->pipeline) {
8558 LOGE("Track %d pre setting -> %d", type, index);
8560 player->track[type].active_track_index = index;
8564 mainbin = player->pipeline->mainbin;
8566 current_active_index = player->track[type].active_track_index;
8568 /*If index is same as running index no need to change the pad*/
8569 if (current_active_index == index)
8572 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8573 result = MM_ERROR_PLAYER_INVALID_STATE;
8577 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8578 if (current_state < GST_STATE_PAUSED) {
8579 result = MM_ERROR_PLAYER_INVALID_STATE;
8580 LOGW("Pipeline not in proper state");
8584 if (MMPLAYER_USE_DECODEBIN(player))
8585 result = __mmplayer_change_selector_pad(player, type, index);
8587 result = __mmplayer_switch_stream(player, type, index);
8589 if (result != MM_ERROR_NONE) {
8590 LOGE("failed to change track");
8594 player->track[type].active_track_index = index;
8596 if (MMPLAYER_USE_DECODEBIN(player)) {
8597 GstEvent *event = NULL;
8598 if (current_state == GST_STATE_PLAYING) {
8599 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8600 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8601 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8603 _mmplayer_gst_send_event_to_sink(player, event);
8605 result = MM_ERROR_PLAYER_INTERNAL;
8616 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8618 mmplayer_t *player = (mmplayer_t *)hplayer;
8622 /* check player handle */
8623 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8625 *silent = player->set_mode.subtitle_off;
8627 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8631 return MM_ERROR_NONE;
8635 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8637 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8638 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8640 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8641 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8645 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8646 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8647 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8648 mmplayer_dump_t *dump_s;
8649 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8650 if (dump_s == NULL) {
8651 LOGE("malloc fail");
8655 dump_s->dump_element_file = NULL;
8656 dump_s->dump_pad = NULL;
8657 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8659 if (dump_s->dump_pad) {
8660 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8661 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]);
8662 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8663 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);
8664 /* add list for removed buffer probe and close FILE */
8665 player->dump_list = g_list_append(player->dump_list, dump_s);
8666 LOGD("%s sink pad added buffer probe for dump", factory_name);
8669 MMPLAYER_FREEIF(dump_s);
8670 LOGE("failed to get %s sink pad added", factory_name);
8677 static GstPadProbeReturn
8678 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8680 FILE *dump_data = (FILE *)u_data;
8682 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8683 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8685 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8687 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8689 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8691 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8693 gst_buffer_unmap(buffer, &probe_info);
8695 return GST_PAD_PROBE_OK;
8699 __mmplayer_release_dump_list(GList *dump_list)
8701 GList *d_list = dump_list;
8706 for (; d_list; d_list = g_list_next(d_list)) {
8707 mmplayer_dump_t *dump_s = d_list->data;
8708 if (dump_s->dump_pad) {
8709 if (dump_s->probe_handle_id)
8710 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8711 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8713 if (dump_s->dump_element_file) {
8714 fclose(dump_s->dump_element_file);
8715 dump_s->dump_element_file = NULL;
8717 MMPLAYER_FREEIF(dump_s);
8719 g_list_free(dump_list);
8724 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8726 mmplayer_t *player = (mmplayer_t *)hplayer;
8730 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8731 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8733 *exist = (bool)player->has_closed_caption;
8737 return MM_ERROR_NONE;
8741 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8746 LOGD("unref internal gst buffer %p", buffer);
8748 gst_buffer_unref((GstBuffer *)buffer);
8755 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8757 mmplayer_t *player = (mmplayer_t *)hplayer;
8761 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8762 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8764 if (MMPLAYER_IS_STREAMING(player))
8765 *timeout = (int)player->ini.live_state_change_timeout;
8767 *timeout = (int)player->ini.localplayback_state_change_timeout;
8769 LOGD("timeout = %d", *timeout);
8772 return MM_ERROR_NONE;
8776 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8780 MMPLAYER_RETURN_IF_FAIL(player);
8782 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8784 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8785 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8786 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8787 player->storage_info[i].id = -1;
8788 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8790 if (path_type != MMPLAYER_PATH_MAX)
8799 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8801 int ret = MM_ERROR_NONE;
8802 mmplayer_t *player = (mmplayer_t *)hplayer;
8803 MMMessageParamType msg_param = {0, };
8806 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8808 LOGW("state changed storage %d:%d", id, state);
8810 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8811 return MM_ERROR_NONE;
8813 /* FIXME: text path should be handled separately. */
8814 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8815 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8816 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8817 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8818 LOGW("external storage is removed");
8820 if (player->msg_posted == FALSE) {
8821 memset(&msg_param, 0, sizeof(MMMessageParamType));
8822 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8823 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8824 player->msg_posted = TRUE;
8827 /* unrealize the player */
8828 ret = _mmplayer_unrealize(hplayer);
8829 if (ret != MM_ERROR_NONE)
8830 LOGE("failed to unrealize");
8838 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8840 int ret = MM_ERROR_NONE;
8841 mmplayer_t *player = (mmplayer_t *)hplayer;
8842 int idx = 0, total = 0;
8843 gchar *result = NULL, *tmp = NULL;
8846 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8847 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8849 total = *num = g_list_length(player->adaptive_info.var_list);
8851 LOGW("There is no stream variant info.");
8855 result = g_strdup("");
8856 for (idx = 0 ; idx < total ; idx++) {
8857 stream_variant_t *v_data = NULL;
8858 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8861 gchar data[64] = {0};
8862 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8864 tmp = g_strconcat(result, data, NULL);
8868 LOGW("There is no variant data in %d", idx);
8873 *var_info = (char *)result;
8875 LOGD("variant info %d:%s", *num, *var_info);
8881 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8883 int ret = MM_ERROR_NONE;
8884 mmplayer_t *player = (mmplayer_t *)hplayer;
8887 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8889 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8891 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8892 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8893 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8895 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8896 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8897 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8898 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8900 /* FIXME: seek to current position for applying new variant limitation */
8909 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8911 int ret = MM_ERROR_NONE;
8912 mmplayer_t *player = (mmplayer_t *)hplayer;
8915 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8916 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8918 *bandwidth = player->adaptive_info.limit.bandwidth;
8919 *width = player->adaptive_info.limit.width;
8920 *height = player->adaptive_info.limit.height;
8922 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8929 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8931 int ret = MM_ERROR_NONE;
8932 mmplayer_t *player = (mmplayer_t *)hplayer;
8935 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8936 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8937 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8939 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8941 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8942 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8943 else /* live case */
8944 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8946 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8953 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8955 #define IDX_FIRST_SW_CODEC 0
8956 mmplayer_t *player = (mmplayer_t *)hplayer;
8957 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8958 const char *attr_name = NULL;
8959 const char *default_type = NULL;
8960 const char *element_hw = NULL;
8961 const char *element_sw = NULL;
8964 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8966 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8968 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8969 switch (stream_type) {
8970 case MM_PLAYER_STREAM_TYPE_AUDIO:
8971 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8972 default_type = player->ini.audiocodec_default_type;
8973 element_hw = player->ini.audiocodec_element_hw;
8974 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8976 case MM_PLAYER_STREAM_TYPE_VIDEO:
8977 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8978 default_type = player->ini.videocodec_default_type;
8979 element_hw = player->ini.videocodec_element_hw;
8980 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8983 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8984 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8988 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8990 if (!strcmp(default_type, "sw"))
8991 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8993 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8995 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8996 codec_type = default_codec_type;
8998 /* to support codec selection, codec info have to be added in ini file.
8999 in case of hw codec is selected, filter elements should be applied
9000 depending on the hw capabilities. */
9001 if (codec_type != default_codec_type) {
9002 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9003 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9004 LOGE("There is no codec for type %d", codec_type);
9005 return MM_ERROR_PLAYER_NO_OP;
9008 LOGD("sorting is required");
9009 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9010 player->need_audio_dec_sorting = TRUE;
9012 player->need_video_dec_sorting = TRUE;
9015 LOGD("update %s codec_type to %d", attr_name, codec_type);
9016 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9019 return MM_ERROR_NONE;
9023 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9025 mmplayer_t *player = (mmplayer_t *)hplayer;
9026 GstElement *rg_vol_element = NULL;
9030 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9032 player->sound.rg_enable = enabled;
9034 /* just hold rgvolume enable value if pipeline is not ready */
9035 if (!player->pipeline || !player->pipeline->audiobin) {
9036 LOGD("pipeline is not ready. holding rgvolume enable value");
9037 return MM_ERROR_NONE;
9040 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9042 if (!rg_vol_element) {
9043 LOGD("rgvolume element is not created");
9044 return MM_ERROR_PLAYER_INTERNAL;
9048 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9050 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9054 return MM_ERROR_NONE;
9058 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9060 mmplayer_t *player = (mmplayer_t *)hplayer;
9061 GstElement *rg_vol_element = NULL;
9062 gboolean enable = FALSE;
9066 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9067 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9069 /* just hold enable_rg value if pipeline is not ready */
9070 if (!player->pipeline || !player->pipeline->audiobin) {
9071 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9072 *enabled = player->sound.rg_enable;
9073 return MM_ERROR_NONE;
9076 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9078 if (!rg_vol_element) {
9079 LOGD("rgvolume element is not created");
9080 return MM_ERROR_PLAYER_INTERNAL;
9083 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9084 *enabled = (bool)enable;
9088 return MM_ERROR_NONE;
9092 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9094 mmplayer_t *player = (mmplayer_t *)hplayer;
9095 MMHandleType attrs = 0;
9097 int ret = MM_ERROR_NONE;
9101 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9103 attrs = MMPLAYER_GET_ATTRS(player);
9104 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9106 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9108 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9109 return MM_ERROR_PLAYER_INTERNAL;
9112 player->video_roi.scale_x = scale_x;
9113 player->video_roi.scale_y = scale_y;
9114 player->video_roi.scale_width = scale_width;
9115 player->video_roi.scale_height = scale_height;
9117 /* check video sinkbin is created */
9118 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9119 return MM_ERROR_NONE;
9121 if (!gst_video_overlay_set_video_roi_area(
9122 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9123 scale_x, scale_y, scale_width, scale_height))
9124 ret = MM_ERROR_PLAYER_INTERNAL;
9126 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9127 scale_x, scale_y, scale_width, scale_height);
9135 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9137 mmplayer_t *player = (mmplayer_t *)hplayer;
9138 int ret = MM_ERROR_NONE;
9142 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9143 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9145 *scale_x = player->video_roi.scale_x;
9146 *scale_y = player->video_roi.scale_y;
9147 *scale_width = player->video_roi.scale_width;
9148 *scale_height = player->video_roi.scale_height;
9150 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9151 *scale_x, *scale_y, *scale_width, *scale_height);
9157 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9159 mmplayer_t *player = (mmplayer_t *)hplayer;
9163 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9165 player->client_pid = pid;
9167 LOGD("client pid[%d] %p", pid, player);
9171 return MM_ERROR_NONE;
9175 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9177 mmplayer_t *player = (mmplayer_t *)hplayer;
9178 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9179 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9183 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9184 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9187 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9189 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9191 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9192 return MM_ERROR_NONE;
9194 /* in case of audio codec default type is HW */
9196 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9197 if (player->ini.support_audio_effect)
9198 return MM_ERROR_NONE;
9199 elem_id = MMPLAYER_A_FILTER;
9201 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9202 if (player->ini.support_replaygain_control)
9203 return MM_ERROR_NONE;
9204 elem_id = MMPLAYER_A_RGVOL;
9206 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9207 if (player->ini.support_pitch_control)
9208 return MM_ERROR_NONE;
9209 elem_id = MMPLAYER_A_PITCH;
9211 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9212 if (player->ini.support_audio_effect)
9213 return MM_ERROR_NONE;
9215 /* default case handling is not required */
9218 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9219 LOGW("audio control option [%d] is not available", opt);
9222 /* setting pcm exporting option is allowed before READY state */
9223 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9224 return MM_ERROR_PLAYER_INVALID_STATE;
9226 /* check whether the audio filter exist or not after READY state,
9227 because the sw codec could be added during auto-plugging in some cases */
9228 if (!player->pipeline ||
9229 !player->pipeline->audiobin ||
9230 !player->pipeline->audiobin[elem_id].gst) {
9231 LOGW("there is no audio elem [%d]", elem_id);
9236 LOGD("audio control opt %d, available %d", opt, *available);
9240 return MM_ERROR_NONE;
9244 __mmplayer_update_duration_value(mmplayer_t *player)
9246 gboolean ret = FALSE;
9247 gint64 dur_nsec = 0;
9248 LOGD("try to update duration");
9250 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9251 player->duration = dur_nsec;
9252 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9256 if (player->duration < 0) {
9257 LOGW("duration is Non-Initialized !!!");
9258 player->duration = 0;
9261 /* update streaming service type */
9262 player->streaming_type = _mmplayer_get_stream_service_type(player);
9264 /* check duration is OK */
9265 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9266 /* FIXIT : find another way to get duration here. */
9267 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9273 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9275 /* update audio params
9276 NOTE : We need original audio params and it can be only obtained from src pad of audio
9277 decoder. Below code only valid when we are not using 'resampler' just before
9278 'audioconverter'. */
9279 GstCaps *caps_a = NULL;
9281 gint samplerate = 0, channels = 0;
9282 GstStructure *p = NULL;
9283 GstElement *aconv = NULL;
9285 LOGD("try to update audio attrs");
9287 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9289 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9290 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9291 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9292 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9294 LOGE("there is no audio converter");
9298 pad = gst_element_get_static_pad(aconv, "sink");
9301 LOGW("failed to get pad from audio converter");
9305 caps_a = gst_pad_get_current_caps(pad);
9307 LOGW("not ready to get audio caps");
9308 gst_object_unref(pad);
9312 p = gst_caps_get_structure(caps_a, 0);
9314 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9316 gst_structure_get_int(p, "rate", &samplerate);
9317 gst_structure_get_int(p, "channels", &channels);
9319 mm_player_set_attribute((MMHandleType)player, NULL,
9320 "content_audio_samplerate", samplerate,
9321 "content_audio_channels", channels, NULL);
9323 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9325 gst_caps_unref(caps_a);
9326 gst_object_unref(pad);
9332 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9334 LOGD("try to update video attrs");
9336 GstCaps *caps_v = NULL;
9340 GstStructure *p = NULL;
9342 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9343 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9345 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9347 LOGD("no videosink sink pad");
9351 caps_v = gst_pad_get_current_caps(pad);
9352 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9353 if (!caps_v && player->v_stream_caps) {
9354 caps_v = player->v_stream_caps;
9355 gst_caps_ref(caps_v);
9359 LOGD("no negotiated caps from videosink");
9360 gst_object_unref(pad);
9364 p = gst_caps_get_structure(caps_v, 0);
9365 gst_structure_get_int(p, "width", &width);
9366 gst_structure_get_int(p, "height", &height);
9368 mm_player_set_attribute((MMHandleType)player, NULL,
9369 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9371 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9373 SECURE_LOGD("width : %d height : %d", width, height);
9375 gst_caps_unref(caps_v);
9376 gst_object_unref(pad);
9379 mm_player_set_attribute((MMHandleType)player, NULL,
9380 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9381 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9388 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9390 gboolean ret = FALSE;
9391 guint64 data_size = 0;
9395 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9396 if (!player->duration)
9399 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9400 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9401 if (stat(path, &sb) == 0)
9402 data_size = (guint64)sb.st_size;
9404 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9405 data_size = player->http_content_size;
9408 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9411 guint64 bitrate = 0;
9412 guint64 msec_dur = 0;
9414 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9416 bitrate = data_size * 8 * 1000 / msec_dur;
9417 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9418 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9419 mm_player_set_attribute((MMHandleType)player, NULL,
9420 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9423 LOGD("player duration is less than 0");
9427 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9428 if (player->total_bitrate) {
9429 mm_player_set_attribute((MMHandleType)player, NULL,
9430 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9439 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9441 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9442 data->uri_type = uri_type;
9446 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9448 int ret = MM_ERROR_PLAYER_INVALID_URI;
9450 char *buffer = NULL;
9451 char *seperator = strchr(path, ',');
9452 char ext[100] = {0,}, size[100] = {0,};
9455 if ((buffer = strstr(path, "ext="))) {
9456 buffer += strlen("ext=");
9458 if (strlen(buffer)) {
9459 strncpy(ext, buffer, 99);
9461 if ((seperator = strchr(ext, ','))
9462 || (seperator = strchr(ext, ' '))
9463 || (seperator = strchr(ext, '\0'))) {
9464 seperator[0] = '\0';
9469 if ((buffer = strstr(path, "size="))) {
9470 buffer += strlen("size=");
9472 if (strlen(buffer) > 0) {
9473 strncpy(size, buffer, 99);
9475 if ((seperator = strchr(size, ','))
9476 || (seperator = strchr(size, ' '))
9477 || (seperator = strchr(size, '\0'))) {
9478 seperator[0] = '\0';
9481 mem_size = atoi(size);
9486 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9488 if (mem_size && param) {
9489 if (data->input_mem.buf)
9490 free(data->input_mem.buf);
9491 data->input_mem.buf = malloc(mem_size);
9493 if (data->input_mem.buf) {
9494 memcpy(data->input_mem.buf, param, mem_size);
9495 data->input_mem.len = mem_size;
9496 ret = MM_ERROR_NONE;
9498 LOGE("failed to alloc mem %d", mem_size);
9499 ret = MM_ERROR_PLAYER_INTERNAL;
9502 data->input_mem.offset = 0;
9503 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9510 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9512 gchar *location = NULL;
9515 int ret = MM_ERROR_NONE;
9517 if ((path = strstr(uri, "file://"))) {
9518 location = g_filename_from_uri(uri, NULL, &err);
9519 if (!location || (err != NULL)) {
9520 LOGE("Invalid URI '%s' for filesrc: %s", path,
9521 (err != NULL) ? err->message : "unknown error");
9525 MMPLAYER_FREEIF(location);
9527 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9528 return MM_ERROR_PLAYER_INVALID_URI;
9530 LOGD("path from uri: %s", location);
9533 path = (location != NULL) ? (location) : ((char *)uri);
9536 ret = _mmplayer_exist_file_path(path);
9538 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9539 if (ret == MM_ERROR_NONE) {
9540 if (_mmplayer_is_sdp_file(path)) {
9541 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9542 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9543 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9545 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9546 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9548 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9549 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9551 LOGE("invalid uri, could not play..");
9552 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9555 MMPLAYER_FREEIF(location);
9560 static mmplayer_video_decoded_data_info_t *
9561 __mmplayer_create_stream_from_pad(GstPad *pad)
9563 GstCaps *caps = NULL;
9564 GstStructure *structure = NULL;
9565 unsigned int fourcc = 0;
9566 const gchar *string_format = NULL;
9567 mmplayer_video_decoded_data_info_t *stream = NULL;
9569 MMPixelFormatType format;
9572 caps = gst_pad_get_current_caps(pad);
9574 LOGE("Caps is NULL.");
9579 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9581 structure = gst_caps_get_structure(caps, 0);
9582 gst_structure_get_int(structure, "width", &width);
9583 gst_structure_get_int(structure, "height", &height);
9584 string_format = gst_structure_get_string(structure, "format");
9587 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9588 format = _mmplayer_get_pixtype(fourcc);
9589 gst_video_info_from_caps(&info, caps);
9590 gst_caps_unref(caps);
9593 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9594 LOGE("Wrong condition!!");
9598 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9600 LOGE("failed to alloc mem for video data");
9604 stream->width = width;
9605 stream->height = height;
9606 stream->format = format;
9607 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9613 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9615 unsigned int pitch = 0;
9616 unsigned int size = 0;
9618 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9621 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9622 bo = gst_tizen_memory_get_bos(mem, index);
9624 stream->bo[index] = tbm_bo_ref(bo);
9626 LOGE("failed to get bo for index %d", index);
9629 for (index = 0; index < stream->plane_num; index++) {
9630 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9631 stream->stride[index] = pitch;
9633 stream->elevation[index] = size / pitch;
9635 stream->elevation[index] = stream->height;
9640 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9642 if (stream->format == MM_PIXEL_FORMAT_I420) {
9643 int ret = TBM_SURFACE_ERROR_NONE;
9644 tbm_surface_h surface;
9645 tbm_surface_info_s info;
9647 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9649 ret = tbm_surface_get_info(surface, &info);
9650 if (ret != TBM_SURFACE_ERROR_NONE) {
9651 tbm_surface_destroy(surface);
9655 tbm_surface_destroy(surface);
9656 stream->stride[0] = info.planes[0].stride;
9657 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9658 stream->stride[1] = info.planes[1].stride;
9659 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9660 stream->stride[2] = info.planes[2].stride;
9661 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9662 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9663 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9664 stream->stride[0] = stream->width * 4;
9665 stream->elevation[0] = stream->height;
9666 stream->bo_size = stream->stride[0] * stream->height;
9668 LOGE("Not support format %d", stream->format);
9676 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9678 tbm_bo_handle thandle;
9680 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9681 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9682 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9686 unsigned char *src = NULL;
9687 unsigned char *dest = NULL;
9688 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9690 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9692 LOGE("fail to gst_memory_map");
9696 if (!mapinfo.data) {
9697 LOGE("data pointer is wrong");
9701 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9702 if (!stream->bo[0]) {
9703 LOGE("Fail to tbm_bo_alloc!!");
9707 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9709 LOGE("thandle pointer is wrong");
9713 if (stream->format == MM_PIXEL_FORMAT_I420) {
9714 src_stride[0] = GST_ROUND_UP_4(stream->width);
9715 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9716 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9717 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9720 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9721 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9723 for (i = 0; i < 3; i++) {
9724 src = mapinfo.data + src_offset[i];
9725 dest = thandle.ptr + dest_offset[i];
9730 for (j = 0; j < stream->height >> k; j++) {
9731 memcpy(dest, src, stream->width>>k);
9732 src += src_stride[i];
9733 dest += stream->stride[i];
9736 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9737 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9739 LOGE("Not support format %d", stream->format);
9743 tbm_bo_unmap(stream->bo[0]);
9744 gst_memory_unmap(mem, &mapinfo);
9750 tbm_bo_unmap(stream->bo[0]);
9753 gst_memory_unmap(mem, &mapinfo);
9759 __mmplayer_set_pause_state(mmplayer_t *player)
9761 if (player->sent_bos)
9764 /* rtsp case, get content attrs by GstMessage */
9765 if (MMPLAYER_IS_RTSP_STREAMING(player))
9768 /* it's first time to update all content attrs. */
9769 _mmplayer_update_content_attrs(player, ATTR_ALL);
9773 __mmplayer_set_playing_state(mmplayer_t *player)
9775 gchar *audio_codec = NULL;
9777 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9778 /* initialize because auto resume is done well. */
9779 player->resumed_by_rewind = FALSE;
9780 player->playback_rate = 1.0;
9783 if (player->sent_bos)
9786 /* try to get content metadata */
9788 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9789 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9790 * legacy mmfw-player api
9792 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9794 if ((player->cmd == MMPLAYER_COMMAND_START)
9795 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9796 __mmplayer_handle_missed_plugin(player);
9799 /* check audio codec field is set or not
9800 * we can get it from typefinder or codec's caps.
9802 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9804 /* The codec format can't be sent for audio only case like amr, mid etc.
9805 * Because, parser don't make related TAG.
9806 * So, if it's not set yet, fill it with found data.
9809 if (g_strrstr(player->type, "audio/midi"))
9810 audio_codec = "MIDI";
9811 else if (g_strrstr(player->type, "audio/x-amr"))
9812 audio_codec = "AMR";
9813 else if (g_strrstr(player->type, "audio/mpeg")
9814 && !g_strrstr(player->type, "mpegversion=(int)1"))
9815 audio_codec = "AAC";
9817 audio_codec = "unknown";
9819 if (mm_player_set_attribute((MMHandleType)player, NULL,
9820 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9821 LOGE("failed to set attribute");
9823 LOGD("set audio codec type with caps");