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;
3276 gint64 end_time = 0;
3278 /* check DRC, if it is, destroy the prev bo list to create again */
3279 if (player->video_bo_size != size) {
3280 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3281 __mmplayer_video_stream_destroy_bo_list(player);
3282 player->video_bo_size = size;
3285 MMPLAYER_VIDEO_BO_LOCK(player);
3287 if ((!player->video_bo_list) ||
3288 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3290 /* create bo list */
3292 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3294 if (player->video_bo_list) {
3295 /* if bo list did not created all, try it again. */
3296 idx = g_list_length(player->video_bo_list);
3297 LOGD("bo list exist(len: %d)", idx);
3300 for (; idx < player->ini.num_of_video_bo; idx++) {
3301 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3303 LOGE("Fail to alloc bo_info.");
3306 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3308 LOGE("Fail to tbm_bo_alloc.");
3309 MMPLAYER_FREEIF(bo_info);
3312 bo_info->used = FALSE;
3313 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3316 /* update video num buffers */
3317 LOGD("video_num_buffers : %d", idx);
3318 mm_player_set_attribute((MMHandleType)player, NULL,
3319 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3320 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3324 MMPLAYER_VIDEO_BO_UNLOCK(player);
3329 if (player->ini.video_bo_timeout > 0)
3330 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3333 /* get bo from list*/
3334 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3335 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3336 if (tmp && (tmp->used == FALSE)) {
3337 LOGD("found bo %p to use", tmp->bo);
3339 MMPLAYER_VIDEO_BO_UNLOCK(player);
3340 return tbm_bo_ref(tmp->bo);
3344 if (player->ini.video_bo_timeout <= 0) {
3345 MMPLAYER_VIDEO_BO_WAIT(player);
3347 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3349 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3355 MMPLAYER_VIDEO_BO_UNLOCK(player);
3360 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3362 mmplayer_t *player = (mmplayer_t *)data;
3364 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3366 /* send prerolled pkt */
3367 player->video_stream_prerolled = false;
3369 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3371 /* not to send prerolled pkt again */
3372 player->video_stream_prerolled = true;
3376 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3378 mmplayer_t *player = (mmplayer_t *)data;
3379 mmplayer_video_decoded_data_info_t *stream = NULL;
3380 GstMemory *mem = NULL;
3383 MMPLAYER_RETURN_IF_FAIL(player);
3384 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3386 if (player->video_stream_prerolled) {
3387 player->video_stream_prerolled = false;
3388 LOGD("skip the prerolled pkt not to send it again");
3392 /* clear stream data structure */
3393 stream = __mmplayer_create_stream_from_pad(pad);
3395 LOGE("failed to alloc stream");
3399 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3401 /* set size and timestamp */
3402 mem = gst_buffer_peek_memory(buffer, 0);
3403 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3404 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3406 /* check zero-copy */
3407 if (player->set_mode.video_zc &&
3408 player->set_mode.video_export &&
3409 gst_is_tizen_memory(mem)) {
3410 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3411 stream->internal_buffer = gst_buffer_ref(buffer);
3412 } else { /* sw codec */
3413 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3416 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3420 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3421 LOGE("failed to send video decoded data.");
3428 LOGE("release video stream resource.");
3429 if (gst_is_tizen_memory(mem)) {
3431 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3433 tbm_bo_unref(stream->bo[i]);
3436 /* unref gst buffer */
3437 if (stream->internal_buffer)
3438 gst_buffer_unref(stream->internal_buffer);
3441 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3443 MMPLAYER_FREEIF(stream);
3448 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3450 mmplayer_gst_element_t *videobin = NULL;
3453 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3455 videobin = player->pipeline->videobin;
3457 /* Set spatial media metadata and/or user settings to the element.
3459 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3460 "projection-type", player->video360_metadata.projection_type, NULL);
3462 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3463 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3465 if (player->video360_metadata.full_pano_width_pixels &&
3466 player->video360_metadata.full_pano_height_pixels &&
3467 player->video360_metadata.cropped_area_image_width &&
3468 player->video360_metadata.cropped_area_image_height) {
3469 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3470 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3471 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3472 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3473 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3474 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3475 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3479 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3480 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3481 "horizontal-fov", player->video360_horizontal_fov,
3482 "vertical-fov", player->video360_vertical_fov, NULL);
3485 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3486 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3487 "zoom", 1.0f / player->video360_zoom, NULL);
3490 if (player->video360_yaw_radians <= M_PI &&
3491 player->video360_yaw_radians >= -M_PI &&
3492 player->video360_pitch_radians <= M_PI_2 &&
3493 player->video360_pitch_radians >= -M_PI_2) {
3494 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3495 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3496 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3497 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3498 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3499 "pose-yaw", player->video360_metadata.init_view_heading,
3500 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3503 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3504 "passthrough", !player->is_video360_enabled, NULL);
3511 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3513 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3514 GList *element_bucket = NULL;
3517 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3519 /* create video360 filter */
3520 if (player->is_360_feature_enabled && player->is_content_spherical) {
3521 LOGD("create video360 element");
3522 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3523 __mmplayer_gst_set_video360_property(player);
3527 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3528 LOGD("skip creating the videoconv and rotator");
3529 return MM_ERROR_NONE;
3532 /* in case of sw codec & overlay surface type, except 360 playback.
3533 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3534 LOGD("create video converter: %s", video_csc);
3535 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3538 *bucket = element_bucket;
3540 return MM_ERROR_NONE;
3542 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3543 g_list_free(element_bucket);
3547 return MM_ERROR_PLAYER_INTERNAL;
3551 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3553 gchar *factory_name = NULL;
3555 switch (surface_type) {
3556 case MM_DISPLAY_SURFACE_OVERLAY:
3557 if (strlen(player->ini.videosink_element_overlay) > 0)
3558 factory_name = player->ini.videosink_element_overlay;
3560 case MM_DISPLAY_SURFACE_REMOTE:
3561 case MM_DISPLAY_SURFACE_NULL:
3562 if (strlen(player->ini.videosink_element_fake) > 0)
3563 factory_name = player->ini.videosink_element_fake;
3566 LOGE("unidentified surface type");
3570 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3571 return factory_name;
3575 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3577 gchar *factory_name = NULL;
3578 mmplayer_gst_element_t *videobin = NULL;
3583 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3585 videobin = player->pipeline->videobin;
3586 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3588 attrs = MMPLAYER_GET_ATTRS(player);
3590 LOGE("cannot get content attribute");
3591 return MM_ERROR_PLAYER_INTERNAL;
3594 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3595 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3596 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3597 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3598 "use-tbm", use_tbm, NULL);
3601 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3602 return MM_ERROR_PLAYER_INTERNAL;
3604 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3607 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3608 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3611 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3613 LOGD("disable last-sample");
3614 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3617 if (player->set_mode.video_export) {
3619 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3620 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3621 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3623 _mmplayer_add_signal_connection(player,
3624 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3625 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3627 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3630 _mmplayer_add_signal_connection(player,
3631 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3632 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3634 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3638 if (videobin[MMPLAYER_V_SINK].gst) {
3639 GstPad *sink_pad = NULL;
3640 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3642 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3643 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3644 gst_object_unref(GST_OBJECT(sink_pad));
3646 LOGE("failed to get sink pad from videosink");
3650 return MM_ERROR_NONE;
3655 * - video overlay surface(arm/x86) : tizenwlsink
3658 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3661 GList *element_bucket = NULL;
3662 mmplayer_gst_element_t *first_element = NULL;
3663 mmplayer_gst_element_t *videobin = NULL;
3664 gchar *videosink_factory_name = NULL;
3667 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3670 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3672 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3674 player->pipeline->videobin = videobin;
3677 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3678 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3679 if (!videobin[MMPLAYER_V_BIN].gst) {
3680 LOGE("failed to create videobin");
3684 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3687 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3688 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3690 /* additional setting for sink plug-in */
3691 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3692 LOGE("failed to set video property");
3696 /* store it as it's sink element */
3697 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3699 /* adding created elements to bin */
3700 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3701 LOGE("failed to add elements");
3705 /* Linking elements in the bucket by added order */
3706 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3707 LOGE("failed to link elements");
3711 /* get first element's sinkpad for creating ghostpad */
3712 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3713 if (!first_element) {
3714 LOGE("failed to get first element from bucket");
3718 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3720 LOGE("failed to get pad from first element");
3724 /* create ghostpad */
3725 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3726 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3727 LOGE("failed to add ghostpad to videobin");
3730 gst_object_unref(pad);
3732 /* done. free allocated variables */
3733 g_list_free(element_bucket);
3737 return MM_ERROR_NONE;
3740 LOGE("ERROR : releasing videobin");
3741 g_list_free(element_bucket);
3744 gst_object_unref(GST_OBJECT(pad));
3746 /* release videobin with it's children */
3747 if (videobin[MMPLAYER_V_BIN].gst)
3748 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3750 MMPLAYER_FREEIF(videobin);
3751 player->pipeline->videobin = NULL;
3753 return MM_ERROR_PLAYER_INTERNAL;
3757 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3759 GList *element_bucket = NULL;
3760 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3762 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3763 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3764 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3765 "signal-handoffs", FALSE,
3768 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3769 _mmplayer_add_signal_connection(player,
3770 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3771 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3773 G_CALLBACK(__mmplayer_update_subtitle),
3776 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3777 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3779 if (!player->play_subtitle) {
3780 LOGD("add textbin sink as sink element of whole pipeline.");
3781 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3784 /* adding created elements to bin */
3785 LOGD("adding created elements to bin");
3786 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3787 LOGE("failed to add elements");
3788 g_list_free(element_bucket);
3792 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3793 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3794 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3796 /* linking elements in the bucket by added order. */
3797 LOGD("Linking elements in the bucket by added order.");
3798 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3799 LOGE("failed to link elements");
3800 g_list_free(element_bucket);
3804 /* done. free allocated variables */
3805 g_list_free(element_bucket);
3807 if (textbin[MMPLAYER_T_QUEUE].gst) {
3809 GstPad *ghostpad = NULL;
3811 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3813 LOGE("failed to get sink pad of text queue");
3817 ghostpad = gst_ghost_pad_new("text_sink", pad);
3818 gst_object_unref(pad);
3821 LOGE("failed to create ghostpad of textbin");
3825 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3826 LOGE("failed to add ghostpad to textbin");
3827 gst_object_unref(ghostpad);
3832 return MM_ERROR_NONE;
3836 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3837 LOGE("remove textbin sink from sink list");
3838 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3841 /* release element at __mmplayer_gst_create_text_sink_bin */
3842 return MM_ERROR_PLAYER_INTERNAL;
3846 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3848 mmplayer_gst_element_t *textbin = NULL;
3849 GList *element_bucket = NULL;
3850 int surface_type = 0;
3855 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3858 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3860 LOGE("failed to allocate memory for textbin");
3861 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3865 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3866 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3867 if (!textbin[MMPLAYER_T_BIN].gst) {
3868 LOGE("failed to create textbin");
3873 player->pipeline->textbin = textbin;
3876 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3877 LOGD("surface type for subtitle : %d", surface_type);
3878 switch (surface_type) {
3879 case MM_DISPLAY_SURFACE_OVERLAY:
3880 case MM_DISPLAY_SURFACE_NULL:
3881 case MM_DISPLAY_SURFACE_REMOTE:
3882 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3883 LOGE("failed to make plain text elements");
3894 return MM_ERROR_NONE;
3898 LOGD("ERROR : releasing textbin");
3900 g_list_free(element_bucket);
3902 /* release signal */
3903 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3905 /* release element which are not added to bin */
3906 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3907 /* NOTE : skip bin */
3908 if (textbin[i].gst) {
3909 GstObject *parent = NULL;
3910 parent = gst_element_get_parent(textbin[i].gst);
3913 gst_object_unref(GST_OBJECT(textbin[i].gst));
3914 textbin[i].gst = NULL;
3916 gst_object_unref(GST_OBJECT(parent));
3921 /* release textbin with it's children */
3922 if (textbin[MMPLAYER_T_BIN].gst)
3923 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3925 MMPLAYER_FREEIF(textbin);
3926 player->pipeline->textbin = NULL;
3929 return MM_ERROR_PLAYER_INTERNAL;
3933 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3935 mmplayer_gst_element_t *mainbin = NULL;
3936 mmplayer_gst_element_t *textbin = NULL;
3937 MMHandleType attrs = 0;
3938 GstElement *subsrc = NULL;
3939 GstElement *subparse = NULL;
3940 gchar *subtitle_uri = NULL;
3941 const gchar *charset = NULL;
3947 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3949 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3951 mainbin = player->pipeline->mainbin;
3953 attrs = MMPLAYER_GET_ATTRS(player);
3955 LOGE("cannot get content attribute");
3956 return MM_ERROR_PLAYER_INTERNAL;
3959 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3960 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3961 LOGE("subtitle uri is not proper filepath.");
3962 return MM_ERROR_PLAYER_INVALID_URI;
3965 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3966 LOGE("failed to get storage info of subtitle path");
3967 return MM_ERROR_PLAYER_INVALID_URI;
3970 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3972 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3973 player->subtitle_language_list = NULL;
3974 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3976 /* create the subtitle source */
3977 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3979 LOGE("failed to create filesrc element");
3982 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3984 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3985 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3987 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3988 LOGW("failed to add queue");
3989 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3990 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3991 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3996 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3998 LOGE("failed to create subparse element");
4002 charset = _mmplayer_get_charset(subtitle_uri);
4004 LOGD("detected charset is %s", charset);
4005 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4008 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4009 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4011 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4012 LOGW("failed to add subparse");
4013 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4014 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4015 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4019 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4020 LOGW("failed to link subsrc and subparse");
4024 player->play_subtitle = TRUE;
4025 player->adjust_subtitle_pos = 0;
4027 LOGD("play subtitle using subtitle file");
4029 if (player->pipeline->textbin == NULL) {
4030 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4031 LOGE("failed to create text sink bin. continuing without text");
4035 textbin = player->pipeline->textbin;
4037 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4038 LOGW("failed to add textbin");
4040 /* release signal */
4041 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4043 /* release textbin with it's children */
4044 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4045 MMPLAYER_FREEIF(player->pipeline->textbin);
4046 player->pipeline->textbin = textbin = NULL;
4050 LOGD("link text input selector and textbin ghost pad");
4052 player->textsink_linked = 1;
4053 player->external_text_idx = 0;
4054 LOGI("textsink is linked");
4056 textbin = player->pipeline->textbin;
4057 LOGD("text bin has been created. reuse it.");
4058 player->external_text_idx = 1;
4061 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4062 LOGW("failed to link subparse and textbin");
4066 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4068 LOGE("failed to get sink pad from textsink to probe data");
4072 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4073 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4075 gst_object_unref(pad);
4078 /* create dot. for debugging */
4079 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4082 return MM_ERROR_NONE;
4085 /* release text pipeline resource */
4086 player->textsink_linked = 0;
4088 /* release signal */
4089 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4091 if (player->pipeline->textbin) {
4092 LOGE("remove textbin");
4094 /* release textbin with it's children */
4095 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4096 MMPLAYER_FREEIF(player->pipeline->textbin);
4097 player->pipeline->textbin = NULL;
4101 /* release subtitle elem */
4102 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4103 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4105 return MM_ERROR_PLAYER_INTERNAL;
4109 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4111 mmplayer_t *player = (mmplayer_t *)data;
4112 MMMessageParamType msg = {0, };
4113 GstClockTime duration = 0;
4114 gpointer text = NULL;
4115 guint text_size = 0;
4116 gboolean ret = TRUE;
4117 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4121 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4122 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4124 if (player->is_subtitle_force_drop) {
4125 LOGW("subtitle is dropped forcedly.");
4129 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4130 text = mapinfo.data;
4131 text_size = mapinfo.size;
4133 if (player->set_mode.subtitle_off) {
4134 LOGD("subtitle is OFF.");
4138 if (!text || (text_size == 0)) {
4139 LOGD("There is no subtitle to be displayed.");
4143 msg.data = (void *)text;
4145 duration = GST_BUFFER_DURATION(buffer);
4147 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4148 if (player->duration > GST_BUFFER_PTS(buffer))
4149 duration = player->duration - GST_BUFFER_PTS(buffer);
4152 LOGI("subtitle duration is invalid, subtitle duration change "
4153 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4155 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4157 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4159 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4160 gst_buffer_unmap(buffer, &mapinfo);
4167 static GstPadProbeReturn
4168 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4170 mmplayer_t *player = (mmplayer_t *)u_data;
4171 GstClockTime cur_timestamp = 0;
4172 gint64 adjusted_timestamp = 0;
4173 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4175 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4177 if (player->set_mode.subtitle_off) {
4178 LOGD("subtitle is OFF.");
4182 if (player->adjust_subtitle_pos == 0) {
4183 LOGD("nothing to do");
4187 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4188 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4190 if (adjusted_timestamp < 0) {
4191 LOGD("adjusted_timestamp under zero");
4196 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4197 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4198 GST_TIME_ARGS(cur_timestamp),
4199 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4201 return GST_PAD_PROBE_OK;
4205 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4209 /* check player and subtitlebin are created */
4210 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4211 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4213 if (position == 0) {
4214 LOGD("nothing to do");
4216 return MM_ERROR_NONE;
4219 /* check current position */
4220 player->adjust_subtitle_pos = position;
4222 LOGD("save adjust_subtitle_pos in player");
4226 return MM_ERROR_NONE;
4230 * This function is to create audio or video pipeline for playing.
4232 * @param player [in] handle of player
4234 * @return This function returns zero on success.
4239 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4241 int ret = MM_ERROR_NONE;
4242 mmplayer_gst_element_t *mainbin = NULL;
4243 MMHandleType attrs = 0;
4246 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4248 /* get profile attribute */
4249 attrs = MMPLAYER_GET_ATTRS(player);
4251 LOGE("failed to get content attribute");
4255 /* create pipeline handles */
4256 if (player->pipeline) {
4257 LOGE("pipeline should be released before create new one");
4261 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4263 /* create mainbin */
4264 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4265 if (mainbin == NULL)
4268 /* create pipeline */
4269 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4270 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4271 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4272 LOGE("failed to create pipeline");
4277 player->pipeline->mainbin = mainbin;
4279 /* create the source and decoder elements */
4280 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4281 ret = _mmplayer_gst_build_es_pipeline(player);
4283 if (MMPLAYER_USE_DECODEBIN(player))
4284 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4286 ret = _mmplayer_gst_build_pipeline_with_src(player);
4289 if (ret != MM_ERROR_NONE) {
4290 LOGE("failed to create some elements");
4294 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4295 if (__mmplayer_check_subtitle(player)
4296 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4297 LOGE("failed to create text pipeline");
4300 ret = _mmplayer_gst_add_bus_watch(player);
4301 if (ret != MM_ERROR_NONE) {
4302 LOGE("failed to add bus watch");
4307 return MM_ERROR_NONE;
4310 _mmplayer_bus_watcher_remove(player);
4311 __mmplayer_gst_destroy_pipeline(player);
4312 return MM_ERROR_PLAYER_INTERNAL;
4316 __mmplayer_reset_gapless_state(mmplayer_t *player)
4319 MMPLAYER_RETURN_IF_FAIL(player
4321 && player->pipeline->audiobin
4322 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4324 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4331 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4334 int ret = MM_ERROR_NONE;
4338 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4340 /* cleanup stuffs */
4341 MMPLAYER_FREEIF(player->type);
4342 player->no_more_pad = FALSE;
4343 player->num_dynamic_pad = 0;
4345 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4346 player->subtitle_language_list = NULL;
4347 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4349 MMPLAYER_RECONFIGURE_LOCK(player);
4350 __mmplayer_reset_gapless_state(player);
4351 MMPLAYER_RECONFIGURE_UNLOCK(player);
4353 if (player->streamer) {
4354 _mm_player_streaming_initialize(player->streamer, FALSE);
4355 _mm_player_streaming_destroy(player->streamer);
4356 player->streamer = NULL;
4359 /* cleanup unlinked mime type */
4360 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4361 MMPLAYER_FREEIF(player->unlinked_video_mime);
4362 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4364 /* cleanup running stuffs */
4365 _mmplayer_cancel_eos_timer(player);
4367 /* cleanup gst stuffs */
4368 if (player->pipeline) {
4369 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4370 GstTagList *tag_list = player->pipeline->tag_list;
4372 /* first we need to disconnect all signal hander */
4373 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4376 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4377 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4378 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4379 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4380 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4381 gst_object_unref(bus);
4383 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4384 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4385 if (ret != MM_ERROR_NONE) {
4386 LOGE("fail to change state to NULL");
4387 return MM_ERROR_PLAYER_INTERNAL;
4390 LOGW("succeeded in changing state to NULL");
4392 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4395 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4396 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4398 MMPLAYER_FREEIF(audiobin);
4399 MMPLAYER_FREEIF(videobin);
4400 MMPLAYER_FREEIF(textbin);
4401 MMPLAYER_FREEIF(mainbin);
4405 gst_tag_list_unref(tag_list);
4407 MMPLAYER_FREEIF(player->pipeline);
4409 MMPLAYER_FREEIF(player->album_art);
4411 if (player->type_caps) {
4412 gst_caps_unref(player->type_caps);
4413 player->type_caps = NULL;
4416 if (player->v_stream_caps) {
4417 gst_caps_unref(player->v_stream_caps);
4418 player->v_stream_caps = NULL;
4421 if (player->a_stream_caps) {
4422 gst_caps_unref(player->a_stream_caps);
4423 player->a_stream_caps = NULL;
4426 if (player->s_stream_caps) {
4427 gst_caps_unref(player->s_stream_caps);
4428 player->s_stream_caps = NULL;
4430 _mmplayer_track_destroy(player);
4432 if (player->sink_elements)
4433 g_list_free(player->sink_elements);
4434 player->sink_elements = NULL;
4436 if (player->bufmgr) {
4437 tbm_bufmgr_deinit(player->bufmgr);
4438 player->bufmgr = NULL;
4441 LOGW("finished destroy pipeline");
4449 __mmplayer_gst_realize(mmplayer_t *player)
4452 int ret = MM_ERROR_NONE;
4456 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4458 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4460 ret = __mmplayer_gst_create_pipeline(player);
4462 LOGE("failed to create pipeline");
4466 /* set pipeline state to READY */
4467 /* NOTE : state change to READY must be performed sync. */
4468 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4469 ret = _mmplayer_gst_set_state(player,
4470 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4472 if (ret != MM_ERROR_NONE) {
4473 /* return error if failed to set state */
4474 LOGE("failed to set READY state");
4478 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4480 /* create dot before error-return. for debugging */
4481 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4489 __mmplayer_gst_unrealize(mmplayer_t *player)
4491 int ret = MM_ERROR_NONE;
4495 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4497 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4498 MMPLAYER_PRINT_STATE(player);
4500 /* release miscellaneous information */
4501 __mmplayer_release_misc(player);
4503 /* destroy pipeline */
4504 ret = __mmplayer_gst_destroy_pipeline(player);
4505 if (ret != MM_ERROR_NONE) {
4506 LOGE("failed to destroy pipeline");
4510 /* release miscellaneous information.
4511 these info needs to be released after pipeline is destroyed. */
4512 __mmplayer_release_misc_post(player);
4514 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4522 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4527 LOGW("set_message_callback is called with invalid player handle");
4528 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4531 player->msg_cb = callback;
4532 player->msg_cb_param = user_param;
4534 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4538 return MM_ERROR_NONE;
4542 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4544 int ret = MM_ERROR_NONE;
4549 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4550 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4551 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4553 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4555 if (strstr(uri, "es_buff://")) {
4556 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4557 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4558 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4559 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4561 tmp = g_ascii_strdown(uri, strlen(uri));
4562 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4563 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4565 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4567 } else if (strstr(uri, "mms://")) {
4568 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4569 } else if ((path = strstr(uri, "mem://"))) {
4570 ret = __mmplayer_set_mem_uri(data, path, param);
4572 ret = __mmplayer_set_file_uri(data, uri);
4575 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4576 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4577 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4578 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4580 /* dump parse result */
4581 SECURE_LOGW("incoming uri : %s", uri);
4582 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4583 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4591 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4594 mmplayer_t *player = NULL;
4595 MMMessageParamType msg = {0, };
4597 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4602 LOGE("user_data is null");
4606 player = (mmplayer_t *)user_data;
4608 if (!player->pipeline || !player->attrs) {
4609 LOGW("not initialized");
4613 LOGD("cmd lock player, cmd state : %d", player->cmd);
4614 MMPLAYER_CMD_LOCK(player);
4615 LOGD("cmd locked player");
4617 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4618 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4619 LOGW("player already destroyed");
4620 MMPLAYER_CMD_UNLOCK(player);
4624 player->interrupted_by_resource = TRUE;
4626 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4628 /* get last play position */
4629 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4630 msg.union_type = MM_MSG_UNION_TIME;
4631 msg.time.elapsed = pos;
4632 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4634 LOGW("failed to get play position.");
4637 LOGD("video resource conflict so, resource will be freed by unrealizing");
4638 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4639 LOGE("failed to unrealize");
4641 MMPLAYER_CMD_UNLOCK(player);
4643 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4644 player->hw_resource[res_idx] = NULL;
4648 return TRUE; /* release all the resources */
4652 __mmplayer_initialize_video_roi(mmplayer_t *player)
4654 player->video_roi.scale_x = 0.0;
4655 player->video_roi.scale_y = 0.0;
4656 player->video_roi.scale_width = 1.0;
4657 player->video_roi.scale_height = 1.0;
4661 _mmplayer_create_player(MMHandleType handle)
4663 int ret = MM_ERROR_PLAYER_INTERNAL;
4664 bool enabled = false;
4666 mmplayer_t *player = MM_PLAYER_CAST(handle);
4670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4672 /* initialize player state */
4673 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4674 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4675 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4676 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4678 /* check current state */
4679 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4681 /* construct attributes */
4682 player->attrs = _mmplayer_construct_attribute(handle);
4684 if (!player->attrs) {
4685 LOGE("Failed to construct attributes");
4689 /* initialize gstreamer with configured parameter */
4690 if (!__mmplayer_init_gstreamer(player)) {
4691 LOGE("Initializing gstreamer failed");
4692 _mmplayer_deconstruct_attribute(handle);
4696 /* create lock. note that g_tread_init() has already called in gst_init() */
4697 g_mutex_init(&player->fsink_lock);
4699 /* create update tag lock */
4700 g_mutex_init(&player->update_tag_lock);
4702 /* create gapless play mutex */
4703 g_mutex_init(&player->gapless_play_thread_mutex);
4705 /* create gapless play cond */
4706 g_cond_init(&player->gapless_play_thread_cond);
4708 /* create gapless play thread */
4709 player->gapless_play_thread =
4710 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4711 if (!player->gapless_play_thread) {
4712 LOGE("failed to create gapless play thread");
4713 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4714 g_mutex_clear(&player->gapless_play_thread_mutex);
4715 g_cond_clear(&player->gapless_play_thread_cond);
4719 player->bus_msg_q = g_queue_new();
4720 if (!player->bus_msg_q) {
4721 LOGE("failed to create queue for bus_msg");
4722 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4726 ret = _mmplayer_initialize_video_capture(player);
4727 if (ret != MM_ERROR_NONE) {
4728 LOGW("video capture is not supported");
4729 /* do not handle as error for headless profile */
4732 /* initialize resource manager */
4733 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4734 __resource_release_cb, player, &player->resource_manager)
4735 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4736 LOGE("failed to create resource manager");
4737 ret = MM_ERROR_PLAYER_INTERNAL;
4741 /* create video bo lock and cond */
4742 g_mutex_init(&player->video_bo_mutex);
4743 g_cond_init(&player->video_bo_cond);
4745 /* create subtitle info lock and cond */
4746 g_mutex_init(&player->subtitle_info_mutex);
4747 g_cond_init(&player->subtitle_info_cond);
4749 player->streaming_type = STREAMING_SERVICE_NONE;
4751 /* give default value of audio effect setting */
4752 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4753 player->sound.rg_enable = false;
4754 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4756 player->play_subtitle = FALSE;
4757 player->has_closed_caption = FALSE;
4758 player->pending_resume = FALSE;
4759 if (player->ini.dump_element_keyword[0][0] == '\0')
4760 player->ini.set_dump_element_flag = FALSE;
4762 player->ini.set_dump_element_flag = TRUE;
4764 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4765 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4766 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4768 /* Set video360 settings to their defaults for just-created player.
4771 player->is_360_feature_enabled = FALSE;
4772 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4773 LOGI("spherical feature info: %d", enabled);
4775 player->is_360_feature_enabled = TRUE;
4777 LOGE("failed to get spherical feature info");
4780 player->is_content_spherical = FALSE;
4781 player->is_video360_enabled = TRUE;
4782 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4783 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4784 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4785 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4786 player->video360_zoom = 1.0f;
4787 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4788 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4790 __mmplayer_initialize_video_roi(player);
4792 /* set player state to null */
4793 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4794 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4798 return MM_ERROR_NONE;
4802 g_mutex_clear(&player->fsink_lock);
4803 /* free update tag lock */
4804 g_mutex_clear(&player->update_tag_lock);
4805 g_queue_free(player->bus_msg_q);
4806 player->bus_msg_q = NULL;
4807 /* free gapless play thread */
4808 if (player->gapless_play_thread) {
4809 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4810 player->gapless_play_thread_exit = TRUE;
4811 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4812 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4814 g_thread_join(player->gapless_play_thread);
4815 player->gapless_play_thread = NULL;
4817 g_mutex_clear(&player->gapless_play_thread_mutex);
4818 g_cond_clear(&player->gapless_play_thread_cond);
4821 /* release attributes */
4822 _mmplayer_deconstruct_attribute(handle);
4830 __mmplayer_init_gstreamer(mmplayer_t *player)
4832 static gboolean initialized = FALSE;
4833 static const int max_argc = 50;
4835 gchar **argv = NULL;
4836 gchar **argv2 = NULL;
4842 LOGD("gstreamer already initialized.");
4847 argc = malloc(sizeof(int));
4848 argv = malloc(sizeof(gchar *) * max_argc);
4849 argv2 = malloc(sizeof(gchar *) * max_argc);
4851 if (!argc || !argv || !argv2)
4854 memset(argv, 0, sizeof(gchar *) * max_argc);
4855 memset(argv2, 0, sizeof(gchar *) * max_argc);
4859 argv[0] = g_strdup("mmplayer");
4862 for (i = 0; i < 5; i++) {
4863 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4864 if (strlen(player->ini.gst_param[i]) > 0) {
4865 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4870 /* we would not do fork for scanning plugins */
4871 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4874 /* check disable registry scan */
4875 if (player->ini.skip_rescan) {
4876 argv[*argc] = g_strdup("--gst-disable-registry-update");
4880 /* check disable segtrap */
4881 if (player->ini.disable_segtrap) {
4882 argv[*argc] = g_strdup("--gst-disable-segtrap");
4886 LOGD("initializing gstreamer with following parameter");
4887 LOGD("argc : %d", *argc);
4890 for (i = 0; i < arg_count; i++) {
4892 LOGD("argv[%d] : %s", i, argv2[i]);
4895 /* initializing gstreamer */
4896 if (!gst_init_check(argc, &argv, &err)) {
4897 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4904 for (i = 0; i < arg_count; i++) {
4906 LOGD("release - argv[%d] : %s", i, argv2[i]);
4908 MMPLAYER_FREEIF(argv2[i]);
4911 MMPLAYER_FREEIF(argv);
4912 MMPLAYER_FREEIF(argv2);
4913 MMPLAYER_FREEIF(argc);
4923 for (i = 0; i < arg_count; i++) {
4924 LOGD("free[%d] : %s", i, argv2[i]);
4925 MMPLAYER_FREEIF(argv2[i]);
4928 MMPLAYER_FREEIF(argv);
4929 MMPLAYER_FREEIF(argv2);
4930 MMPLAYER_FREEIF(argc);
4936 __mmplayer_check_async_state_transition(mmplayer_t *player)
4938 GstState element_state = GST_STATE_VOID_PENDING;
4939 GstState element_pending_state = GST_STATE_VOID_PENDING;
4940 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4941 GstElement *element = NULL;
4942 gboolean async = FALSE;
4944 /* check player handle */
4945 MMPLAYER_RETURN_IF_FAIL(player &&
4947 player->pipeline->mainbin &&
4948 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4951 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4953 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4954 LOGD("don't need to check the pipeline state");
4958 MMPLAYER_PRINT_STATE(player);
4960 /* wait for state transition */
4961 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4962 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4964 if (ret == GST_STATE_CHANGE_FAILURE) {
4965 LOGE(" [%s] state : %s pending : %s",
4966 GST_ELEMENT_NAME(element),
4967 gst_element_state_get_name(element_state),
4968 gst_element_state_get_name(element_pending_state));
4970 /* dump state of all element */
4971 _mmplayer_dump_pipeline_state(player);
4976 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4981 _mmplayer_destroy(MMHandleType handle)
4983 mmplayer_t *player = MM_PLAYER_CAST(handle);
4987 /* check player handle */
4988 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4990 /* destroy can called at anytime */
4991 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4993 /* check async state transition */
4994 __mmplayer_check_async_state_transition(player);
4996 /* release gapless play thread */
4997 if (player->gapless_play_thread) {
4998 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4999 player->gapless_play_thread_exit = TRUE;
5000 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5001 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5003 LOGD("waiting for gapless play thread exit");
5004 g_thread_join(player->gapless_play_thread);
5005 g_mutex_clear(&player->gapless_play_thread_mutex);
5006 g_cond_clear(&player->gapless_play_thread_cond);
5007 LOGD("gapless play thread released");
5010 _mmplayer_release_video_capture(player);
5012 /* release miscellaneous information */
5013 __mmplayer_release_misc(player);
5015 /* release pipeline */
5016 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5017 LOGE("failed to destroy pipeline");
5018 return MM_ERROR_PLAYER_INTERNAL;
5021 __mmplayer_destroy_hw_resource(player);
5023 g_queue_free(player->bus_msg_q);
5025 /* release subtitle info lock and cond */
5026 g_mutex_clear(&player->subtitle_info_mutex);
5027 g_cond_clear(&player->subtitle_info_cond);
5029 __mmplayer_release_dump_list(player->dump_list);
5031 /* release miscellaneous information.
5032 these info needs to be released after pipeline is destroyed. */
5033 __mmplayer_release_misc_post(player);
5035 /* release attributes */
5036 _mmplayer_deconstruct_attribute(handle);
5038 if (player->uri_info.uri_list) {
5039 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5040 player->uri_info.uri_list = NULL;
5044 g_mutex_clear(&player->fsink_lock);
5047 g_mutex_clear(&player->update_tag_lock);
5049 /* release video bo lock and cond */
5050 g_mutex_clear(&player->video_bo_mutex);
5051 g_cond_clear(&player->video_bo_cond);
5055 return MM_ERROR_NONE;
5059 _mmplayer_realize(MMHandleType hplayer)
5061 mmplayer_t *player = (mmplayer_t *)hplayer;
5062 int ret = MM_ERROR_NONE;
5065 MMHandleType attrs = 0;
5069 /* check player handle */
5070 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5072 /* check current state */
5073 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5075 attrs = MMPLAYER_GET_ATTRS(player);
5077 LOGE("fail to get attributes.");
5078 return MM_ERROR_PLAYER_INTERNAL;
5080 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5081 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5083 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5084 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5086 if (ret != MM_ERROR_NONE) {
5087 LOGE("failed to parse profile");
5092 if (uri && (strstr(uri, "es_buff://"))) {
5093 if (strstr(uri, "es_buff://push_mode"))
5094 player->es_player_push_mode = TRUE;
5096 player->es_player_push_mode = FALSE;
5099 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5100 LOGW("mms protocol is not supported format.");
5101 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5104 if (MMPLAYER_IS_STREAMING(player))
5105 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5107 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5109 player->smooth_streaming = FALSE;
5110 player->videodec_linked = 0;
5111 player->audiodec_linked = 0;
5112 player->textsink_linked = 0;
5113 player->is_external_subtitle_present = FALSE;
5114 player->is_external_subtitle_added_now = FALSE;
5115 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5116 player->video360_metadata.is_spherical = -1;
5117 player->is_openal_plugin_used = FALSE;
5118 player->subtitle_language_list = NULL;
5119 player->is_subtitle_force_drop = FALSE;
5121 _mmplayer_track_initialize(player);
5122 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5124 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5125 gint prebuffer_ms = 0, rebuffer_ms = 0;
5127 player->streamer = _mm_player_streaming_create();
5128 _mm_player_streaming_initialize(player->streamer, TRUE);
5130 mm_attrs_multiple_get(player->attrs, NULL,
5131 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5132 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5134 if (prebuffer_ms > 0) {
5135 prebuffer_ms = MAX(prebuffer_ms, 1000);
5136 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5139 if (rebuffer_ms > 0) {
5140 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5141 rebuffer_ms = MAX(rebuffer_ms, 1000);
5142 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5145 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5146 player->streamer->buffering_req.rebuffer_time);
5149 /* realize pipeline */
5150 ret = __mmplayer_gst_realize(player);
5151 if (ret != MM_ERROR_NONE)
5152 LOGE("fail to realize the player.");
5154 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5162 _mmplayer_unrealize(MMHandleType hplayer)
5164 mmplayer_t *player = (mmplayer_t *)hplayer;
5165 int ret = MM_ERROR_NONE;
5166 int rm_ret = MM_ERROR_NONE;
5167 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5171 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5173 MMPLAYER_CMD_UNLOCK(player);
5174 _mmplayer_bus_watcher_remove(player);
5175 /* destroy the gst bus msg thread which is created during realize.
5176 this funct have to be called before getting cmd lock. */
5177 _mmplayer_bus_msg_thread_destroy(player);
5178 MMPLAYER_CMD_LOCK(player);
5180 /* check current state */
5181 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5183 /* check async state transition */
5184 __mmplayer_check_async_state_transition(player);
5186 /* unrealize pipeline */
5187 ret = __mmplayer_gst_unrealize(player);
5189 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5190 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5191 if (rm_ret != MM_ERROR_NONE)
5192 LOGE("failed to release [%d] resources", res_idx);
5195 player->interrupted_by_resource = FALSE;
5202 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5204 mmplayer_t *player = (mmplayer_t *)hplayer;
5206 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5208 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5212 _mmplayer_get_state(MMHandleType hplayer, int *state)
5214 mmplayer_t *player = (mmplayer_t *)hplayer;
5216 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5218 *state = MMPLAYER_CURRENT_STATE(player);
5220 return MM_ERROR_NONE;
5224 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5226 GstElement *vol_element = NULL;
5227 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5230 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5231 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5233 /* check pipeline handle */
5234 if (!player->pipeline || !player->pipeline->audiobin) {
5235 LOGD("'%s' will be applied when audiobin is created", prop_name);
5237 /* NOTE : stored value will be used in create_audiobin
5238 * returning MM_ERROR_NONE here makes application to able to
5239 * set audio volume or mute at anytime.
5241 return MM_ERROR_NONE;
5244 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5245 volume_elem_id = MMPLAYER_A_SINK;
5247 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5249 LOGE("failed to get vol element %d", volume_elem_id);
5250 return MM_ERROR_PLAYER_INTERNAL;
5253 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5255 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5256 LOGE("there is no '%s' property", prop_name);
5257 return MM_ERROR_PLAYER_INTERNAL;
5260 if (!strcmp(prop_name, "volume")) {
5261 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5262 } else if (!strcmp(prop_name, "mute")) {
5263 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5265 LOGE("invalid property %s", prop_name);
5266 return MM_ERROR_PLAYER_INTERNAL;
5269 return MM_ERROR_NONE;
5273 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5275 int ret = MM_ERROR_NONE;
5276 mmplayer_t *player = (mmplayer_t *)hplayer;
5279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5281 LOGD("volume = %f", volume);
5283 /* invalid factor range or not */
5284 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5285 LOGE("Invalid volume value");
5286 return MM_ERROR_INVALID_ARGUMENT;
5289 player->sound.volume = volume;
5291 ret = __mmplayer_gst_set_volume_property(player, "volume");
5298 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5300 mmplayer_t *player = (mmplayer_t *)hplayer;
5304 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5305 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5307 *volume = player->sound.volume;
5309 LOGD("current vol = %f", *volume);
5312 return MM_ERROR_NONE;
5316 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5318 int ret = MM_ERROR_NONE;
5319 mmplayer_t *player = (mmplayer_t *)hplayer;
5322 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5324 LOGD("mute = %d", mute);
5326 player->sound.mute = mute;
5328 ret = __mmplayer_gst_set_volume_property(player, "mute");
5335 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5337 mmplayer_t *player = (mmplayer_t *)hplayer;
5341 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5342 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5344 *mute = player->sound.mute;
5346 LOGD("current mute = %d", *mute);
5350 return MM_ERROR_NONE;
5354 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5356 mmplayer_t *player = (mmplayer_t *)hplayer;
5360 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5362 player->audio_stream_changed_cb = callback;
5363 player->audio_stream_changed_cb_user_param = user_param;
5364 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5368 return MM_ERROR_NONE;
5372 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5374 mmplayer_t *player = (mmplayer_t *)hplayer;
5378 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5380 player->audio_decoded_cb = callback;
5381 player->audio_decoded_cb_user_param = user_param;
5382 player->audio_extract_opt = opt;
5383 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5387 return MM_ERROR_NONE;
5391 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5393 mmplayer_t *player = (mmplayer_t *)hplayer;
5397 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5399 if (callback && !player->bufmgr)
5400 player->bufmgr = tbm_bufmgr_init(-1);
5402 player->set_mode.video_export = (callback) ? true : false;
5403 player->video_decoded_cb = callback;
5404 player->video_decoded_cb_user_param = user_param;
5406 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5410 return MM_ERROR_NONE;
5414 _mmplayer_start(MMHandleType hplayer)
5416 mmplayer_t *player = (mmplayer_t *)hplayer;
5417 gint ret = MM_ERROR_NONE;
5421 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5423 /* check current state */
5424 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5426 /* start pipeline */
5427 ret = _mmplayer_gst_start(player);
5428 if (ret != MM_ERROR_NONE)
5429 LOGE("failed to start player.");
5431 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5432 LOGD("force playing start even during buffering");
5433 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5441 /* NOTE: post "not supported codec message" to application
5442 * when one codec is not found during AUTOPLUGGING in MSL.
5443 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5444 * And, if any codec is not found, don't send message here.
5445 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5448 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5450 MMMessageParamType msg_param;
5451 memset(&msg_param, 0, sizeof(MMMessageParamType));
5452 gboolean post_msg_direct = FALSE;
5456 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5458 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5459 player->not_supported_codec, player->can_support_codec);
5461 if (player->not_found_demuxer) {
5462 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5463 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5465 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5466 MMPLAYER_FREEIF(msg_param.data);
5468 return MM_ERROR_NONE;
5471 if (player->not_supported_codec) {
5472 if (player->can_support_codec) {
5473 // There is one codec to play
5474 post_msg_direct = TRUE;
5476 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5477 post_msg_direct = TRUE;
5480 if (post_msg_direct) {
5481 MMMessageParamType msg_param;
5482 memset(&msg_param, 0, sizeof(MMMessageParamType));
5484 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5485 LOGW("not found AUDIO codec, posting error code to application.");
5487 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5488 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5489 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5490 LOGW("not found VIDEO codec, posting error code to application.");
5492 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5493 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5496 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5498 MMPLAYER_FREEIF(msg_param.data);
5500 return MM_ERROR_NONE;
5502 // no any supported codec case
5503 LOGW("not found any codec, posting error code to application.");
5505 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5506 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5507 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5509 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5510 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5513 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5515 MMPLAYER_FREEIF(msg_param.data);
5521 return MM_ERROR_NONE;
5524 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5526 GstState element_state = GST_STATE_VOID_PENDING;
5527 GstState element_pending_state = GST_STATE_VOID_PENDING;
5528 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5529 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5531 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5533 MMPLAYER_RECONFIGURE_LOCK(player);
5534 if (!player->gapless.reconfigure) {
5535 MMPLAYER_RECONFIGURE_UNLOCK(player);
5539 LOGI("reconfigure is under process");
5540 MMPLAYER_RECONFIGURE_WAIT(player);
5541 MMPLAYER_RECONFIGURE_UNLOCK(player);
5542 LOGI("reconfigure is completed.");
5544 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5545 &element_state, &element_pending_state, timeout * GST_SECOND);
5546 if (result == GST_STATE_CHANGE_FAILURE)
5547 LOGW("failed to get pipeline state in %d sec", timeout);
5552 /* NOTE : it should be able to call 'stop' anytime*/
5554 _mmplayer_stop(MMHandleType hplayer)
5556 mmplayer_t *player = (mmplayer_t *)hplayer;
5557 int ret = MM_ERROR_NONE;
5561 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5563 /* check current state */
5564 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5566 /* need to wait till the rebuilding pipeline is completed */
5567 __mmplayer_check_pipeline_reconfigure_state(player);
5568 MMPLAYER_RECONFIGURE_LOCK(player);
5569 __mmplayer_reset_gapless_state(player);
5570 MMPLAYER_RECONFIGURE_UNLOCK(player);
5572 /* NOTE : application should not wait for EOS after calling STOP */
5573 _mmplayer_cancel_eos_timer(player);
5576 player->seek_state = MMPLAYER_SEEK_NONE;
5579 ret = _mmplayer_gst_stop(player);
5581 if (ret != MM_ERROR_NONE)
5582 LOGE("failed to stop player.");
5590 _mmplayer_pause(MMHandleType hplayer)
5592 mmplayer_t *player = (mmplayer_t *)hplayer;
5593 gint64 pos_nsec = 0;
5594 gboolean async = FALSE;
5595 gint ret = MM_ERROR_NONE;
5599 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5601 /* check current state */
5602 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5604 /* check pipeline reconfigure state */
5605 __mmplayer_check_pipeline_reconfigure_state(player);
5607 switch (MMPLAYER_CURRENT_STATE(player)) {
5608 case MM_PLAYER_STATE_READY:
5610 /* check prepare async or not.
5611 * In the case of streaming playback, it's recommended to avoid blocking wait.
5613 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5614 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5616 /* Changing back sync of rtspsrc to async */
5617 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5618 LOGD("async prepare working mode for rtsp");
5624 case MM_PLAYER_STATE_PLAYING:
5626 /* NOTE : store current point to overcome some bad operation
5627 *(returning zero when getting current position in paused state) of some
5630 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5631 LOGW("getting current position failed in paused");
5633 player->last_position = pos_nsec;
5635 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5636 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5637 This causes problem is position calculation during normal pause resume scenarios also.
5638 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5639 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5640 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5641 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5647 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5648 LOGD("doing async pause in case of ms buff src");
5652 /* pause pipeline */
5653 ret = _mmplayer_gst_pause(player, async);
5654 if (ret != MM_ERROR_NONE) {
5655 LOGE("failed to pause player. ret : 0x%x", ret);
5656 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5660 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5661 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5662 LOGE("failed to update display_rotation");
5666 return MM_ERROR_NONE;
5669 /* in case of streaming, pause could take long time.*/
5671 _mmplayer_abort_pause(MMHandleType hplayer)
5673 mmplayer_t *player = (mmplayer_t *)hplayer;
5674 int ret = MM_ERROR_NONE;
5678 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5680 player->pipeline->mainbin,
5681 MM_ERROR_PLAYER_NOT_INITIALIZED);
5683 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5684 LOGD("set the videobin state to READY");
5685 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5686 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5690 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5691 LOGD("set the audiobin state to READY");
5692 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5693 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5697 LOGD("set the pipeline state to READY");
5698 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5699 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5701 if (ret != MM_ERROR_NONE) {
5702 LOGE("fail to change state to READY");
5703 return MM_ERROR_PLAYER_INTERNAL;
5706 LOGD("succeeded in changing state to READY");
5711 _mmplayer_resume(MMHandleType hplayer)
5713 mmplayer_t *player = (mmplayer_t *)hplayer;
5714 int ret = MM_ERROR_NONE;
5715 gboolean async = FALSE;
5719 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5721 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5722 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5723 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5727 /* Changing back sync mode rtspsrc to async */
5728 LOGD("async resume for rtsp case");
5732 /* check current state */
5733 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5735 ret = _mmplayer_gst_resume(player, async);
5736 if (ret != MM_ERROR_NONE)
5737 LOGE("failed to resume player.");
5739 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5740 LOGD("force resume even during buffering");
5741 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5750 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5752 mmplayer_t *player = (mmplayer_t *)hplayer;
5753 gint64 pos_nsec = 0;
5754 int ret = MM_ERROR_NONE;
5756 signed long long start = 0, stop = 0;
5757 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5760 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5761 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5763 /* The sound of video is not supported under 0.0 and over 2.0. */
5764 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5765 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5768 _mmplayer_set_mute(hplayer, mute);
5770 if (player->playback_rate == rate)
5771 return MM_ERROR_NONE;
5773 /* If the position is reached at start potion during fast backward, EOS is posted.
5774 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5776 player->playback_rate = rate;
5778 current_state = MMPLAYER_CURRENT_STATE(player);
5780 if (current_state != MM_PLAYER_STATE_PAUSED)
5781 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5783 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5785 if ((current_state == MM_PLAYER_STATE_PAUSED)
5786 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5787 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5788 pos_nsec = player->last_position;
5793 stop = GST_CLOCK_TIME_NONE;
5795 start = GST_CLOCK_TIME_NONE;
5799 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5800 player->playback_rate,
5802 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5803 GST_SEEK_TYPE_SET, start,
5804 GST_SEEK_TYPE_SET, stop)) {
5805 LOGE("failed to set speed playback");
5806 return MM_ERROR_PLAYER_SEEK;
5809 LOGD("succeeded to set speed playback as %0.1f", rate);
5813 return MM_ERROR_NONE;;
5817 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5819 mmplayer_t *player = (mmplayer_t *)hplayer;
5820 int ret = MM_ERROR_NONE;
5824 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5826 /* check pipeline reconfigure state */
5827 __mmplayer_check_pipeline_reconfigure_state(player);
5829 ret = _mmplayer_gst_set_position(player, position, FALSE);
5837 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5839 mmplayer_t *player = (mmplayer_t *)hplayer;
5840 int ret = MM_ERROR_NONE;
5842 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5843 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5845 if (g_strrstr(player->type, "video/mpegts"))
5846 __mmplayer_update_duration_value(player);
5848 *duration = player->duration;
5853 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5855 mmplayer_t *player = (mmplayer_t *)hplayer;
5856 int ret = MM_ERROR_NONE;
5858 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5860 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5866 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5868 mmplayer_t *player = (mmplayer_t *)hplayer;
5869 int ret = MM_ERROR_NONE;
5873 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5875 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5883 __mmplayer_is_midi_type(gchar *str_caps)
5885 if ((g_strrstr(str_caps, "audio/midi")) ||
5886 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5887 (g_strrstr(str_caps, "application/x-smaf")) ||
5888 (g_strrstr(str_caps, "audio/x-imelody")) ||
5889 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5890 (g_strrstr(str_caps, "audio/xmf")) ||
5891 (g_strrstr(str_caps, "audio/mxmf"))) {
5900 __mmplayer_is_only_mp3_type(gchar *str_caps)
5902 if (g_strrstr(str_caps, "application/x-id3") ||
5903 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5909 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5911 GstStructure *caps_structure = NULL;
5912 gint samplerate = 0;
5916 MMPLAYER_RETURN_IF_FAIL(player && caps);
5918 caps_structure = gst_caps_get_structure(caps, 0);
5920 /* set stream information */
5921 gst_structure_get_int(caps_structure, "rate", &samplerate);
5922 gst_structure_get_int(caps_structure, "channels", &channels);
5924 mm_player_set_attribute((MMHandleType)player, NULL,
5925 "content_audio_samplerate", samplerate,
5926 "content_audio_channels", channels, NULL);
5928 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5932 __mmplayer_update_content_type_info(mmplayer_t *player)
5935 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5937 if (__mmplayer_is_midi_type(player->type)) {
5938 player->bypass_audio_effect = TRUE;
5942 if (!player->streamer) {
5943 LOGD("no need to check streaming type");
5947 if (g_strrstr(player->type, "application/x-hls")) {
5948 /* If it can't know exact type when it parses uri because of redirection case,
5949 * it will be fixed by typefinder or when doing autoplugging.
5951 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5952 player->streamer->is_adaptive_streaming = TRUE;
5953 } else if (g_strrstr(player->type, "application/dash+xml")) {
5954 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5955 player->streamer->is_adaptive_streaming = TRUE;
5958 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5959 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5960 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5962 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5963 if (player->streamer->is_adaptive_streaming)
5964 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5966 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5970 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5975 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5976 GstCaps *caps, gpointer data)
5978 mmplayer_t *player = (mmplayer_t *)data;
5982 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5984 /* store type string */
5985 if (player->type_caps) {
5986 gst_caps_unref(player->type_caps);
5987 player->type_caps = NULL;
5990 player->type_caps = gst_caps_copy(caps);
5991 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5993 MMPLAYER_FREEIF(player->type);
5994 player->type = gst_caps_to_string(caps);
5996 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5997 player, player->type, probability, gst_caps_get_size(caps));
5999 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6000 (g_strrstr(player->type, "audio/x-raw-int"))) {
6001 LOGE("not support media format");
6003 if (player->msg_posted == FALSE) {
6004 MMMessageParamType msg_param;
6005 memset(&msg_param, 0, sizeof(MMMessageParamType));
6007 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6008 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6010 /* don't post more if one was sent already */
6011 player->msg_posted = TRUE;
6016 __mmplayer_update_content_type_info(player);
6018 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6021 pad = gst_element_get_static_pad(tf, "src");
6023 LOGE("fail to get typefind src pad.");
6027 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6028 gboolean async = FALSE;
6029 LOGE("failed to autoplug %s", player->type);
6031 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6033 if (async && player->msg_posted == FALSE)
6034 __mmplayer_handle_missed_plugin(player);
6036 gst_object_unref(GST_OBJECT(pad));
6043 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6045 GstElement *decodebin = NULL;
6049 /* create decodebin */
6050 decodebin = gst_element_factory_make("decodebin", NULL);
6053 LOGE("fail to create decodebin");
6057 /* raw pad handling signal */
6058 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6059 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6061 /* no-more-pad pad handling signal */
6062 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6063 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6065 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6066 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6068 /* This signal is emitted when a pad for which there is no further possible
6069 decoding is added to the decodebin.*/
6070 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6071 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6073 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6074 before looking for any elements that can handle that stream.*/
6075 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6076 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6078 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6079 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6080 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6082 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6083 before looking for any elements that can handle that stream.*/
6084 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6085 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6087 /* This signal is emitted once decodebin has finished decoding all the data.*/
6088 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6089 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6091 /* This signal is emitted when a element is added to the bin.*/
6092 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6093 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6100 __mmplayer_gst_make_queue2(mmplayer_t *player)
6102 GstElement *queue2 = NULL;
6103 gint64 dur_bytes = 0L;
6104 mmplayer_gst_element_t *mainbin = NULL;
6105 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6108 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6110 mainbin = player->pipeline->mainbin;
6112 queue2 = gst_element_factory_make("queue2", "queue2");
6114 LOGE("failed to create buffering queue element");
6118 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6119 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6121 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6123 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6124 * skip the pull mode(file or ring buffering) setting. */
6125 if (dur_bytes > 0) {
6126 if (!g_strrstr(player->type, "video/mpegts")) {
6127 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6128 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6134 _mm_player_streaming_set_queue2(player->streamer,
6138 (guint64)dur_bytes); /* no meaning at the moment */
6144 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6146 mmplayer_gst_element_t *mainbin = NULL;
6147 GstElement *decodebin = NULL;
6148 GstElement *queue2 = NULL;
6149 GstPad *sinkpad = NULL;
6150 GstPad *qsrcpad = NULL;
6153 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6155 mainbin = player->pipeline->mainbin;
6157 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6159 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6160 LOGW("need to check: muxed buffer is not null");
6163 queue2 = __mmplayer_gst_make_queue2(player);
6165 LOGE("failed to make queue2");
6169 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6170 LOGE("failed to add buffering queue");
6174 sinkpad = gst_element_get_static_pad(queue2, "sink");
6175 qsrcpad = gst_element_get_static_pad(queue2, "src");
6177 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6178 LOGE("failed to link [%s:%s]-[%s:%s]",
6179 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6183 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6184 LOGE("failed to sync queue2 state with parent");
6188 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6189 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6193 gst_object_unref(GST_OBJECT(sinkpad));
6197 /* create decodebin */
6198 decodebin = _mmplayer_gst_make_decodebin(player);
6200 LOGE("failed to make decodebin");
6204 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6205 LOGE("failed to add decodebin");
6209 /* to force caps on the decodebin element and avoid reparsing stuff by
6210 * typefind. It also avoids a deadlock in the way typefind activates pads in
6211 * the state change */
6212 g_object_set(decodebin, "sink-caps", caps, NULL);
6214 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6216 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6217 LOGE("failed to link [%s:%s]-[%s:%s]",
6218 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6222 gst_object_unref(GST_OBJECT(sinkpad));
6224 gst_object_unref(GST_OBJECT(qsrcpad));
6227 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6228 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6230 /* set decodebin property about buffer in streaming playback. *
6231 * in case of HLS/DASH, it does not need to have big buffer *
6232 * because it is kind of adaptive streaming. */
6233 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6234 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6235 gint high_percent = 0;
6237 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6238 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6240 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6242 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6244 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6245 "high-percent", high_percent,
6246 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6247 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6248 "max-size-buffers", 0, NULL); // disable or automatic
6251 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6252 LOGE("failed to sync decodebin state with parent");
6263 gst_object_unref(GST_OBJECT(sinkpad));
6266 gst_object_unref(GST_OBJECT(qsrcpad));
6269 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6270 * You need to explicitly set elements to the NULL state before
6271 * dropping the final reference, to allow them to clean up.
6273 gst_element_set_state(queue2, GST_STATE_NULL);
6275 /* And, it still has a parent "player".
6276 * You need to let the parent manage the object instead of unreffing the object directly.
6278 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6279 gst_object_unref(queue2);
6284 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6285 * You need to explicitly set elements to the NULL state before
6286 * dropping the final reference, to allow them to clean up.
6288 gst_element_set_state(decodebin, GST_STATE_NULL);
6290 /* And, it still has a parent "player".
6291 * You need to let the parent manage the object instead of unreffing the object directly.
6294 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6295 gst_object_unref(decodebin);
6303 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6307 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6308 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6310 LOGD("class : %s, mime : %s", factory_class, mime);
6312 /* add missing plugin */
6313 /* NOTE : msl should check missing plugin for image mime type.
6314 * Some motion jpeg clips can have playable audio track.
6315 * So, msl have to play audio after displaying popup written video format not supported.
6317 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6318 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6319 LOGD("not found demuxer");
6320 player->not_found_demuxer = TRUE;
6321 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6327 if (!g_strrstr(factory_class, "Demuxer")) {
6328 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6329 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6330 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6332 /* check that clip have multi tracks or not */
6333 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6334 LOGD("video plugin is already linked");
6336 LOGW("add VIDEO to missing plugin");
6337 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6338 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6340 } else if (g_str_has_prefix(mime, "audio")) {
6341 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6342 LOGD("audio plugin is already linked");
6344 LOGW("add AUDIO to missing plugin");
6345 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6346 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6354 return MM_ERROR_NONE;
6358 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6360 mmplayer_t *player = (mmplayer_t *)data;
6364 MMPLAYER_RETURN_IF_FAIL(player);
6366 /* remove fakesink. */
6367 if (!_mmplayer_gst_remove_fakesink(player,
6368 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6369 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6370 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6371 * source element are not same. To overcome this situation, this function will called
6372 * several places and several times. Therefore, this is not an error case.
6377 LOGD("[handle: %p] pipeline has completely constructed", player);
6379 if ((player->msg_posted == FALSE) &&
6380 (player->cmd >= MMPLAYER_COMMAND_START))
6381 __mmplayer_handle_missed_plugin(player);
6383 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6387 __mmplayer_check_profile(void)
6390 static int profile_tv = -1;
6392 if (__builtin_expect(profile_tv != -1, 1))
6395 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6396 switch (*profileName) {
6411 __mmplayer_get_next_uri(mmplayer_t *player)
6413 mmplayer_parse_profile_t profile;
6415 guint num_of_list = 0;
6418 num_of_list = g_list_length(player->uri_info.uri_list);
6419 uri_idx = player->uri_info.uri_idx;
6421 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6422 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6423 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6425 LOGW("next uri does not exist");
6429 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6430 LOGE("failed to parse profile");
6434 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6435 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6436 LOGW("uri type is not supported(%d)", profile.uri_type);
6440 LOGD("success to find next uri %d", uri_idx);
6444 if (!uri || uri_idx == num_of_list) {
6445 LOGE("failed to find next uri");
6449 player->uri_info.uri_idx = uri_idx;
6450 if (mm_player_set_attribute((MMHandleType)player, NULL,
6451 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6452 LOGE("failed to set attribute");
6456 SECURE_LOGD("next playback uri: %s", uri);
6461 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6463 #define REPEAT_COUNT_INFINITE -1
6464 #define REPEAT_COUNT_MIN 2
6465 #define ORIGINAL_URI_ONLY 1
6467 MMHandleType attrs = 0;
6471 guint num_of_uri = 0;
6472 int profile_tv = -1;
6476 LOGD("checking for gapless play option");
6478 if (player->build_audio_offload) {
6479 LOGE("offload path is not supportable.");
6483 if (player->pipeline->textbin) {
6484 LOGE("subtitle path is enabled. gapless play is not supported.");
6488 attrs = MMPLAYER_GET_ATTRS(player);
6490 LOGE("fail to get attributes.");
6494 mm_attrs_multiple_get(player->attrs, NULL,
6495 "content_video_found", &video,
6496 "profile_play_count", &count,
6497 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6499 /* gapless playback is not supported in case of video at TV profile. */
6500 profile_tv = __mmplayer_check_profile();
6501 if (profile_tv && video) {
6502 LOGW("not support video gapless playback");
6506 /* check repeat count in case of audio */
6508 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6509 LOGW("gapless is disabled");
6513 num_of_uri = g_list_length(player->uri_info.uri_list);
6515 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6517 if (num_of_uri == ORIGINAL_URI_ONLY) {
6518 /* audio looping path */
6519 if (count >= REPEAT_COUNT_MIN) {
6520 /* decrease play count */
6521 /* we succeeded to rewind. update play count and then wait for next EOS */
6523 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6524 } else if (count != REPEAT_COUNT_INFINITE) {
6525 LOGD("there is no next uri and no repeat");
6528 LOGD("looping cnt %d", count);
6530 /* gapless playback path */
6531 if (!__mmplayer_get_next_uri(player)) {
6532 LOGE("failed to get next uri");
6539 LOGE("unable to play gapless path. EOS will be posted soon");
6544 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6546 GstPad *sinkpad = g_value_get_object (item);
6547 GstElement *element = GST_ELEMENT(user_data);
6548 if (!sinkpad || !element) {
6549 LOGE("invalid parameter");
6553 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6554 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6558 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6560 mmplayer_gst_element_t *sinkbin = NULL;
6561 main_element_id_e concatId = MMPLAYER_M_NUM;
6562 main_element_id_e sinkId = MMPLAYER_M_NUM;
6563 gboolean send_notice = FALSE;
6564 GstElement *element;
6568 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6570 LOGD("type %d", type);
6573 case MM_PLAYER_TRACK_TYPE_AUDIO:
6574 concatId = MMPLAYER_M_A_CONCAT;
6575 sinkId = MMPLAYER_A_BIN;
6576 sinkbin = player->pipeline->audiobin;
6578 case MM_PLAYER_TRACK_TYPE_VIDEO:
6579 concatId = MMPLAYER_M_V_CONCAT;
6580 sinkId = MMPLAYER_V_BIN;
6581 sinkbin = player->pipeline->videobin;
6584 case MM_PLAYER_TRACK_TYPE_TEXT:
6585 concatId = MMPLAYER_M_T_CONCAT;
6586 sinkId = MMPLAYER_T_BIN;
6587 sinkbin = player->pipeline->textbin;
6590 LOGE("requested type is not supportable");
6595 element = player->pipeline->mainbin[concatId].gst;
6599 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6600 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6601 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6602 if (srcpad && sinkpad) {
6603 /* after getting drained signal there is no data flows, so no need to do pad_block */
6604 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6605 gst_pad_unlink(srcpad, sinkpad);
6607 /* send custom event to sink pad to handle it at video sink */
6609 LOGD("send custom event to sinkpad");
6610 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6611 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6612 gst_pad_send_event(sinkpad, event);
6615 gst_object_unref(srcpad);
6616 gst_object_unref(sinkpad);
6619 LOGD("release concat request pad");
6620 /* release and unref requests pad from the selector */
6621 iter = gst_element_iterate_sink_pads(element);
6622 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6623 gst_iterator_resync(iter);
6624 gst_iterator_free(iter);
6630 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6632 mmplayer_track_t *selector = &player->track[type];
6633 mmplayer_gst_element_t *sinkbin = NULL;
6634 main_element_id_e selectorId = MMPLAYER_M_NUM;
6635 main_element_id_e sinkId = MMPLAYER_M_NUM;
6636 GstPad *srcpad = NULL;
6637 GstPad *sinkpad = NULL;
6638 gboolean send_notice = FALSE;
6641 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6643 LOGD("type %d", type);
6646 case MM_PLAYER_TRACK_TYPE_AUDIO:
6647 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6648 sinkId = MMPLAYER_A_BIN;
6649 sinkbin = player->pipeline->audiobin;
6651 case MM_PLAYER_TRACK_TYPE_VIDEO:
6652 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6653 sinkId = MMPLAYER_V_BIN;
6654 sinkbin = player->pipeline->videobin;
6657 case MM_PLAYER_TRACK_TYPE_TEXT:
6658 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6659 sinkId = MMPLAYER_T_BIN;
6660 sinkbin = player->pipeline->textbin;
6663 LOGE("requested type is not supportable");
6668 if (player->pipeline->mainbin[selectorId].gst) {
6671 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6673 if (selector->event_probe_id != 0)
6674 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6675 selector->event_probe_id = 0;
6677 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6678 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6680 if (srcpad && sinkpad) {
6681 /* after getting drained signal there is no data flows, so no need to do pad_block */
6682 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6683 gst_pad_unlink(srcpad, sinkpad);
6685 /* send custom event to sink pad to handle it at video sink */
6687 LOGD("send custom event to sinkpad");
6688 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6689 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6690 gst_pad_send_event(sinkpad, event);
6694 gst_object_unref(sinkpad);
6697 gst_object_unref(srcpad);
6700 LOGD("selector release");
6702 /* release and unref requests pad from the selector */
6703 for (n = 0; n < selector->streams->len; n++) {
6704 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6705 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6708 g_ptr_array_set_size(selector->streams, 0);
6710 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6711 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6713 player->pipeline->mainbin[selectorId].gst = NULL;
6721 __mmplayer_deactivate_old_path(mmplayer_t *player)
6724 MMPLAYER_RETURN_IF_FAIL(player);
6726 if (MMPLAYER_USE_DECODEBIN(player)) {
6727 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6728 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6729 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6730 LOGE("deactivate selector error");
6734 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6735 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6736 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6737 LOGE("deactivate concat error");
6742 _mmplayer_track_destroy(player);
6743 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6745 if (player->streamer) {
6746 _mm_player_streaming_initialize(player->streamer, FALSE);
6747 _mm_player_streaming_destroy(player->streamer);
6748 player->streamer = NULL;
6751 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6757 if (!player->msg_posted) {
6758 MMMessageParamType msg = {0,};
6761 msg.code = MM_ERROR_PLAYER_INTERNAL;
6762 LOGE("gapless_uri_play> deactivate error");
6764 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6765 player->msg_posted = TRUE;
6771 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6773 int result = MM_ERROR_NONE;
6774 mmplayer_t *player = (mmplayer_t *)hplayer;
6777 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6778 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6780 if (mm_player_set_attribute(hplayer, NULL,
6781 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6782 LOGE("failed to set attribute");
6783 result = MM_ERROR_PLAYER_INTERNAL;
6785 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6786 LOGE("failed to add the original uri in the uri list.");
6794 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6796 mmplayer_t *player = (mmplayer_t *)hplayer;
6797 guint num_of_list = 0;
6801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6802 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6804 if (player->pipeline && player->pipeline->textbin) {
6805 LOGE("subtitle path is enabled.");
6806 return MM_ERROR_PLAYER_INVALID_STATE;
6809 num_of_list = g_list_length(player->uri_info.uri_list);
6811 if (is_first_path) {
6812 if (num_of_list == 0) {
6813 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6814 SECURE_LOGD("add original path : %s", uri);
6816 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6817 player->uri_info.uri_list = g_list_prepend(
6818 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6819 SECURE_LOGD("change original path : %s", uri);
6822 MMHandleType attrs = 0;
6823 attrs = MMPLAYER_GET_ATTRS(player);
6825 if (num_of_list == 0) {
6826 char *original_uri = NULL;
6829 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6831 if (!original_uri) {
6832 LOGE("there is no original uri.");
6833 return MM_ERROR_PLAYER_INVALID_STATE;
6836 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6837 player->uri_info.uri_idx = 0;
6839 SECURE_LOGD("add original path at first : %s", original_uri);
6843 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6844 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6848 return MM_ERROR_NONE;
6852 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6854 mmplayer_t *player = (mmplayer_t *)hplayer;
6855 char *next_uri = NULL;
6856 guint num_of_list = 0;
6859 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6861 num_of_list = g_list_length(player->uri_info.uri_list);
6863 if (num_of_list > 0) {
6864 gint uri_idx = player->uri_info.uri_idx;
6866 if (uri_idx < num_of_list - 1)
6871 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6872 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6874 *uri = g_strdup(next_uri);
6878 return MM_ERROR_NONE;
6882 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6883 GstCaps *caps, gpointer data)
6885 mmplayer_t *player = (mmplayer_t *)data;
6886 const gchar *klass = NULL;
6887 const gchar *mime = NULL;
6888 gchar *caps_str = NULL;
6890 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6891 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6892 caps_str = gst_caps_to_string(caps);
6894 LOGW("unknown type of caps : %s from %s",
6895 caps_str, GST_ELEMENT_NAME(elem));
6897 MMPLAYER_FREEIF(caps_str);
6899 /* There is no available codec. */
6900 __mmplayer_check_not_supported_codec(player, klass, mime);
6904 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6905 GstCaps *caps, gpointer data)
6907 mmplayer_t *player = (mmplayer_t *)data;
6908 const char *mime = NULL;
6909 gboolean ret = TRUE;
6911 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6912 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6914 if (g_str_has_prefix(mime, "audio")) {
6915 GstStructure *caps_structure = NULL;
6916 gint samplerate = 0;
6918 gchar *caps_str = NULL;
6920 caps_structure = gst_caps_get_structure(caps, 0);
6921 gst_structure_get_int(caps_structure, "rate", &samplerate);
6922 gst_structure_get_int(caps_structure, "channels", &channels);
6924 if ((channels > 0 && samplerate == 0)) {
6925 LOGD("exclude audio...");
6929 caps_str = gst_caps_to_string(caps);
6930 /* set it directly because not sent by TAG */
6931 if (g_strrstr(caps_str, "mobile-xmf"))
6932 mm_player_set_attribute((MMHandleType)player, NULL,
6933 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6935 MMPLAYER_FREEIF(caps_str);
6936 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6937 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
6938 LOGD("video is already linked, allow the stream switch");
6941 LOGD("video is already linked");
6945 LOGD("found new stream");
6952 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6954 gboolean ret = FALSE;
6955 GDBusConnection *conn = NULL;
6957 GVariant *result = NULL;
6958 const gchar *dbus_device_type = NULL;
6959 const gchar *dbus_ret = NULL;
6962 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6964 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6969 result = g_dbus_connection_call_sync(conn,
6970 "org.pulseaudio.Server",
6971 "/org/pulseaudio/StreamManager",
6972 "org.pulseaudio.StreamManager",
6973 "GetCurrentMediaRoutingPath",
6974 g_variant_new("(s)", "out"),
6975 G_VARIANT_TYPE("(ss)"),
6976 G_DBUS_CALL_FLAGS_NONE,
6980 if (!result || err) {
6981 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6986 /* device type is listed in stream-map.json at mmfw-sysconf */
6987 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6989 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6990 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6993 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6994 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6995 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6996 LOGD("audio offload is supportable");
7002 LOGD("audio offload is not supportable");
7005 g_variant_unref(result);
7007 g_object_unref(conn);
7012 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7014 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7015 gint64 position = 0;
7017 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7018 player->pipeline && player->pipeline->mainbin);
7020 MMPLAYER_CMD_LOCK(player);
7021 current_state = MMPLAYER_CURRENT_STATE(player);
7023 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7024 LOGW("getting current position failed in paused");
7026 _mmplayer_unrealize((MMHandleType)player);
7027 _mmplayer_realize((MMHandleType)player);
7029 _mmplayer_set_position((MMHandleType)player, position);
7031 /* async not to be blocked in streaming case */
7032 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7034 _mmplayer_pause((MMHandleType)player);
7036 if (current_state == MM_PLAYER_STATE_PLAYING)
7037 _mmplayer_start((MMHandleType)player);
7038 MMPLAYER_CMD_UNLOCK(player);
7040 LOGD("rebuilding audio pipeline is completed.");
7043 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7045 mmplayer_t *player = (mmplayer_t *)user_data;
7046 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7047 gboolean is_supportable = FALSE;
7049 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7050 LOGW("failed to get device type");
7052 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7054 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7055 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7056 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7057 LOGD("ignore this dev connected info");
7061 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7062 if (player->build_audio_offload == is_supportable) {
7063 LOGD("keep current pipeline without re-building");
7067 /* rebuild pipeline */
7068 LOGD("re-build pipeline - offload: %d", is_supportable);
7069 player->build_audio_offload = FALSE;
7070 __mmplayer_rebuild_audio_pipeline(player);
7076 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7078 unsigned int id = 0;
7080 if (player->audio_device_cb_id != 0) {
7081 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7085 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7086 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7087 LOGD("added device connected cb (%u)", id);
7088 player->audio_device_cb_id = id;
7090 LOGW("failed to add device connected cb");
7097 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7099 mmplayer_t *player = (mmplayer_t *)hplayer;
7102 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7103 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7105 *activated = player->build_audio_offload;
7107 LOGD("offload activated : %d", (int)*activated);
7110 return MM_ERROR_NONE;
7114 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7117 this function need to be updated according to the supported media format
7118 @see player->ini.audio_offload_media_format */
7120 if (__mmplayer_is_only_mp3_type(player->type)) {
7121 LOGD("offload supportable media format type");
7129 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7131 gboolean ret = FALSE;
7132 GstElementFactory *factory = NULL;
7135 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7137 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7138 if (!__mmplayer_is_offload_supported_type(player))
7141 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7142 LOGD("there is no audio offload sink");
7146 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7147 LOGW("there is no audio device type to support offload");
7151 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7153 LOGW("there is no installed audio offload sink element");
7156 gst_object_unref(factory);
7158 if (_mmplayer_acquire_hw_resource(player,
7159 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7160 LOGE("failed to acquire audio offload decoder resource");
7164 if (!__mmplayer_add_audio_device_connected_cb(player))
7167 if (!__mmplayer_is_audio_offload_device_type(player))
7170 LOGD("audio offload can be built");
7175 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7181 static GstAutoplugSelectResult
7182 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7184 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7185 int audio_offload = 0;
7187 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7188 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7190 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7191 LOGD("expose audio path to build offload output path");
7192 player->build_audio_offload = TRUE;
7193 /* update codec info */
7194 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7195 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7196 player->audiodec_linked = 1;
7198 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7202 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7203 And need to consider the multi-track audio content.
7204 There is no HW audio decoder in public. */
7206 /* set stream information */
7207 if (!player->audiodec_linked)
7208 _mmplayer_set_audio_attrs(player, caps);
7210 /* update codec info */
7211 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7212 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7213 player->audiodec_linked = 1;
7215 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7217 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7218 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7220 /* mark video decoder for acquire */
7221 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7222 LOGW("video decoder resource is already acquired, skip it.");
7223 ret = GST_AUTOPLUG_SELECT_SKIP;
7227 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7228 LOGE("failed to acquire video decoder resource");
7229 ret = GST_AUTOPLUG_SELECT_SKIP;
7232 player->interrupted_by_resource = FALSE;
7235 /* update codec info */
7236 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7237 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7238 player->videodec_linked = 1;
7246 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7247 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7249 #define DEFAULT_IDX 0xFFFF
7250 #define MIN_FACTORY_NUM 2
7251 mmplayer_t *player = (mmplayer_t *)data;
7252 GValueArray *new_factories = NULL;
7253 GValue val = { 0, };
7254 GstElementFactory *factory = NULL;
7255 const gchar *klass = NULL;
7256 gchar *factory_name = NULL;
7257 guint hw_dec_idx = DEFAULT_IDX;
7258 guint first_sw_dec_idx = DEFAULT_IDX;
7259 guint last_sw_dec_idx = DEFAULT_IDX;
7260 guint new_pos = DEFAULT_IDX;
7261 guint rm_pos = DEFAULT_IDX;
7262 int audio_codec_type;
7263 int video_codec_type;
7264 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7266 if (factories->n_values < MIN_FACTORY_NUM)
7269 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7270 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7273 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7275 for (int i = 0 ; i < factories->n_values ; i++) {
7276 gchar *hw_dec_info = NULL;
7277 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7279 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7281 LOGW("failed to get factory object");
7284 klass = gst_element_factory_get_klass(factory);
7285 factory_name = GST_OBJECT_NAME(factory);
7288 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7290 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7291 if (!player->need_audio_dec_sorting) {
7292 LOGD("sorting is not required");
7295 codec_type = audio_codec_type;
7296 hw_dec_info = player->ini.audiocodec_element_hw;
7297 sw_dec_info = player->ini.audiocodec_element_sw;
7298 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7299 if (!player->need_video_dec_sorting) {
7300 LOGD("sorting is not required");
7303 codec_type = video_codec_type;
7304 hw_dec_info = player->ini.videocodec_element_hw;
7305 sw_dec_info = player->ini.videocodec_element_sw;
7310 if (g_strrstr(factory_name, hw_dec_info)) {
7313 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7314 if (strstr(factory_name, sw_dec_info[j])) {
7315 last_sw_dec_idx = i;
7316 if (first_sw_dec_idx == DEFAULT_IDX) {
7317 first_sw_dec_idx = i;
7322 if (first_sw_dec_idx == DEFAULT_IDX)
7323 LOGW("unknown codec %s", factory_name);
7327 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7330 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7331 if (hw_dec_idx < first_sw_dec_idx)
7333 new_pos = first_sw_dec_idx;
7334 rm_pos = hw_dec_idx + 1;
7335 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7336 if (last_sw_dec_idx < hw_dec_idx)
7338 new_pos = last_sw_dec_idx + 1;
7339 rm_pos = hw_dec_idx;
7344 /* change position - insert H/W decoder according to the new position */
7345 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7347 LOGW("failed to get factory object");
7350 new_factories = g_value_array_copy(factories);
7351 g_value_init (&val, G_TYPE_OBJECT);
7352 g_value_set_object (&val, factory);
7353 g_value_array_insert(new_factories, new_pos, &val);
7354 g_value_unset (&val);
7355 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7357 for (int i = 0 ; i < new_factories->n_values ; i++) {
7358 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7360 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7361 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7363 LOGE("[Re-arranged] failed to get factory object");
7366 return new_factories;
7370 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7371 GstCaps *caps, GstElementFactory *factory, gpointer data)
7373 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7374 mmplayer_t *player = (mmplayer_t *)data;
7376 gchar *factory_name = NULL;
7377 gchar *caps_str = NULL;
7378 const gchar *klass = NULL;
7381 factory_name = GST_OBJECT_NAME(factory);
7382 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7383 caps_str = gst_caps_to_string(caps);
7385 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7387 /* store type string */
7388 if (player->type == NULL) {
7389 player->type = gst_caps_to_string(caps);
7390 __mmplayer_update_content_type_info(player);
7393 /* filtering exclude keyword */
7394 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7395 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7396 LOGW("skipping [%s] by exclude keyword [%s]",
7397 factory_name, player->ini.exclude_element_keyword[idx]);
7399 result = GST_AUTOPLUG_SELECT_SKIP;
7404 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7405 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7406 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7407 factory_name, player->ini.unsupported_codec_keyword[idx]);
7408 result = GST_AUTOPLUG_SELECT_SKIP;
7413 /* exclude webm format */
7414 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7415 * because webm format is not supportable.
7416 * If webm is disabled in "autoplug-continue", there is no state change
7417 * failure or error because the decodebin will expose the pad directly.
7418 * It make MSL invoke _prepare_async_callback.
7419 * So, we need to disable webm format in "autoplug-select" */
7420 if (caps_str && strstr(caps_str, "webm")) {
7421 LOGW("webm is not supported");
7422 result = GST_AUTOPLUG_SELECT_SKIP;
7426 /* check factory class for filtering */
7427 /* NOTE : msl don't need to use image plugins.
7428 * So, those plugins should be skipped for error handling.
7430 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7431 LOGD("skipping [%s] by not required", factory_name);
7432 result = GST_AUTOPLUG_SELECT_SKIP;
7436 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7437 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7438 // TO CHECK : subtitle if needed, add subparse exception.
7439 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7440 result = GST_AUTOPLUG_SELECT_SKIP;
7444 if (g_strrstr(factory_name, "mpegpsdemux")) {
7445 LOGD("skipping PS container - not support");
7446 result = GST_AUTOPLUG_SELECT_SKIP;
7450 if (g_strrstr(factory_name, "mssdemux"))
7451 player->smooth_streaming = TRUE;
7453 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7454 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7457 GstStructure *str = NULL;
7458 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7460 /* don't make video because of not required */
7461 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7462 (!player->set_mode.video_export)) {
7463 LOGD("no need video decoding, expose pad");
7464 result = GST_AUTOPLUG_SELECT_EXPOSE;
7468 /* get w/h for omx state-tune */
7469 /* FIXME: deprecated? */
7470 str = gst_caps_get_structure(caps, 0);
7471 gst_structure_get_int(str, "width", &width);
7474 if (player->v_stream_caps) {
7475 gst_caps_unref(player->v_stream_caps);
7476 player->v_stream_caps = NULL;
7479 player->v_stream_caps = gst_caps_copy(caps);
7480 LOGD("take caps for video state tune");
7481 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7485 if (g_strrstr(klass, "Codec/Decoder")) {
7486 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7487 if (result != GST_AUTOPLUG_SELECT_TRY) {
7488 LOGW("skip add decoder");
7494 MMPLAYER_FREEIF(caps_str);
7500 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7503 int ret = MM_ERROR_NONE;
7504 mmplayer_t *player = (mmplayer_t *)data;
7505 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7506 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7507 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7510 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7512 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7514 if (MMPLAYER_USE_DECODEBIN(player))
7517 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7520 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7522 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst, GST_STATE_NULL, FALSE, timeout);
7523 if (ret != MM_ERROR_NONE) {
7524 LOGE("fail to change state to NULL");
7528 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL, FALSE, timeout);
7529 if (ret != MM_ERROR_NONE) {
7530 LOGE("fail to change state to NULL");
7534 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7535 LOGE("failed to remove video concat");
7538 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7539 LOGE("failed to remove videobin");
7542 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7543 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7544 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7546 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7547 MMPLAYER_FREEIF(player->pipeline->videobin);
7549 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7550 if (ret != MM_ERROR_NONE)
7551 LOGE("failed to release overlay resources");
7553 player->videodec_linked = 0;
7555 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7560 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7562 mmplayer_t *player = (mmplayer_t *)data;
7565 MMPLAYER_RETURN_IF_FAIL(player);
7567 LOGD("got about to finish signal");
7569 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7570 LOGW("Fail to get cmd lock");
7574 if (!__mmplayer_verify_gapless_play_path(player)) {
7575 LOGD("decoding is finished.");
7576 MMPLAYER_CMD_UNLOCK(player);
7580 _mmplayer_set_reconfigure_state(player, TRUE);
7581 MMPLAYER_CMD_UNLOCK(player);
7583 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7584 __mmplayer_deactivate_old_path(player);
7590 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7592 mmplayer_t *player = (mmplayer_t *)data;
7593 GstIterator *iter = NULL;
7594 GValue item = { 0, };
7596 gboolean done = FALSE;
7597 gboolean is_all_drained = TRUE;
7600 MMPLAYER_RETURN_IF_FAIL(player);
7602 LOGD("got drained signal");
7604 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7605 LOGW("Fail to get cmd lock");
7609 if (!__mmplayer_verify_gapless_play_path(player)) {
7610 LOGD("decoding is finished.");
7611 MMPLAYER_CMD_UNLOCK(player);
7615 _mmplayer_set_reconfigure_state(player, TRUE);
7616 MMPLAYER_CMD_UNLOCK(player);
7618 /* check decodebin src pads whether they received EOS or not */
7619 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7622 switch (gst_iterator_next(iter, &item)) {
7623 case GST_ITERATOR_OK:
7624 pad = g_value_get_object(&item);
7625 if (pad && !GST_PAD_IS_EOS(pad)) {
7626 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7627 is_all_drained = FALSE;
7630 g_value_reset(&item);
7632 case GST_ITERATOR_RESYNC:
7633 gst_iterator_resync(iter);
7635 case GST_ITERATOR_ERROR:
7636 case GST_ITERATOR_DONE:
7641 g_value_unset(&item);
7642 gst_iterator_free(iter);
7644 if (!is_all_drained) {
7645 LOGD("Wait util the all pads get EOS.");
7650 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7651 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7653 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7654 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7655 __mmplayer_deactivate_old_path(player);
7661 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7663 mmplayer_t *player = (mmplayer_t *)data;
7664 const gchar *klass = NULL;
7665 gchar *factory_name = NULL;
7667 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7668 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7670 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7672 if (__mmplayer_add_dump_buffer_probe(player, element))
7673 LOGD("add buffer probe");
7675 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7676 gchar *selected = NULL;
7677 selected = g_strdup(GST_ELEMENT_NAME(element));
7678 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7680 /* update codec info */
7681 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7682 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7683 player->audiodec_linked = 1;
7684 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7685 /* update codec info */
7686 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7687 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7688 player->videodec_linked = 1;
7691 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7692 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7693 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7695 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7696 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7698 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7699 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7700 "max-video-width", player->adaptive_info.limit.width,
7701 "max-video-height", player->adaptive_info.limit.height, NULL);
7703 } else if (g_strrstr(klass, "Demuxer")) {
7705 LOGD("plugged element is demuxer. take it");
7707 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7708 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7709 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7710 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7711 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7714 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7715 int surface_type = 0;
7717 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7720 // to support trust-zone only
7721 if (g_strrstr(factory_name, "asfdemux")) {
7722 LOGD("set file-location %s", player->profile.uri);
7723 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7724 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7725 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7726 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7727 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7728 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7729 (__mmplayer_is_only_mp3_type(player->type))) {
7730 LOGD("[mpegaudioparse] set streaming pull mode.");
7731 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7733 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7734 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7735 } else if (g_strrstr(factory_name, "omxdec_h264")) {
7736 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7737 if (video_parse && (g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7738 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7739 LOGD("Send SPS and PPS Insertion every IDR frame");
7743 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7744 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7745 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7747 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7748 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7750 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7751 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7752 (MMPLAYER_IS_DASH_STREAMING(player))) {
7753 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7754 _mm_player_streaming_set_multiqueue(player->streamer, element);
7755 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7764 __mmplayer_release_misc(mmplayer_t *player)
7767 bool cur_mode = player->set_mode.rich_audio;
7770 MMPLAYER_RETURN_IF_FAIL(player);
7772 player->sent_bos = FALSE;
7773 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7775 player->seek_state = MMPLAYER_SEEK_NONE;
7777 player->total_bitrate = 0;
7778 player->total_maximum_bitrate = 0;
7780 player->not_found_demuxer = 0;
7782 player->last_position = 0;
7783 player->duration = 0;
7784 player->http_content_size = 0;
7785 player->not_supported_codec = MISSING_PLUGIN_NONE;
7786 player->can_support_codec = FOUND_PLUGIN_NONE;
7787 player->pending_seek.is_pending = false;
7788 player->pending_seek.pos = 0;
7789 player->msg_posted = FALSE;
7790 player->has_many_types = FALSE;
7791 player->is_subtitle_force_drop = FALSE;
7792 player->play_subtitle = FALSE;
7793 player->adjust_subtitle_pos = 0;
7794 player->has_closed_caption = FALSE;
7795 player->set_mode.video_export = false;
7796 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7797 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7799 player->set_mode.rich_audio = cur_mode;
7801 if (player->audio_device_cb_id > 0 &&
7802 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7803 LOGW("failed to remove audio device_connected_callback");
7804 player->audio_device_cb_id = 0;
7806 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7807 player->bitrate[i] = 0;
7808 player->maximum_bitrate[i] = 0;
7811 /* free memory related to audio effect */
7812 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7814 if (player->adaptive_info.var_list) {
7815 g_list_free_full(player->adaptive_info.var_list, g_free);
7816 player->adaptive_info.var_list = NULL;
7819 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7820 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7821 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7823 /* Reset video360 settings to their defaults in case if the pipeline is to be
7826 player->video360_metadata.is_spherical = -1;
7827 player->is_openal_plugin_used = FALSE;
7829 player->is_content_spherical = FALSE;
7830 player->is_video360_enabled = TRUE;
7831 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7832 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7833 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7834 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7835 player->video360_zoom = 1.0f;
7836 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7837 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7839 player->sound.rg_enable = false;
7841 __mmplayer_initialize_video_roi(player);
7846 __mmplayer_release_misc_post(mmplayer_t *player)
7848 gchar *original_uri = NULL;
7851 /* player->pipeline is already released before. */
7852 MMPLAYER_RETURN_IF_FAIL(player);
7854 player->video_decoded_cb = NULL;
7855 player->video_decoded_cb_user_param = NULL;
7856 player->video_stream_prerolled = false;
7858 player->audio_decoded_cb = NULL;
7859 player->audio_decoded_cb_user_param = NULL;
7860 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7862 player->audio_stream_changed_cb = NULL;
7863 player->audio_stream_changed_cb_user_param = NULL;
7865 mm_player_set_attribute((MMHandleType)player, NULL,
7866 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7868 /* clean found audio decoders */
7869 if (player->audio_decoders) {
7870 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7871 player->audio_decoders = NULL;
7874 /* clean the uri list except original uri */
7875 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7877 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7878 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7879 g_list_free_full(tmp, (GDestroyNotify)g_free);
7882 LOGW("failed to get original uri info");
7884 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7885 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7886 MMPLAYER_FREEIF(original_uri);
7889 /* clear the audio stream buffer list */
7890 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7892 /* clear the video stream bo list */
7893 __mmplayer_video_stream_destroy_bo_list(player);
7894 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7896 if (player->profile.input_mem.buf) {
7897 free(player->profile.input_mem.buf);
7898 player->profile.input_mem.buf = NULL;
7900 player->profile.input_mem.len = 0;
7901 player->profile.input_mem.offset = 0;
7903 player->uri_info.uri_idx = 0;
7908 __mmplayer_check_subtitle(mmplayer_t *player)
7910 MMHandleType attrs = 0;
7911 char *subtitle_uri = NULL;
7915 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7917 /* get subtitle attribute */
7918 attrs = MMPLAYER_GET_ATTRS(player);
7922 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7923 if (!subtitle_uri || !strlen(subtitle_uri))
7926 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7927 player->is_external_subtitle_present = TRUE;
7935 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7937 MMPLAYER_RETURN_IF_FAIL(player);
7939 if (player->eos_timer) {
7940 LOGD("cancel eos timer");
7941 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7942 player->eos_timer = 0;
7949 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7953 MMPLAYER_RETURN_IF_FAIL(player);
7954 MMPLAYER_RETURN_IF_FAIL(sink);
7957 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7959 player->sink_elements = g_list_append(player->sink_elements, sink);
7965 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7969 MMPLAYER_RETURN_IF_FAIL(player);
7970 MMPLAYER_RETURN_IF_FAIL(sink);
7972 player->sink_elements = g_list_remove(player->sink_elements, sink);
7978 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7979 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7981 mmplayer_signal_item_t *item = NULL;
7984 MMPLAYER_RETURN_IF_FAIL(player);
7986 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7987 LOGE("invalid signal type [%d]", type);
7991 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7993 LOGE("cannot connect signal [%s]", signal);
7998 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7999 player->signals[type] = g_list_append(player->signals[type], item);
8005 /* NOTE : be careful with calling this api. please refer to below glib comment
8006 * glib comment : Note that there is a bug in GObject that makes this function much
8007 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8008 * will no longer be called, but, the signal handler is not currently disconnected.
8009 * If the instance is itself being freed at the same time than this doesn't matter,
8010 * since the signal will automatically be removed, but if instance persists,
8011 * then the signal handler will leak. You should not remove the signal yourself
8012 * because in a future versions of GObject, the handler will automatically be
8015 * It's possible to work around this problem in a way that will continue to work
8016 * with future versions of GObject by checking that the signal handler is still
8017 * connected before disconnected it:
8019 * if (g_signal_handler_is_connected(instance, id))
8020 * g_signal_handler_disconnect(instance, id);
8023 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8025 GList *sig_list = NULL;
8026 mmplayer_signal_item_t *item = NULL;
8030 MMPLAYER_RETURN_IF_FAIL(player);
8032 LOGD("release signals type : %d", type);
8034 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8035 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8036 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8037 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8038 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8039 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8043 sig_list = player->signals[type];
8045 for (; sig_list; sig_list = sig_list->next) {
8046 item = sig_list->data;
8048 if (item && item->obj) {
8049 if (g_signal_handler_is_connected(item->obj, item->sig))
8050 g_signal_handler_disconnect(item->obj, item->sig);
8053 MMPLAYER_FREEIF(item);
8056 g_list_free(player->signals[type]);
8057 player->signals[type] = NULL;
8065 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8067 mmplayer_t *player = 0;
8068 int prev_display_surface_type = 0;
8072 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8074 player = MM_PLAYER_CAST(handle);
8076 /* check video sinkbin is created */
8077 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8078 LOGW("Videosink is already created");
8079 return MM_ERROR_NONE;
8082 LOGD("videosink element is not yet ready");
8084 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8085 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8087 return MM_ERROR_INVALID_ARGUMENT;
8090 /* load previous attributes */
8091 if (player->attrs) {
8092 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8093 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8094 if (prev_display_surface_type == surface_type) {
8095 LOGD("incoming display surface type is same as previous one, do nothing..");
8097 return MM_ERROR_NONE;
8100 LOGE("failed to load attributes");
8102 return MM_ERROR_PLAYER_INTERNAL;
8105 /* videobin is not created yet, so we just set attributes related to display surface */
8106 LOGD("store display attribute for given surface type(%d)", surface_type);
8107 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8108 "display_overlay", wl_surface_id, NULL);
8111 return MM_ERROR_NONE;
8114 /* Note : if silent is true, then subtitle would not be displayed. :*/
8116 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8118 mmplayer_t *player = (mmplayer_t *)hplayer;
8122 /* check player handle */
8123 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8125 player->set_mode.subtitle_off = silent;
8127 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8131 return MM_ERROR_NONE;
8135 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8137 mmplayer_gst_element_t *mainbin = NULL;
8138 mmplayer_gst_element_t *textbin = NULL;
8139 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8140 GstState current_state = GST_STATE_VOID_PENDING;
8141 GstState element_state = GST_STATE_VOID_PENDING;
8142 GstState element_pending_state = GST_STATE_VOID_PENDING;
8144 GstEvent *event = NULL;
8145 int result = MM_ERROR_NONE;
8147 GstClock *curr_clock = NULL;
8148 GstClockTime base_time, start_time, curr_time;
8153 /* check player handle */
8154 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8156 player->pipeline->mainbin &&
8157 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8159 mainbin = player->pipeline->mainbin;
8160 textbin = player->pipeline->textbin;
8162 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8164 // sync clock with current pipeline
8165 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8166 curr_time = gst_clock_get_time(curr_clock);
8168 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8169 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8171 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8172 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8174 if (current_state > GST_STATE_READY) {
8175 // sync state with current pipeline
8176 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8177 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8178 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8180 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8181 if (GST_STATE_CHANGE_FAILURE == ret) {
8182 LOGE("fail to state change.");
8183 result = MM_ERROR_PLAYER_INTERNAL;
8187 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8188 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8191 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8192 gst_object_unref(curr_clock);
8195 // seek to current position
8196 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8197 result = MM_ERROR_PLAYER_INVALID_STATE;
8198 LOGE("gst_element_query_position failed, invalid state");
8202 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8203 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);
8205 _mmplayer_gst_send_event_to_sink(player, event);
8207 result = MM_ERROR_PLAYER_INTERNAL;
8208 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8212 /* sync state with current pipeline */
8213 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8214 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8215 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8217 return MM_ERROR_NONE;
8220 /* release text pipeline resource */
8221 player->textsink_linked = 0;
8223 /* release signal */
8224 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8226 /* release textbin with it's children */
8227 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8228 MMPLAYER_FREEIF(player->pipeline->textbin);
8229 player->pipeline->textbin = NULL;
8231 /* release subtitle elem */
8232 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8233 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8239 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8241 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8242 GstState current_state = GST_STATE_VOID_PENDING;
8244 MMHandleType attrs = 0;
8245 mmplayer_gst_element_t *mainbin = NULL;
8246 mmplayer_gst_element_t *textbin = NULL;
8248 gchar *subtitle_uri = NULL;
8249 int result = MM_ERROR_NONE;
8250 const gchar *charset = NULL;
8254 /* check player handle */
8255 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8257 player->pipeline->mainbin &&
8258 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8259 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8261 mainbin = player->pipeline->mainbin;
8262 textbin = player->pipeline->textbin;
8264 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8265 if (current_state < GST_STATE_READY) {
8266 result = MM_ERROR_PLAYER_INVALID_STATE;
8267 LOGE("Pipeline is not in proper state");
8271 attrs = MMPLAYER_GET_ATTRS(player);
8273 LOGE("cannot get content attribute");
8274 result = MM_ERROR_PLAYER_INTERNAL;
8278 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8279 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8280 LOGE("subtitle uri is not proper filepath");
8281 result = MM_ERROR_PLAYER_INVALID_URI;
8285 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8286 LOGE("failed to get storage info of subtitle path");
8287 result = MM_ERROR_PLAYER_INVALID_URI;
8291 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8292 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8294 if (!strcmp(filepath, subtitle_uri)) {
8295 LOGD("subtitle path is not changed");
8298 if (mm_player_set_attribute((MMHandleType)player, NULL,
8299 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8300 LOGE("failed to set attribute");
8305 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8306 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8307 player->subtitle_language_list = NULL;
8308 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8310 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8311 if (ret != GST_STATE_CHANGE_SUCCESS) {
8312 LOGE("failed to change state of textbin to READY");
8313 result = MM_ERROR_PLAYER_INTERNAL;
8317 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8318 if (ret != GST_STATE_CHANGE_SUCCESS) {
8319 LOGE("failed to change state of subparse to READY");
8320 result = MM_ERROR_PLAYER_INTERNAL;
8324 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8325 if (ret != GST_STATE_CHANGE_SUCCESS) {
8326 LOGE("failed to change state of filesrc to READY");
8327 result = MM_ERROR_PLAYER_INTERNAL;
8331 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8333 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8335 charset = _mmplayer_get_charset(filepath);
8337 LOGD("detected charset is %s", charset);
8338 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8341 result = _mmplayer_sync_subtitle_pipeline(player);
8348 /* API to switch between external subtitles */
8350 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8352 int result = MM_ERROR_NONE;
8353 mmplayer_t *player = (mmplayer_t *)hplayer;
8358 /* check player handle */
8359 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8361 /* filepath can be null in idle state */
8363 /* check file path */
8364 if ((path = strstr(filepath, "file://")))
8365 result = _mmplayer_exist_file_path(path + 7);
8367 result = _mmplayer_exist_file_path(filepath);
8369 if (result != MM_ERROR_NONE) {
8370 LOGE("invalid subtitle path 0x%X", result);
8371 return result; /* file not found or permission denied */
8375 if (!player->pipeline) {
8377 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8378 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8379 LOGE("failed to set attribute");
8380 return MM_ERROR_PLAYER_INTERNAL;
8383 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8384 /* check filepath */
8385 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8387 if (!__mmplayer_check_subtitle(player)) {
8388 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8389 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8390 LOGE("failed to set attribute");
8391 return MM_ERROR_PLAYER_INTERNAL;
8394 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8395 LOGE("fail to create text pipeline");
8396 return MM_ERROR_PLAYER_INTERNAL;
8399 result = _mmplayer_sync_subtitle_pipeline(player);
8401 result = __mmplayer_change_external_subtitle_language(player, filepath);
8404 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8405 player->is_external_subtitle_added_now = TRUE;
8407 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8408 if (!player->subtitle_language_list) {
8409 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8410 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8411 LOGW("subtitle language list is not updated yet");
8413 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8421 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8423 guint active_idx = 0;
8424 GstStream *stream = NULL;
8425 GList *streams = NULL;
8426 GstCaps *caps = NULL;
8429 LOGD("Switching Streams... type: %d, index: %d", type, index);
8431 player->track[type].active_track_index = index;
8433 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8434 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8435 LOGD("track type:%d, total: %d, active: %d", i,
8436 player->track[i].total_track_num, player->track[i].active_track_index);
8437 if (player->track[i].total_track_num > 0 &&
8438 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8439 active_idx = player->track[i].active_track_index;
8440 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8441 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8442 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8444 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8445 caps = gst_stream_get_caps(stream);
8447 _mmplayer_set_audio_attrs(player, caps);
8448 gst_caps_unref(caps);
8455 LOGD("send select stream event");
8456 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8457 gst_event_new_select_streams(streams));
8458 g_list_free(streams);
8462 return MM_ERROR_NONE;
8466 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8468 int result = MM_ERROR_NONE;
8469 gchar *change_pad_name = NULL;
8470 GstPad *sinkpad = NULL;
8471 mmplayer_gst_element_t *mainbin = NULL;
8472 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8473 GstCaps *caps = NULL;
8474 gint total_track_num = 0;
8478 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8479 MM_ERROR_PLAYER_NOT_INITIALIZED);
8481 LOGD("Change Track(%d) to %d", type, index);
8483 mainbin = player->pipeline->mainbin;
8485 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8486 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8487 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8488 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8490 /* Changing Video Track is not supported. */
8491 LOGE("Track Type Error");
8495 if (mainbin[elem_idx].gst == NULL) {
8496 result = MM_ERROR_PLAYER_NO_OP;
8497 LOGD("Req track doesn't exist");
8501 total_track_num = player->track[type].total_track_num;
8502 if (total_track_num <= 0) {
8503 result = MM_ERROR_PLAYER_NO_OP;
8504 LOGD("Language list is not available");
8508 if ((index < 0) || (index >= total_track_num)) {
8509 result = MM_ERROR_INVALID_ARGUMENT;
8510 LOGD("Not a proper index : %d", index);
8514 /*To get the new pad from the selector*/
8515 change_pad_name = g_strdup_printf("sink_%u", index);
8516 if (change_pad_name == NULL) {
8517 result = MM_ERROR_PLAYER_INTERNAL;
8518 LOGD("Pad does not exists");
8522 LOGD("new active pad name: %s", change_pad_name);
8524 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8525 if (sinkpad == NULL) {
8526 LOGD("sinkpad is NULL");
8527 result = MM_ERROR_PLAYER_INTERNAL;
8531 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8532 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8534 caps = gst_pad_get_current_caps(sinkpad);
8535 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8538 gst_object_unref(sinkpad);
8540 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8541 _mmplayer_set_audio_attrs(player, caps);
8544 gst_caps_unref(caps);
8547 MMPLAYER_FREEIF(change_pad_name);
8552 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8554 int result = MM_ERROR_NONE;
8555 mmplayer_t *player = NULL;
8556 mmplayer_gst_element_t *mainbin = NULL;
8558 gint current_active_index = 0;
8560 GstState current_state = GST_STATE_VOID_PENDING;
8565 player = (mmplayer_t *)hplayer;
8566 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8568 if (!player->pipeline) {
8569 LOGE("Track %d pre setting -> %d", type, index);
8571 player->track[type].active_track_index = index;
8575 mainbin = player->pipeline->mainbin;
8577 current_active_index = player->track[type].active_track_index;
8579 /*If index is same as running index no need to change the pad*/
8580 if (current_active_index == index)
8583 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8584 result = MM_ERROR_PLAYER_INVALID_STATE;
8588 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8589 if (current_state < GST_STATE_PAUSED) {
8590 result = MM_ERROR_PLAYER_INVALID_STATE;
8591 LOGW("Pipeline not in proper state");
8595 if (MMPLAYER_USE_DECODEBIN(player))
8596 result = __mmplayer_change_selector_pad(player, type, index);
8598 result = __mmplayer_switch_stream(player, type, index);
8600 if (result != MM_ERROR_NONE) {
8601 LOGE("failed to change track");
8605 player->track[type].active_track_index = index;
8607 if (MMPLAYER_USE_DECODEBIN(player)) {
8608 GstEvent *event = NULL;
8609 if (current_state == GST_STATE_PLAYING) {
8610 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8611 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8612 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8614 _mmplayer_gst_send_event_to_sink(player, event);
8616 result = MM_ERROR_PLAYER_INTERNAL;
8627 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8629 mmplayer_t *player = (mmplayer_t *)hplayer;
8633 /* check player handle */
8634 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8636 *silent = player->set_mode.subtitle_off;
8638 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8642 return MM_ERROR_NONE;
8646 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8648 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8649 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8651 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8652 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8656 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8657 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8658 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8659 mmplayer_dump_t *dump_s;
8660 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8661 if (dump_s == NULL) {
8662 LOGE("malloc fail");
8666 dump_s->dump_element_file = NULL;
8667 dump_s->dump_pad = NULL;
8668 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8670 if (dump_s->dump_pad) {
8671 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8672 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]);
8673 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8674 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);
8675 /* add list for removed buffer probe and close FILE */
8676 player->dump_list = g_list_append(player->dump_list, dump_s);
8677 LOGD("%s sink pad added buffer probe for dump", factory_name);
8680 MMPLAYER_FREEIF(dump_s);
8681 LOGE("failed to get %s sink pad added", factory_name);
8688 static GstPadProbeReturn
8689 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8691 FILE *dump_data = (FILE *)u_data;
8693 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8694 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8696 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8698 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8700 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8702 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8704 gst_buffer_unmap(buffer, &probe_info);
8706 return GST_PAD_PROBE_OK;
8710 __mmplayer_release_dump_list(GList *dump_list)
8712 GList *d_list = dump_list;
8717 for (; d_list; d_list = g_list_next(d_list)) {
8718 mmplayer_dump_t *dump_s = d_list->data;
8719 if (dump_s->dump_pad) {
8720 if (dump_s->probe_handle_id)
8721 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8722 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8724 if (dump_s->dump_element_file) {
8725 fclose(dump_s->dump_element_file);
8726 dump_s->dump_element_file = NULL;
8728 MMPLAYER_FREEIF(dump_s);
8730 g_list_free(dump_list);
8735 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8737 mmplayer_t *player = (mmplayer_t *)hplayer;
8741 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8742 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8744 *exist = (bool)player->has_closed_caption;
8748 return MM_ERROR_NONE;
8752 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8757 LOGD("unref internal gst buffer %p", buffer);
8759 gst_buffer_unref((GstBuffer *)buffer);
8766 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8768 mmplayer_t *player = (mmplayer_t *)hplayer;
8772 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8773 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8775 if (MMPLAYER_IS_STREAMING(player))
8776 *timeout = (int)player->ini.live_state_change_timeout;
8778 *timeout = (int)player->ini.localplayback_state_change_timeout;
8780 LOGD("timeout = %d", *timeout);
8783 return MM_ERROR_NONE;
8787 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8791 MMPLAYER_RETURN_IF_FAIL(player);
8793 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8795 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8796 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8797 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8798 player->storage_info[i].id = -1;
8799 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8801 if (path_type != MMPLAYER_PATH_MAX)
8810 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8812 int ret = MM_ERROR_NONE;
8813 mmplayer_t *player = (mmplayer_t *)hplayer;
8814 MMMessageParamType msg_param = {0, };
8817 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8819 LOGW("state changed storage %d:%d", id, state);
8821 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8822 return MM_ERROR_NONE;
8824 /* FIXME: text path should be handled separately. */
8825 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8826 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8827 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8828 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8829 LOGW("external storage is removed");
8831 if (player->msg_posted == FALSE) {
8832 memset(&msg_param, 0, sizeof(MMMessageParamType));
8833 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8834 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8835 player->msg_posted = TRUE;
8838 /* unrealize the player */
8839 ret = _mmplayer_unrealize(hplayer);
8840 if (ret != MM_ERROR_NONE)
8841 LOGE("failed to unrealize");
8849 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8851 int ret = MM_ERROR_NONE;
8852 mmplayer_t *player = (mmplayer_t *)hplayer;
8853 int idx = 0, total = 0;
8854 gchar *result = NULL, *tmp = NULL;
8857 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8858 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8860 total = *num = g_list_length(player->adaptive_info.var_list);
8862 LOGW("There is no stream variant info.");
8866 result = g_strdup("");
8867 for (idx = 0 ; idx < total ; idx++) {
8868 stream_variant_t *v_data = NULL;
8869 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8872 gchar data[64] = {0};
8873 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8875 tmp = g_strconcat(result, data, NULL);
8879 LOGW("There is no variant data in %d", idx);
8884 *var_info = (char *)result;
8886 LOGD("variant info %d:%s", *num, *var_info);
8892 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8894 int ret = MM_ERROR_NONE;
8895 mmplayer_t *player = (mmplayer_t *)hplayer;
8898 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8900 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8902 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8903 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8904 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8906 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8907 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8908 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8909 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8911 /* FIXME: seek to current position for applying new variant limitation */
8920 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8922 int ret = MM_ERROR_NONE;
8923 mmplayer_t *player = (mmplayer_t *)hplayer;
8926 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8927 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8929 *bandwidth = player->adaptive_info.limit.bandwidth;
8930 *width = player->adaptive_info.limit.width;
8931 *height = player->adaptive_info.limit.height;
8933 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8940 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8942 int ret = MM_ERROR_NONE;
8943 mmplayer_t *player = (mmplayer_t *)hplayer;
8946 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8947 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8948 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8950 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8952 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8953 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8954 else /* live case */
8955 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8957 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8964 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8966 #define IDX_FIRST_SW_CODEC 0
8967 mmplayer_t *player = (mmplayer_t *)hplayer;
8968 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8969 const char *attr_name = NULL;
8970 const char *default_type = NULL;
8971 const char *element_hw = NULL;
8972 const char *element_sw = NULL;
8975 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8977 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8979 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8980 switch (stream_type) {
8981 case MM_PLAYER_STREAM_TYPE_AUDIO:
8982 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8983 default_type = player->ini.audiocodec_default_type;
8984 element_hw = player->ini.audiocodec_element_hw;
8985 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8987 case MM_PLAYER_STREAM_TYPE_VIDEO:
8988 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8989 default_type = player->ini.videocodec_default_type;
8990 element_hw = player->ini.videocodec_element_hw;
8991 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8994 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8995 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8999 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9001 if (!strcmp(default_type, "sw"))
9002 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9004 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9006 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9007 codec_type = default_codec_type;
9009 /* to support codec selection, codec info have to be added in ini file.
9010 in case of hw codec is selected, filter elements should be applied
9011 depending on the hw capabilities. */
9012 if (codec_type != default_codec_type) {
9013 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9014 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9015 LOGE("There is no codec for type %d", codec_type);
9016 return MM_ERROR_PLAYER_NO_OP;
9019 LOGD("sorting is required");
9020 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9021 player->need_audio_dec_sorting = TRUE;
9023 player->need_video_dec_sorting = TRUE;
9026 LOGD("update %s codec_type to %d", attr_name, codec_type);
9027 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9030 return MM_ERROR_NONE;
9034 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9036 mmplayer_t *player = (mmplayer_t *)hplayer;
9037 GstElement *rg_vol_element = NULL;
9041 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9043 player->sound.rg_enable = enabled;
9045 /* just hold rgvolume enable value if pipeline is not ready */
9046 if (!player->pipeline || !player->pipeline->audiobin) {
9047 LOGD("pipeline is not ready. holding rgvolume enable value");
9048 return MM_ERROR_NONE;
9051 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9053 if (!rg_vol_element) {
9054 LOGD("rgvolume element is not created");
9055 return MM_ERROR_PLAYER_INTERNAL;
9059 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9061 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9065 return MM_ERROR_NONE;
9069 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9071 mmplayer_t *player = (mmplayer_t *)hplayer;
9072 GstElement *rg_vol_element = NULL;
9073 gboolean enable = FALSE;
9077 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9078 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9080 /* just hold enable_rg value if pipeline is not ready */
9081 if (!player->pipeline || !player->pipeline->audiobin) {
9082 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9083 *enabled = player->sound.rg_enable;
9084 return MM_ERROR_NONE;
9087 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9089 if (!rg_vol_element) {
9090 LOGD("rgvolume element is not created");
9091 return MM_ERROR_PLAYER_INTERNAL;
9094 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9095 *enabled = (bool)enable;
9099 return MM_ERROR_NONE;
9103 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9105 mmplayer_t *player = (mmplayer_t *)hplayer;
9106 MMHandleType attrs = 0;
9108 int ret = MM_ERROR_NONE;
9112 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9114 attrs = MMPLAYER_GET_ATTRS(player);
9115 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9117 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9119 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9120 return MM_ERROR_PLAYER_INTERNAL;
9123 player->video_roi.scale_x = scale_x;
9124 player->video_roi.scale_y = scale_y;
9125 player->video_roi.scale_width = scale_width;
9126 player->video_roi.scale_height = scale_height;
9128 /* check video sinkbin is created */
9129 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9130 return MM_ERROR_NONE;
9132 if (!gst_video_overlay_set_video_roi_area(
9133 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9134 scale_x, scale_y, scale_width, scale_height))
9135 ret = MM_ERROR_PLAYER_INTERNAL;
9137 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9138 scale_x, scale_y, scale_width, scale_height);
9146 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9148 mmplayer_t *player = (mmplayer_t *)hplayer;
9149 int ret = MM_ERROR_NONE;
9153 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9154 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9156 *scale_x = player->video_roi.scale_x;
9157 *scale_y = player->video_roi.scale_y;
9158 *scale_width = player->video_roi.scale_width;
9159 *scale_height = player->video_roi.scale_height;
9161 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9162 *scale_x, *scale_y, *scale_width, *scale_height);
9168 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9170 mmplayer_t *player = (mmplayer_t *)hplayer;
9174 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9176 player->client_pid = pid;
9178 LOGD("client pid[%d] %p", pid, player);
9182 return MM_ERROR_NONE;
9186 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9188 mmplayer_t *player = (mmplayer_t *)hplayer;
9189 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9190 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9194 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9195 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9198 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9200 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9202 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9203 return MM_ERROR_NONE;
9205 /* in case of audio codec default type is HW */
9207 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9208 if (player->ini.support_audio_effect)
9209 return MM_ERROR_NONE;
9210 elem_id = MMPLAYER_A_FILTER;
9212 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9213 if (player->ini.support_replaygain_control)
9214 return MM_ERROR_NONE;
9215 elem_id = MMPLAYER_A_RGVOL;
9217 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9218 if (player->ini.support_pitch_control)
9219 return MM_ERROR_NONE;
9220 elem_id = MMPLAYER_A_PITCH;
9222 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9223 if (player->ini.support_audio_effect)
9224 return MM_ERROR_NONE;
9226 /* default case handling is not required */
9229 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9230 LOGW("audio control option [%d] is not available", opt);
9233 /* setting pcm exporting option is allowed before READY state */
9234 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9235 return MM_ERROR_PLAYER_INVALID_STATE;
9237 /* check whether the audio filter exist or not after READY state,
9238 because the sw codec could be added during auto-plugging in some cases */
9239 if (!player->pipeline ||
9240 !player->pipeline->audiobin ||
9241 !player->pipeline->audiobin[elem_id].gst) {
9242 LOGW("there is no audio elem [%d]", elem_id);
9247 LOGD("audio control opt %d, available %d", opt, *available);
9251 return MM_ERROR_NONE;
9255 __mmplayer_update_duration_value(mmplayer_t *player)
9257 gboolean ret = FALSE;
9258 gint64 dur_nsec = 0;
9259 LOGD("try to update duration");
9261 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9262 player->duration = dur_nsec;
9263 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9267 if (player->duration < 0) {
9268 LOGW("duration is Non-Initialized !!!");
9269 player->duration = 0;
9272 /* update streaming service type */
9273 player->streaming_type = _mmplayer_get_stream_service_type(player);
9275 /* check duration is OK */
9276 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9277 /* FIXIT : find another way to get duration here. */
9278 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9284 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9286 /* update audio params
9287 NOTE : We need original audio params and it can be only obtained from src pad of audio
9288 decoder. Below code only valid when we are not using 'resampler' just before
9289 'audioconverter'. */
9290 GstCaps *caps_a = NULL;
9292 gint samplerate = 0, channels = 0;
9293 GstStructure *p = NULL;
9294 GstElement *aconv = NULL;
9296 LOGD("try to update audio attrs");
9298 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9300 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9301 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9302 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9303 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9305 LOGE("there is no audio converter");
9309 pad = gst_element_get_static_pad(aconv, "sink");
9312 LOGW("failed to get pad from audio converter");
9316 caps_a = gst_pad_get_current_caps(pad);
9318 LOGW("not ready to get audio caps");
9319 gst_object_unref(pad);
9323 p = gst_caps_get_structure(caps_a, 0);
9325 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9327 gst_structure_get_int(p, "rate", &samplerate);
9328 gst_structure_get_int(p, "channels", &channels);
9330 mm_player_set_attribute((MMHandleType)player, NULL,
9331 "content_audio_samplerate", samplerate,
9332 "content_audio_channels", channels, NULL);
9334 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9336 gst_caps_unref(caps_a);
9337 gst_object_unref(pad);
9343 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9345 LOGD("try to update video attrs");
9347 GstCaps *caps_v = NULL;
9351 GstStructure *p = NULL;
9353 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9354 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9356 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9358 LOGD("no videosink sink pad");
9362 caps_v = gst_pad_get_current_caps(pad);
9363 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9364 if (!caps_v && player->v_stream_caps) {
9365 caps_v = player->v_stream_caps;
9366 gst_caps_ref(caps_v);
9370 LOGD("no negotiated caps from videosink");
9371 gst_object_unref(pad);
9375 p = gst_caps_get_structure(caps_v, 0);
9376 gst_structure_get_int(p, "width", &width);
9377 gst_structure_get_int(p, "height", &height);
9379 mm_player_set_attribute((MMHandleType)player, NULL,
9380 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9382 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9384 SECURE_LOGD("width : %d height : %d", width, height);
9386 gst_caps_unref(caps_v);
9387 gst_object_unref(pad);
9390 mm_player_set_attribute((MMHandleType)player, NULL,
9391 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9392 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9399 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9401 gboolean ret = FALSE;
9402 guint64 data_size = 0;
9406 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9407 if (!player->duration)
9410 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9411 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9412 if (stat(path, &sb) == 0)
9413 data_size = (guint64)sb.st_size;
9415 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9416 data_size = player->http_content_size;
9419 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9422 guint64 bitrate = 0;
9423 guint64 msec_dur = 0;
9425 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9427 bitrate = data_size * 8 * 1000 / msec_dur;
9428 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9429 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9430 mm_player_set_attribute((MMHandleType)player, NULL,
9431 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9434 LOGD("player duration is less than 0");
9438 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9439 if (player->total_bitrate) {
9440 mm_player_set_attribute((MMHandleType)player, NULL,
9441 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9450 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9452 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9453 data->uri_type = uri_type;
9457 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9459 int ret = MM_ERROR_PLAYER_INVALID_URI;
9461 char *buffer = NULL;
9462 char *seperator = strchr(path, ',');
9463 char ext[100] = {0,}, size[100] = {0,};
9466 if ((buffer = strstr(path, "ext="))) {
9467 buffer += strlen("ext=");
9469 if (strlen(buffer)) {
9470 strncpy(ext, buffer, 99);
9472 if ((seperator = strchr(ext, ','))
9473 || (seperator = strchr(ext, ' '))
9474 || (seperator = strchr(ext, '\0'))) {
9475 seperator[0] = '\0';
9480 if ((buffer = strstr(path, "size="))) {
9481 buffer += strlen("size=");
9483 if (strlen(buffer) > 0) {
9484 strncpy(size, buffer, 99);
9486 if ((seperator = strchr(size, ','))
9487 || (seperator = strchr(size, ' '))
9488 || (seperator = strchr(size, '\0'))) {
9489 seperator[0] = '\0';
9492 mem_size = atoi(size);
9497 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9499 if (mem_size && param) {
9500 if (data->input_mem.buf)
9501 free(data->input_mem.buf);
9502 data->input_mem.buf = malloc(mem_size);
9504 if (data->input_mem.buf) {
9505 memcpy(data->input_mem.buf, param, mem_size);
9506 data->input_mem.len = mem_size;
9507 ret = MM_ERROR_NONE;
9509 LOGE("failed to alloc mem %d", mem_size);
9510 ret = MM_ERROR_PLAYER_INTERNAL;
9513 data->input_mem.offset = 0;
9514 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9521 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9523 gchar *location = NULL;
9526 int ret = MM_ERROR_NONE;
9528 if ((path = strstr(uri, "file://"))) {
9529 location = g_filename_from_uri(uri, NULL, &err);
9530 if (!location || (err != NULL)) {
9531 LOGE("Invalid URI '%s' for filesrc: %s", path,
9532 (err != NULL) ? err->message : "unknown error");
9536 MMPLAYER_FREEIF(location);
9538 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9539 return MM_ERROR_PLAYER_INVALID_URI;
9541 LOGD("path from uri: %s", location);
9544 path = (location != NULL) ? (location) : ((char *)uri);
9547 ret = _mmplayer_exist_file_path(path);
9549 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9550 if (ret == MM_ERROR_NONE) {
9551 if (_mmplayer_is_sdp_file(path)) {
9552 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9553 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9554 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9556 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9557 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9559 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9560 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9562 LOGE("invalid uri, could not play..");
9563 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9566 MMPLAYER_FREEIF(location);
9571 static mmplayer_video_decoded_data_info_t *
9572 __mmplayer_create_stream_from_pad(GstPad *pad)
9574 GstCaps *caps = NULL;
9575 GstStructure *structure = NULL;
9576 unsigned int fourcc = 0;
9577 const gchar *string_format = NULL;
9578 mmplayer_video_decoded_data_info_t *stream = NULL;
9580 MMPixelFormatType format;
9583 caps = gst_pad_get_current_caps(pad);
9585 LOGE("Caps is NULL.");
9590 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9592 structure = gst_caps_get_structure(caps, 0);
9593 gst_structure_get_int(structure, "width", &width);
9594 gst_structure_get_int(structure, "height", &height);
9595 string_format = gst_structure_get_string(structure, "format");
9598 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9599 format = _mmplayer_get_pixtype(fourcc);
9600 gst_video_info_from_caps(&info, caps);
9601 gst_caps_unref(caps);
9604 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9605 LOGE("Wrong condition!!");
9609 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9611 LOGE("failed to alloc mem for video data");
9615 stream->width = width;
9616 stream->height = height;
9617 stream->format = format;
9618 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9624 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9626 unsigned int pitch = 0;
9627 unsigned int size = 0;
9629 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9632 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9633 bo = gst_tizen_memory_get_bos(mem, index);
9635 stream->bo[index] = tbm_bo_ref(bo);
9637 LOGE("failed to get bo for index %d", index);
9640 for (index = 0; index < stream->plane_num; index++) {
9641 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9642 stream->stride[index] = pitch;
9644 stream->elevation[index] = size / pitch;
9646 stream->elevation[index] = stream->height;
9651 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9653 if (stream->format == MM_PIXEL_FORMAT_I420) {
9654 int ret = TBM_SURFACE_ERROR_NONE;
9655 tbm_surface_h surface;
9656 tbm_surface_info_s info;
9658 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9660 ret = tbm_surface_get_info(surface, &info);
9661 if (ret != TBM_SURFACE_ERROR_NONE) {
9662 tbm_surface_destroy(surface);
9666 tbm_surface_destroy(surface);
9667 stream->stride[0] = info.planes[0].stride;
9668 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9669 stream->stride[1] = info.planes[1].stride;
9670 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9671 stream->stride[2] = info.planes[2].stride;
9672 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9673 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9674 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9675 stream->stride[0] = stream->width * 4;
9676 stream->elevation[0] = stream->height;
9677 stream->bo_size = stream->stride[0] * stream->height;
9679 LOGE("Not support format %d", stream->format);
9687 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9689 tbm_bo_handle thandle;
9691 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9692 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9693 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9697 unsigned char *src = NULL;
9698 unsigned char *dest = NULL;
9699 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9701 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9703 LOGE("fail to gst_memory_map");
9707 if (!mapinfo.data) {
9708 LOGE("data pointer is wrong");
9712 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9713 if (!stream->bo[0]) {
9714 LOGE("Fail to tbm_bo_alloc!!");
9718 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9720 LOGE("thandle pointer is wrong");
9724 if (stream->format == MM_PIXEL_FORMAT_I420) {
9725 src_stride[0] = GST_ROUND_UP_4(stream->width);
9726 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9727 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9728 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9731 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9732 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9734 for (i = 0; i < 3; i++) {
9735 src = mapinfo.data + src_offset[i];
9736 dest = thandle.ptr + dest_offset[i];
9741 for (j = 0; j < stream->height >> k; j++) {
9742 memcpy(dest, src, stream->width>>k);
9743 src += src_stride[i];
9744 dest += stream->stride[i];
9747 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9748 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9750 LOGE("Not support format %d", stream->format);
9754 tbm_bo_unmap(stream->bo[0]);
9755 gst_memory_unmap(mem, &mapinfo);
9761 tbm_bo_unmap(stream->bo[0]);
9764 gst_memory_unmap(mem, &mapinfo);
9770 __mmplayer_set_pause_state(mmplayer_t *player)
9772 if (player->sent_bos)
9775 /* rtsp case, get content attrs by GstMessage */
9776 if (MMPLAYER_IS_RTSP_STREAMING(player))
9779 /* it's first time to update all content attrs. */
9780 _mmplayer_update_content_attrs(player, ATTR_ALL);
9784 __mmplayer_set_playing_state(mmplayer_t *player)
9786 gchar *audio_codec = NULL;
9788 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9789 /* initialize because auto resume is done well. */
9790 player->resumed_by_rewind = FALSE;
9791 player->playback_rate = 1.0;
9794 if (player->sent_bos)
9797 /* try to get content metadata */
9799 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9800 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9801 * legacy mmfw-player api
9803 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9805 if ((player->cmd == MMPLAYER_COMMAND_START)
9806 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9807 __mmplayer_handle_missed_plugin(player);
9810 /* check audio codec field is set or not
9811 * we can get it from typefinder or codec's caps.
9813 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9815 /* The codec format can't be sent for audio only case like amr, mid etc.
9816 * Because, parser don't make related TAG.
9817 * So, if it's not set yet, fill it with found data.
9820 if (g_strrstr(player->type, "audio/midi"))
9821 audio_codec = "MIDI";
9822 else if (g_strrstr(player->type, "audio/x-amr"))
9823 audio_codec = "AMR";
9824 else if (g_strrstr(player->type, "audio/mpeg")
9825 && !g_strrstr(player->type, "mpegversion=(int)1"))
9826 audio_codec = "AAC";
9828 audio_codec = "unknown";
9830 if (mm_player_set_attribute((MMHandleType)player, NULL,
9831 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9832 LOGE("failed to set attribute");
9834 LOGD("set audio codec type with caps");