4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related function will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
143 static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
144 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void __mmplayer_release_misc(mmplayer_t *player);
150 static void __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
160 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
161 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
162 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
163 static gpointer __mmplayer_gapless_play_thread(gpointer data);
164 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
165 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_release_dump_list(GList *dump_list);
167 static int __mmplayer_gst_realize(mmplayer_t *player);
168 static int __mmplayer_gst_unrealize(mmplayer_t *player);
169 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
170 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
173 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
174 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
175 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
176 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
177 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
178 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
179 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
180 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
181 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
182 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
183 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
184 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
188 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
189 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
190 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
192 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
193 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
194 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
195 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
197 static void __mmplayer_set_pause_state(mmplayer_t *player);
198 static void __mmplayer_set_playing_state(mmplayer_t *player);
199 static int __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index);
200 /*===========================================================================================
202 | FUNCTION DEFINITIONS |
204 ========================================================================================== */
206 /* This function should be called after the pipeline goes PAUSED or higher
209 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
211 static gboolean has_duration = FALSE;
212 static gboolean has_video_attrs = FALSE;
213 static gboolean has_audio_attrs = FALSE;
214 static gboolean has_bitrate = FALSE;
215 gboolean missing_only = FALSE;
216 gboolean all = FALSE;
217 MMHandleType attrs = 0;
221 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
223 /* check player state here */
224 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
225 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
226 /* give warning now only */
227 LOGW("be careful. content attributes may not available in this state ");
230 /* get content attribute first */
231 attrs = MMPLAYER_GET_ATTRS(player);
233 LOGE("cannot get content attribute");
237 /* get update flag */
239 if (flag & ATTR_MISSING_ONLY) {
241 LOGD("updating missed attr only");
244 if (flag & ATTR_ALL) {
246 has_duration = FALSE;
247 has_video_attrs = FALSE;
248 has_audio_attrs = FALSE;
251 LOGD("updating all attrs");
254 if (missing_only && all) {
255 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
256 missing_only = FALSE;
259 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
260 has_duration = __mmplayer_update_duration_value(player);
262 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
263 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
265 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
266 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
268 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
269 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
277 _mmplayer_get_stream_service_type(mmplayer_t *player)
279 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
283 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
285 player->pipeline->mainbin &&
286 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
287 STREAMING_SERVICE_NONE);
289 /* streaming service type if streaming */
290 if (!MMPLAYER_IS_STREAMING(player))
291 return STREAMING_SERVICE_NONE;
293 streaming_type = (player->duration == 0) ?
294 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
296 switch (streaming_type) {
297 case STREAMING_SERVICE_LIVE:
298 LOGD("it's live streaming");
300 case STREAMING_SERVICE_VOD:
301 LOGD("it's vod streaming");
304 LOGE("should not get here");
310 return streaming_type;
313 /* this function sets the player state and also report
314 * it to application by calling callback function
317 _mmplayer_set_state(mmplayer_t *player, int state)
319 MMMessageParamType msg = {0, };
321 MMPLAYER_RETURN_IF_FAIL(player);
323 if (MMPLAYER_CURRENT_STATE(player) == state) {
324 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
325 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
329 /* update player states */
330 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
331 MMPLAYER_CURRENT_STATE(player) = state;
333 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
334 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
337 MMPLAYER_PRINT_STATE(player);
339 switch (MMPLAYER_CURRENT_STATE(player)) {
340 case MM_PLAYER_STATE_NULL:
341 case MM_PLAYER_STATE_READY:
343 case MM_PLAYER_STATE_PAUSED:
344 __mmplayer_set_pause_state(player);
346 case MM_PLAYER_STATE_PLAYING:
347 __mmplayer_set_playing_state(player);
349 case MM_PLAYER_STATE_NONE:
351 LOGW("invalid target state, there is nothing to do.");
356 /* post message to application */
357 if (MMPLAYER_TARGET_STATE(player) == state) {
358 /* fill the message with state of player */
359 msg.union_type = MM_MSG_UNION_STATE;
360 msg.state.previous = MMPLAYER_PREV_STATE(player);
361 msg.state.current = MMPLAYER_CURRENT_STATE(player);
363 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
365 /* state changed by resource callback */
366 if (player->interrupted_by_resource)
367 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
368 else /* state changed by usecase */
369 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
372 LOGD("intermediate state, do nothing.");
373 MMPLAYER_PRINT_STATE(player);
377 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
378 && !player->sent_bos) {
379 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
380 player->sent_bos = TRUE;
387 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
389 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
390 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
392 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
394 LOGD("incoming command : %d ", command);
396 current_state = MMPLAYER_CURRENT_STATE(player);
397 pending_state = MMPLAYER_PENDING_STATE(player);
399 MMPLAYER_PRINT_STATE(player);
402 case MMPLAYER_COMMAND_CREATE:
404 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
406 if (current_state == MM_PLAYER_STATE_NULL ||
407 current_state == MM_PLAYER_STATE_READY ||
408 current_state == MM_PLAYER_STATE_PAUSED ||
409 current_state == MM_PLAYER_STATE_PLAYING)
414 case MMPLAYER_COMMAND_DESTROY:
416 /* destroy can called anytime */
418 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
422 case MMPLAYER_COMMAND_REALIZE:
424 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
426 if (pending_state != MM_PLAYER_STATE_NONE) {
429 /* need ready state to realize */
430 if (current_state == MM_PLAYER_STATE_READY)
433 if (current_state != MM_PLAYER_STATE_NULL)
439 case MMPLAYER_COMMAND_UNREALIZE:
441 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
443 if (current_state == MM_PLAYER_STATE_NULL)
448 case MMPLAYER_COMMAND_START:
450 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
452 if (pending_state == MM_PLAYER_STATE_NONE) {
453 if (current_state == MM_PLAYER_STATE_PLAYING)
455 else if (current_state != MM_PLAYER_STATE_READY &&
456 current_state != MM_PLAYER_STATE_PAUSED)
458 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
460 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
461 LOGD("player is going to paused state, just change the pending state as playing");
468 case MMPLAYER_COMMAND_STOP:
470 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
472 if (current_state == MM_PLAYER_STATE_READY)
475 /* need playing/paused state to stop */
476 if (current_state != MM_PLAYER_STATE_PLAYING &&
477 current_state != MM_PLAYER_STATE_PAUSED)
482 case MMPLAYER_COMMAND_PAUSE:
484 if (MMPLAYER_IS_LIVE_STREAMING(player))
487 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
488 goto NOT_COMPLETED_SEEK;
490 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
492 if (pending_state == MM_PLAYER_STATE_NONE) {
493 if (current_state == MM_PLAYER_STATE_PAUSED)
495 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of browser
497 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
499 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
500 if (current_state == MM_PLAYER_STATE_PAUSED)
501 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
508 case MMPLAYER_COMMAND_RESUME:
510 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
511 goto NOT_COMPLETED_SEEK;
513 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
515 if (pending_state == MM_PLAYER_STATE_NONE) {
516 if (current_state == MM_PLAYER_STATE_PLAYING)
518 else if (current_state != MM_PLAYER_STATE_PAUSED)
520 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
522 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
523 LOGD("player is going to paused state, just change the pending state as playing");
533 player->cmd = command;
535 return MM_ERROR_NONE;
538 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
539 MMPLAYER_STATE_GET_NAME(current_state), command);
540 return MM_ERROR_PLAYER_INVALID_STATE;
543 LOGW("not completed seek");
544 return MM_ERROR_PLAYER_DOING_SEEK;
547 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
548 return MM_ERROR_PLAYER_NO_OP;
551 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
552 return MM_ERROR_PLAYER_NO_OP;
555 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
557 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
558 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
561 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
562 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
564 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
565 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
567 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
568 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
571 LOGE("invalid mmplayer resource type %d", type);
572 return MM_ERROR_PLAYER_INTERNAL;
575 if (player->hw_resource[type] != NULL) {
576 LOGD("[%d type] resource was already acquired", type);
577 return MM_ERROR_NONE;
580 LOGD("mark for acquire [%d type] resource", type);
581 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
582 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
583 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
584 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
585 return MM_ERROR_PLAYER_INTERNAL;
588 LOGD("commit [%d type] resource", type);
589 rm_ret = mm_resource_manager_commit(player->resource_manager);
590 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
591 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
592 return MM_ERROR_PLAYER_INTERNAL;
596 return MM_ERROR_NONE;
599 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
601 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
603 MMPLAYER_RETURN_IF_FAIL(player);
604 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
606 rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
607 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
608 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
612 rm_ret = mm_resource_manager_commit(player->resource_manager);
613 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
614 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
617 /* de-initialize resource manager */
618 rm_ret = mm_resource_manager_destroy(player->resource_manager);
619 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
620 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
624 player->resource_manager = NULL;
626 LOGD("resource manager is destroyed");
629 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
631 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
635 if (player->hw_resource[type] == NULL) {
636 LOGD("there is no acquired [%d type] resource", type);
637 return MM_ERROR_NONE;
640 LOGD("mark for release [%d type] resource", type);
641 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
642 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
643 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
644 return MM_ERROR_PLAYER_INTERNAL;
647 player->hw_resource[type] = NULL;
649 LOGD("commit [%d type] resource", type);
650 rm_ret = mm_resource_manager_commit(player->resource_manager);
651 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
652 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
653 return MM_ERROR_PLAYER_INTERNAL;
657 return MM_ERROR_NONE;
661 __mmplayer_initialize_gapless_play(mmplayer_t *player)
667 player->smooth_streaming = FALSE;
668 player->videodec_linked = 0;
669 player->audiodec_linked = 0;
670 player->textsink_linked = 0;
671 player->is_external_subtitle_present = FALSE;
672 player->is_external_subtitle_added_now = FALSE;
673 player->not_supported_codec = MISSING_PLUGIN_NONE;
674 player->can_support_codec = FOUND_PLUGIN_NONE;
675 player->pending_seek.is_pending = false;
676 player->pending_seek.pos = 0;
677 player->msg_posted = FALSE;
678 player->has_many_types = FALSE;
679 player->no_more_pad = FALSE;
680 player->not_found_demuxer = 0;
681 player->seek_state = MMPLAYER_SEEK_NONE;
682 player->is_subtitle_force_drop = FALSE;
683 player->play_subtitle = FALSE;
684 player->adjust_subtitle_pos = 0;
686 player->total_bitrate = 0;
687 player->total_maximum_bitrate = 0;
689 _mmplayer_track_initialize(player);
690 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
692 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
693 player->bitrate[i] = 0;
694 player->maximum_bitrate[i] = 0;
697 if (player->v_stream_caps) {
698 gst_caps_unref(player->v_stream_caps);
699 player->v_stream_caps = NULL;
702 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
704 /* clean found audio decoders */
705 if (player->audio_decoders) {
706 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
707 player->audio_decoders = NULL;
710 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
715 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
717 LOGI("set pipeline reconfigure state %d", state);
718 MMPLAYER_RECONFIGURE_LOCK(player);
719 player->gapless.reconfigure = state;
720 if (!state) /* wake up the waiting job */
721 MMPLAYER_RECONFIGURE_SIGNAL(player);
722 MMPLAYER_RECONFIGURE_UNLOCK(player);
726 __mmplayer_gapless_play_thread(gpointer data)
728 mmplayer_t *player = (mmplayer_t *)data;
729 mmplayer_gst_element_t *mainbin = NULL;
731 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
733 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
734 while (!player->gapless_play_thread_exit) {
735 LOGD("gapless play thread started. waiting for signal.");
736 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
738 LOGD("reconfigure pipeline for gapless play.");
740 if (player->gapless_play_thread_exit) {
741 _mmplayer_set_reconfigure_state(player, FALSE);
742 LOGD("exiting gapless play thread");
746 mainbin = player->pipeline->mainbin;
748 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
749 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
752 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
754 /* Initialize Player values */
755 __mmplayer_initialize_gapless_play(player);
757 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
759 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
765 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
767 GSource *source = NULL;
771 source = g_main_context_find_source_by_id(context, source_id);
772 if (source != NULL) {
773 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
774 g_source_destroy(source);
781 _mmplayer_watcher_removed_notify(gpointer data)
783 mmplayer_t *player = (mmplayer_t *)data;
784 MMPLAYER_RETURN_IF_FAIL(player);
786 MMPLAYER_BUS_WATCHER_LOCK(player);
787 player->bus_watcher = 0;
788 MMPLAYER_BUS_WATCHER_SIGNAL(player);
789 MMPLAYER_BUS_WATCHER_UNLOCK(player);
793 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
795 mmplayer_t *player = (mmplayer_t *)hplayer;
798 MMPLAYER_RETURN_IF_FAIL(player);
800 /* disconnecting bus watch */
801 if (player->bus_watcher > 0) {
802 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
803 MMPLAYER_BUS_WATCHER_LOCK(player);
804 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
805 while (player->bus_watcher > 0) {
806 if (!MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time)) {
807 LOGW("MMPLAYER_BUS_WATCHER_WAIT_UNTIL() timeout has passed - bus_watcher (%d)",
808 player->bus_watcher);
812 MMPLAYER_BUS_WATCHER_UNLOCK(player);
813 g_mutex_clear(&player->bus_watcher_mutex);
814 g_cond_clear(&player->bus_watcher_cond);
821 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
823 mmplayer_t *player = (mmplayer_t *)hplayer;
824 GstMessage *msg = NULL;
825 GQueue *queue = NULL;
828 MMPLAYER_RETURN_IF_FAIL(player);
830 /* destroy the gst bus msg thread */
831 if (player->bus_msg_thread) {
832 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
833 player->bus_msg_thread_exit = TRUE;
834 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
835 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
837 LOGD("gst bus msg thread exit.");
838 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
839 player->bus_msg_thread = NULL;
841 g_mutex_clear(&player->bus_msg_thread_mutex);
842 g_cond_clear(&player->bus_msg_thread_cond);
845 g_mutex_lock(&player->bus_msg_q_lock);
846 queue = player->bus_msg_q;
847 while (!g_queue_is_empty(queue)) {
848 msg = (GstMessage *)g_queue_pop_head(queue);
853 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
854 gst_message_unref(msg);
856 g_mutex_unlock(&player->bus_msg_q_lock);
862 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
864 GstElement *parent = NULL;
866 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
867 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
870 MMPLAYER_FSINK_LOCK(player);
872 /* get parent of fakesink */
873 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
875 LOGD("fakesink already removed");
879 gst_element_set_locked_state(fakesink->gst, TRUE);
881 /* setting the state to NULL never returns async
882 * so no need to wait for completion of state transition
884 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
885 LOGE("fakesink state change failure!");
886 /* FIXIT : should I return here? or try to proceed to next? */
889 /* remove fakesink from it's parent */
890 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
891 LOGE("failed to remove fakesink");
893 gst_object_unref(parent);
898 gst_object_unref(parent);
900 LOGD("state-holder removed");
902 gst_element_set_locked_state(fakesink->gst, FALSE);
904 MMPLAYER_FSINK_UNLOCK(player);
909 gst_element_set_locked_state(fakesink->gst, FALSE);
911 MMPLAYER_FSINK_UNLOCK(player);
915 static GstPadProbeReturn
916 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
918 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
919 return GST_PAD_PROBE_OK;
923 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
925 gint64 stop_running_time = 0;
926 gint64 position_running_time = 0;
930 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
931 if ((player->gapless.update_segment[idx] == TRUE) ||
932 !(player->track[idx].event_probe_id)) {
934 LOGW("[%d] skip", idx);
939 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
941 gst_segment_to_running_time(&player->gapless.segment[idx],
942 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
943 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
945 gst_segment_to_running_time(&player->gapless.segment[idx],
946 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
948 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
950 gst_segment_to_running_time(&player->gapless.segment[idx],
951 GST_FORMAT_TIME, player->duration);
954 position_running_time =
955 gst_segment_to_running_time(&player->gapless.segment[idx],
956 GST_FORMAT_TIME, player->gapless.segment[idx].position);
958 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
959 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
961 GST_TIME_ARGS(stop_running_time),
962 GST_TIME_ARGS(position_running_time),
963 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
964 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
966 position_running_time = MAX(position_running_time, stop_running_time);
967 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
968 GST_FORMAT_TIME, player->gapless.segment[idx].start);
969 position_running_time = MAX(0, position_running_time);
970 position = MAX(position, position_running_time);
974 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
975 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
976 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
978 player->gapless.start_time[stream_type] += position;
984 static GstPadProbeReturn
985 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
987 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
988 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
989 mmplayer_t *player = (mmplayer_t *)data;
990 GstCaps *caps = NULL;
991 GstStructure *str = NULL;
992 const gchar *name = NULL;
993 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
994 gboolean caps_ret = TRUE;
996 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
997 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
998 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
999 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
1000 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
1003 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1007 if (strstr(name, "audio")) {
1008 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1009 } else if (strstr(name, "video")) {
1010 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1012 /* text track is not supportable */
1013 LOGE("invalid name %s", name);
1017 switch (GST_EVENT_TYPE(event)) {
1020 /* in case of gapless, drop eos event not to send it to sink */
1021 if (player->gapless.reconfigure && !player->msg_posted) {
1022 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1023 ret = GST_PAD_PROBE_DROP;
1027 case GST_EVENT_STREAM_START:
1029 __mmplayer_gst_selector_update_start_time(player, stream_type);
1032 case GST_EVENT_FLUSH_STOP:
1034 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1035 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1036 player->gapless.start_time[stream_type] = 0;
1039 case GST_EVENT_SEGMENT:
1044 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1045 gst_event_copy_segment(event, &segment);
1047 if (segment.format != GST_FORMAT_TIME)
1050 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1051 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1052 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1053 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1054 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1055 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1057 /* keep the all the segment ev to cover the seeking */
1058 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1059 player->gapless.update_segment[stream_type] = TRUE;
1061 if (!player->gapless.running)
1064 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1066 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1068 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1069 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1070 gst_event_unref(event);
1071 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1077 gdouble proportion = 0.0;
1078 GstClockTimeDiff diff = 0;
1079 GstClockTime timestamp = 0;
1080 gint64 running_time_diff = -1;
1081 GstQOSType type = 0;
1082 GstEvent *tmpev = NULL;
1084 running_time_diff = player->gapless.segment[stream_type].base;
1086 if (running_time_diff <= 0) /* don't need to adjust */
1089 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1090 gst_event_unref(event);
1092 if (timestamp < running_time_diff) {
1093 LOGW("QOS event from previous group");
1094 ret = GST_PAD_PROBE_DROP;
1099 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1100 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1101 stream_type, GST_TIME_ARGS(timestamp),
1102 GST_TIME_ARGS(running_time_diff),
1103 GST_TIME_ARGS(timestamp - running_time_diff));
1106 timestamp -= running_time_diff;
1108 /* That case is invalid for QoS events */
1109 if (diff < 0 && -diff > timestamp) {
1110 LOGW("QOS event from previous group");
1111 ret = GST_PAD_PROBE_DROP;
1115 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1116 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1126 gst_caps_unref(caps);
1130 /* create fakesink for audio or video path without audiobin or videobin */
1132 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1134 GstElement *pipeline = NULL;
1135 GstElement *fakesink = NULL;
1136 GstPad *sinkpad = NULL;
1139 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1141 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1144 fakesink = gst_element_factory_make("fakesink", NULL);
1145 if (fakesink == NULL) {
1146 LOGE("failed to create fakesink");
1150 if (!gst_bin_add(GST_BIN(pipeline), fakesink)) {
1151 LOGE("failed to add fakesink to pipeline");
1156 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1158 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1160 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1161 LOGE("failed to link fakesink");
1165 if (strstr(name, "video")) {
1166 if (player->v_stream_caps) {
1167 gst_caps_unref(player->v_stream_caps);
1168 player->v_stream_caps = NULL;
1170 if (player->ini.set_dump_element_flag)
1171 __mmplayer_add_dump_buffer_probe(player, fakesink);
1174 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1175 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1177 /* store it as it's sink element */
1178 __mmplayer_add_sink(player, fakesink, FALSE);
1181 gst_object_unref(GST_OBJECT(sinkpad));
1189 gst_object_unref(GST_OBJECT(sinkpad));
1192 gst_element_set_state(fakesink, GST_STATE_NULL);
1194 if (!gst_bin_remove(GST_BIN(pipeline), fakesink))
1195 gst_object_unref(GST_OBJECT(fakesink));
1202 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1204 GstElement *pipeline = NULL;
1205 GstElement *concat = NULL;
1208 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1210 concat = gst_element_factory_make("concat", NULL);
1212 LOGE("failed to create concat");
1216 gst_element_set_state(concat, GST_STATE_PAUSED);
1218 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1219 if (!gst_bin_add(GST_BIN(pipeline), concat)) {
1220 LOGE("failed to add concat to pipeline");
1221 gst_element_set_state(concat, GST_STATE_NULL);
1222 gst_object_unref(GST_OBJECT(concat));
1226 LOGD("Create concat [%d] element", elem_idx);
1228 player->pipeline->mainbin[elem_idx].id = elem_idx;
1229 player->pipeline->mainbin[elem_idx].gst = concat;
1236 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1238 GstElement *pipeline = NULL;
1239 GstElement *selector = NULL;
1240 GstPad *srcpad = NULL;
1243 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1245 selector = gst_element_factory_make("input-selector", NULL);
1247 LOGE("failed to create input-selector");
1250 g_object_set(selector, "sync-streams", TRUE, NULL);
1252 srcpad = gst_element_get_static_pad(selector, "src");
1254 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1255 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1256 __mmplayer_gst_selector_blocked, NULL, NULL);
1257 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1258 __mmplayer_gst_selector_event_probe, player, NULL);
1260 gst_element_set_state(selector, GST_STATE_PAUSED);
1262 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1263 if (!gst_bin_add(GST_BIN(pipeline), selector)) {
1264 LOGE("failed to add selector to pipeline");
1266 if (player->track[stream_type].block_id != 0)
1267 gst_pad_remove_probe (srcpad, player->track[stream_type].block_id);
1268 player->track[stream_type].block_id = 0;
1270 if (player->track[stream_type].event_probe_id != 0)
1271 gst_pad_remove_probe (srcpad, player->track[stream_type].event_probe_id);
1272 player->track[stream_type].event_probe_id = 0;
1274 gst_object_unref(GST_OBJECT(srcpad));
1276 gst_element_set_state(selector, GST_STATE_NULL);
1277 gst_object_unref(GST_OBJECT(selector));
1281 gst_object_unref(GST_OBJECT(srcpad));
1283 player->pipeline->mainbin[elem_idx].id = elem_idx;
1284 player->pipeline->mainbin[elem_idx].gst = selector;
1291 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1293 mmplayer_t *player = (mmplayer_t *)data;
1294 GstElement *combiner = NULL;
1295 GstCaps *caps = NULL;
1296 GstStructure *str = NULL;
1297 const gchar *name = NULL;
1298 GstPad *sinkpad = NULL;
1299 gboolean first_track = FALSE;
1300 gboolean caps_ret = TRUE;
1302 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1303 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1306 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1307 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1309 LOGD("pad-added signal handling");
1311 /* get mimetype from caps */
1312 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1316 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1318 LOGD("detected mimetype : %s", name);
1321 if (strstr(name, "video")) {
1323 gchar *caps_str = NULL;
1325 caps_str = gst_caps_to_string(caps);
1326 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1327 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1328 player->set_mode.video_zc = true;
1330 MMPLAYER_FREEIF(caps_str);
1332 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1333 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1335 LOGD("surface type : %d", stype);
1337 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1338 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1342 /* in case of exporting video frame, it requires the 360 video filter.
1343 * it will be handled in _no_more_pads(). */
1344 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1345 __mmplayer_gst_make_fakesink(player, pad, name);
1349 if (MMPLAYER_USE_DECODEBIN(player)) {
1350 LOGD("video selector is required");
1351 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1353 LOGD("video concat is required");
1354 elem_idx = MMPLAYER_M_V_CONCAT;
1356 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1357 } else if (strstr(name, "audio")) {
1358 gint samplerate = 0;
1361 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1362 if (player->build_audio_offload)
1363 player->no_more_pad = TRUE; /* remove state holder */
1364 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1368 gst_structure_get_int(str, "rate", &samplerate);
1369 gst_structure_get_int(str, "channels", &channels);
1371 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1372 __mmplayer_gst_make_fakesink(player, pad, name);
1375 if (MMPLAYER_USE_DECODEBIN(player)) {
1376 LOGD("audio selector is required");
1377 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1379 LOGD("audio concat is required");
1380 elem_idx = MMPLAYER_M_A_CONCAT;
1382 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1384 } else if (strstr(name, "text")) {
1385 if (MMPLAYER_USE_DECODEBIN(player)) {
1386 LOGD("text selector is required");
1387 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1389 LOGD("text concat is required");
1390 elem_idx = MMPLAYER_M_T_CONCAT;
1392 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1394 LOGE("invalid caps info");
1398 /* check selector and create it */
1399 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1400 if (MMPLAYER_USE_DECODEBIN(player))
1401 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1403 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1409 LOGD("Combiner element is already created.");
1413 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1415 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1417 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1418 LOGE("failed to link combiner");
1419 gst_object_unref(GST_OBJECT(combiner));
1424 if (MMPLAYER_USE_DECODEBIN(player)) {
1425 LOGD("this track will be activated");
1426 g_object_set(combiner, "active-pad", sinkpad, NULL);
1430 if (MMPLAYER_USE_DECODEBIN(player)) {
1431 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1433 /* apply the text track information */
1434 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1435 mm_player_set_attribute((MMHandleType)player, NULL,
1436 "content_text_track_num", player->track[stream_type].total_track_num,
1437 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1438 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1445 gst_caps_unref(caps);
1448 gst_object_unref(GST_OBJECT(sinkpad));
1452 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-added");
1457 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1459 GstPad *srcpad = NULL;
1462 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1464 LOGD("type %d", type);
1467 LOGD("there is no %d track", type);
1471 srcpad = gst_element_get_static_pad(combiner, "src");
1473 LOGE("failed to get srcpad from combiner");
1477 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1479 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1481 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1482 if (player->track[type].block_id) {
1483 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1484 player->track[type].block_id = 0;
1488 gst_object_unref(GST_OBJECT(srcpad));
1497 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1499 gint active_index = 0;
1502 MMPLAYER_RETURN_IF_FAIL(player);
1504 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1506 /* change track to active pad */
1507 active_index = player->track[type].active_track_index;
1508 if ((active_index != DEFAULT_TRACK_INDEX) &&
1509 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1510 LOGW("failed to change %d type track to %d", type, active_index);
1511 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1515 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1516 mm_player_set_attribute((MMHandleType)player, NULL,
1517 "content_text_track_num", player->track[type].total_track_num,
1518 "current_text_track_index", player->track[type].active_track_index, NULL);
1525 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1528 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1530 if (!audio_selector) {
1531 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1533 /* in case the source is changed, output can be changed. */
1534 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1535 LOGD("remove previous audiobin if it exist");
1537 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1538 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1540 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1541 MMPLAYER_FREEIF(player->pipeline->audiobin);
1544 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1545 _mmplayer_pipeline_complete(NULL, player);
1550 /* apply the audio track information */
1551 if (MMPLAYER_USE_DECODEBIN(player))
1552 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1554 /* create audio sink path */
1555 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1556 LOGE("failed to create audio sink path");
1565 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1568 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1570 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1571 LOGD("text path is not supported");
1575 /* apply the text track information */
1576 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1578 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1579 player->has_closed_caption = TRUE;
1581 /* create text decode path */
1582 player->no_more_pad = TRUE;
1584 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1585 LOGE("failed to create text sink path");
1594 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1596 gint64 dur_bytes = 0L;
1599 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1600 player->pipeline->mainbin && player->streamer, FALSE);
1602 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1603 LOGE("fail to get duration.");
1605 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1606 * use file information was already set on Q2 when it was created. */
1607 _mm_player_streaming_set_queue2(player->streamer,
1608 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1609 TRUE, /* use_buffering */
1610 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1611 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1618 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1620 mmplayer_t *player = NULL;
1621 GstElement *video_selector = NULL;
1622 GstElement *audio_selector = NULL;
1623 GstElement *text_selector = NULL;
1626 player = (mmplayer_t *)data;
1628 LOGD("no-more-pad signal handling");
1630 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1631 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1632 LOGW("player is shutting down");
1636 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1637 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1638 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1639 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1640 LOGE("failed to set queue2 buffering");
1645 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1646 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1647 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1649 if (!video_selector && !audio_selector && !text_selector) {
1650 LOGW("there is no selector");
1651 player->no_more_pad = TRUE;
1655 /* create video path followed by video-select */
1656 if (video_selector && !audio_selector && !text_selector)
1657 player->no_more_pad = TRUE;
1659 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1662 /* create audio path followed by audio-select */
1663 if (audio_selector && !text_selector)
1664 player->no_more_pad = TRUE;
1666 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1669 /* create text path followed by text-select */
1670 __mmplayer_create_text_sink_path(player, text_selector);
1673 _mmplayer_set_reconfigure_state(player, FALSE);
1678 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1680 gboolean ret = FALSE;
1681 GstElement *pipeline = NULL;
1682 GstPad *sinkpad = NULL;
1685 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1686 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1688 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1690 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1692 LOGE("failed to get pad from sinkbin");
1698 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1699 LOGE("failed to link sinkbin for reusing");
1700 goto EXIT; /* exit either pass or fail */
1704 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1705 LOGE("failed to set state(READY) to sinkbin");
1710 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1711 LOGE("failed to add sinkbin to pipeline");
1716 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1717 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1722 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1723 LOGE("failed to set state(PAUSED) to sinkbin");
1732 gst_object_unref(GST_OBJECT(sinkpad));
1740 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1742 mmplayer_t *player = NULL;
1743 GstCaps *caps = NULL;
1744 gchar *caps_str = NULL;
1745 GstStructure *str = NULL;
1746 const gchar *name = NULL;
1747 GstElement *sinkbin = NULL;
1748 gboolean reusing = FALSE;
1749 gboolean caps_ret = TRUE;
1750 gchar *sink_pad_name = "sink";
1753 player = (mmplayer_t *)data;
1756 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1757 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1758 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1760 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1764 gst_caps_unref(caps);
1765 caps = gst_caps_ref(ref_caps);
1768 caps_str = gst_caps_to_string(caps);
1770 LOGD("detected mimetype : %s", name);
1772 if (strstr(name, "audio")) {
1773 if (player->pipeline->audiobin == NULL) {
1774 const gchar *audio_format = gst_structure_get_string(str, "format");
1776 LOGD("original audio format %s", audio_format);
1777 mm_player_set_attribute((MMHandleType)player, NULL,
1778 "content_audio_format", audio_format, strlen(audio_format), NULL);
1781 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1782 LOGE("failed to create audiobin. continuing without audio");
1786 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1787 LOGD("creating audiobin success");
1790 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1791 LOGD("reusing audiobin");
1792 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1794 } else if (strstr(name, "video")) {
1795 /* 1. zero copy is updated at _decode_pad_added()
1796 * 2. NULL surface type is handled in _decode_pad_added() */
1797 LOGD("zero copy %d", player->set_mode.video_zc);
1798 if (player->pipeline->videobin == NULL) {
1799 int surface_type = 0;
1800 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1801 LOGD("display_surface_type (%d)", surface_type);
1803 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) &&
1804 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1805 LOGE("failed to acquire video overlay resource");
1809 player->interrupted_by_resource = FALSE;
1811 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1812 LOGE("failed to create videobin. continuing without video");
1816 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1817 LOGD("creating videosink bin success");
1820 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1821 LOGD("re-using videobin");
1822 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1824 } else if (strstr(name, "text")) {
1825 if (player->pipeline->textbin == NULL) {
1826 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1827 LOGE("failed to create text sink bin. continuing without text");
1831 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1832 player->textsink_linked = 1;
1833 LOGD("creating textsink bin success");
1835 if (!player->textsink_linked) {
1836 LOGD("re-using textbin");
1838 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1839 player->textsink_linked = 1;
1841 /* linked textbin exist which means that the external subtitle path exist already */
1842 LOGW("ignoring internal subtitle since external subtitle is available");
1845 sink_pad_name = "text_sink";
1847 LOGW("unknown mime type %s, ignoring it", name);
1851 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1854 LOGD("[handle: %p] success to create and link sink bin", player);
1856 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1857 * streaming task. if the task blocked, then buffer will not flow to the next element
1858 *(autoplugging element). so this is special hack for streaming. please try to remove it
1860 /* dec stream count. we can remove fakesink if it's zero */
1861 if (player->num_dynamic_pad)
1862 player->num_dynamic_pad--;
1864 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1866 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1867 _mmplayer_pipeline_complete(NULL, player);
1871 MMPLAYER_FREEIF(caps_str);
1874 gst_caps_unref(caps);
1880 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1882 int required_angle = 0; /* Angle required for straight view */
1883 int rotation_angle = 0;
1885 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1886 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1888 /* Counter clockwise */
1889 switch (orientation) {
1894 required_angle = 270;
1897 required_angle = 180;
1900 required_angle = 90;
1904 rotation_angle = display_angle + required_angle;
1905 if (rotation_angle >= 360)
1906 rotation_angle -= 360;
1908 /* check if supported or not */
1909 if (rotation_angle % 90) {
1910 LOGD("not supported rotation angle = %d", rotation_angle);
1914 switch (rotation_angle) {
1916 *value = MM_DISPLAY_ROTATION_NONE;
1919 *value = MM_DISPLAY_ROTATION_90;
1922 *value = MM_DISPLAY_ROTATION_180;
1925 *value = MM_DISPLAY_ROTATION_270;
1929 LOGD("setting rotation property value : %d", *value);
1935 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1937 int display_rotation = 0;
1938 gchar *org_orient = NULL;
1939 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1942 LOGE("cannot get content attribute");
1943 return MM_ERROR_PLAYER_INTERNAL;
1946 if (display_angle) {
1947 /* update user rotation */
1948 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1950 /* Counter clockwise */
1951 switch (display_rotation) {
1952 case MM_DISPLAY_ROTATION_NONE:
1955 case MM_DISPLAY_ROTATION_90:
1956 *display_angle = 90;
1958 case MM_DISPLAY_ROTATION_180:
1959 *display_angle = 180;
1961 case MM_DISPLAY_ROTATION_270:
1962 *display_angle = 270;
1965 LOGW("wrong angle type : %d", display_rotation);
1968 LOGD("check user angle: %d", *display_angle);
1972 /* Counter clockwise */
1973 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1976 if (!strcmp(org_orient, "rotate-90"))
1978 else if (!strcmp(org_orient, "rotate-180"))
1980 else if (!strcmp(org_orient, "rotate-270"))
1983 LOGD("original rotation is %s", org_orient);
1985 LOGD("content_video_orientation get fail");
1988 LOGD("check orientation: %d", *orientation);
1991 return MM_ERROR_NONE;
1994 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1996 int rotation_value = 0;
1997 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1998 int display_angle = 0;
2001 /* check video sinkbin is created */
2002 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2005 _mmplayer_get_video_angle(player, &display_angle, &orientations);
2007 /* get rotation value to set */
2008 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
2009 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
2010 LOGD("set video param : rotate %d", rotation_value);
2013 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
2015 MMHandleType attrs = 0;
2019 /* check video sinkbin is created */
2020 if (!(_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY) ||
2021 _mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI)))
2024 attrs = MMPLAYER_GET_ATTRS(player);
2025 MMPLAYER_RETURN_IF_FAIL(attrs);
2027 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
2028 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
2029 LOGD("set video param : visible %d", visible);
2032 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
2034 MMHandleType attrs = 0;
2035 int display_method = 0;
2038 /* check video sinkbin is created */
2039 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2042 attrs = MMPLAYER_GET_ATTRS(player);
2043 MMPLAYER_RETURN_IF_FAIL(attrs);
2045 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2046 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2047 LOGD("set video param : method %d", display_method);
2050 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2052 MMHandleType attrs = 0;
2056 /* check video sinkbin is created */
2057 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2060 attrs = MMPLAYER_GET_ATTRS(player);
2061 MMPLAYER_RETURN_IF_FAIL(attrs);
2063 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2064 MMPLAYER_RETURN_IF_FAIL(handle);
2066 gst_video_overlay_set_video_roi_area(
2067 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2068 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2069 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2070 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2073 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2075 MMHandleType attrs = 0;
2080 int win_roi_width = 0;
2081 int win_roi_height = 0;
2084 /* check video sinkbin is created */
2085 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2088 attrs = MMPLAYER_GET_ATTRS(player);
2089 MMPLAYER_RETURN_IF_FAIL(attrs);
2091 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2092 MMPLAYER_RETURN_IF_FAIL(handle);
2094 /* It should be set after setting window */
2095 mm_attrs_multiple_get(attrs, NULL,
2096 "display_win_roi_x", &win_roi_x,
2097 "display_win_roi_y", &win_roi_y,
2098 "display_win_roi_width", &win_roi_width,
2099 "display_win_roi_height", &win_roi_height, NULL);
2101 /* After setting window handle, set display roi area */
2102 gst_video_overlay_set_display_roi_area(
2103 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2104 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2105 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2106 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2109 static void __mmplayer_video_param_set_display_overlay_sync_ui(mmplayer_t *player)
2111 MMHandleType attrs = 0;
2112 gchar *handle = NULL;
2114 /* check video sinkbin is created */
2115 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI))
2118 attrs = MMPLAYER_GET_ATTRS(player);
2119 MMPLAYER_RETURN_IF_FAIL(attrs);
2121 /* common case if using overlay surface */
2122 mm_attrs_get_string_by_name(attrs, "exported_shell_handle", &handle);
2123 MMPLAYER_RETURN_IF_FAIL(handle);
2125 gst_video_overlay_set_wl_window_exported_shell_handle(
2126 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2128 LOGD("set video param: exported_shell_handle (%s)", handle);
2131 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2133 MMHandleType attrs = 0;
2136 /* check video sinkbin is created */
2137 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2140 attrs = MMPLAYER_GET_ATTRS(player);
2141 MMPLAYER_RETURN_IF_FAIL(attrs);
2143 /* common case if using overlay surface */
2144 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2145 MMPLAYER_RETURN_IF_FAIL(handle);
2147 /* default is using wl_surface_id */
2148 LOGD("set video param : wl_surface_id %d", handle);
2149 gst_video_overlay_set_wl_window_wl_surface_id(
2150 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2155 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2157 gboolean update_all_param = FALSE;
2158 int curr_type = MM_DISPLAY_SURFACE_NUM;
2162 if (!player || !player->pipeline || !player->pipeline->mainbin || !player->pipeline->videobin ||
2163 !player->pipeline->videobin[MMPLAYER_V_BIN].gst ||
2164 !player->pipeline->videobin[MMPLAYER_V_SINK].gst) {
2165 LOGW("videosink is not ready yet");
2166 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2169 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &curr_type);
2171 if (curr_type != MM_DISPLAY_SURFACE_OVERLAY && curr_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2172 LOGE("current type(%d) is wrong", curr_type);
2173 return MM_ERROR_PLAYER_INTERNAL;
2176 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2177 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2178 return MM_ERROR_PLAYER_INTERNAL;
2181 LOGD("param_name : %s", param_name);
2182 if (!g_strcmp0(param_name, "update_all_param"))
2183 update_all_param = TRUE;
2185 if (curr_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
2186 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2188 return MM_ERROR_NONE;
2190 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2191 __mmplayer_video_param_set_display_overlay(player);
2192 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2193 __mmplayer_video_param_set_display_method(player);
2194 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2195 __mmplayer_video_param_set_display_visible(player);
2196 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2197 __mmplayer_video_param_set_display_rotation(player);
2198 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2199 __mmplayer_video_param_set_roi_area(player);
2200 if (update_all_param)
2201 __mmplayer_video_param_set_video_roi_area(player);
2204 return MM_ERROR_NONE;
2207 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2209 gboolean disable_overlay = FALSE;
2212 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2213 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2214 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2216 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2217 LOGW("Display control is not supported");
2218 return MM_ERROR_PLAYER_INTERNAL;
2221 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2223 if (disable == (bool)disable_overlay) {
2224 LOGE("It's the same with current setting: (%d)", disable);
2225 return MM_ERROR_NONE;
2229 LOGE("disable overlay");
2230 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2232 /* release overlay resource */
2233 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2234 LOGE("failed to release overlay resource");
2235 return MM_ERROR_PLAYER_INTERNAL;
2238 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2239 LOGE("failed to acquire video overlay resource");
2240 return MM_ERROR_PLAYER_INTERNAL;
2242 player->interrupted_by_resource = FALSE;
2244 LOGD("enable overlay");
2245 __mmplayer_video_param_set_display_overlay(player);
2246 __mmplayer_video_param_set_display_overlay_sync_ui(player);
2247 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2251 return MM_ERROR_NONE;
2255 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2257 int ret = MM_ERROR_NONE;
2258 mmplayer_t *player = (mmplayer_t *)hplayer;
2261 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2263 if (MMPLAYER_USE_DECODEBIN(player)) {
2264 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2269 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2270 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2271 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2273 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2275 /* release decoder resource */
2276 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2277 LOGE("failed to release video decoder resources");
2278 return MM_ERROR_PLAYER_INTERNAL;
2280 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2282 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2286 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2293 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2295 GList *bucket = element_bucket;
2296 mmplayer_gst_element_t *element = NULL;
2297 mmplayer_gst_element_t *prv_element = NULL;
2298 GstElement *tee_element = NULL;
2299 gint successful_link_count = 0;
2303 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2305 prv_element = (mmplayer_gst_element_t *)bucket->data;
2306 bucket = bucket->next;
2308 for (; bucket; bucket = bucket->next) {
2309 element = (mmplayer_gst_element_t *)bucket->data;
2311 if (element && element->gst) {
2312 if (prv_element && prv_element->gst) {
2313 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2315 prv_element->gst = tee_element;
2317 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2318 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2319 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2323 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2324 LOGD("linking [%s] to [%s] success",
2325 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2326 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2327 successful_link_count++;
2328 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2329 LOGD("keep audio-tee element for next audio pipeline branch");
2330 tee_element = prv_element->gst;
2333 LOGD("linking [%s] to [%s] failed",
2334 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2335 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2341 prv_element = element;
2346 return successful_link_count;
2350 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2352 GList *bucket = element_bucket;
2353 mmplayer_gst_element_t *element = NULL;
2354 int successful_add_count = 0;
2358 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2359 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2361 for (; bucket; bucket = bucket->next) {
2362 element = (mmplayer_gst_element_t *)bucket->data;
2364 if (element && element->gst) {
2365 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2366 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2367 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2368 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2371 successful_add_count++;
2377 return successful_add_count;
2381 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2383 mmplayer_t *player = (mmplayer_t *)data;
2384 GstCaps *caps = NULL;
2385 GstStructure *str = NULL;
2387 gboolean caps_ret = TRUE;
2391 MMPLAYER_RETURN_IF_FAIL(pad);
2392 MMPLAYER_RETURN_IF_FAIL(unused);
2393 MMPLAYER_RETURN_IF_FAIL(data);
2395 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2399 LOGD("name = %s", name);
2401 if (strstr(name, "audio")) {
2402 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2404 if (player->audio_stream_changed_cb) {
2405 LOGE("call the audio stream changed cb");
2406 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2408 } else if (strstr(name, "video")) {
2409 if ((name = gst_structure_get_string(str, "format")))
2410 player->set_mode.video_zc = name[0] == 'S';
2412 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2413 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2415 LOGW("invalid caps info");
2420 gst_caps_unref(caps);
2428 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2433 MMPLAYER_RETURN_IF_FAIL(player);
2435 if (player->audio_stream_buff_list) {
2436 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2437 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2440 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2441 __mmplayer_audio_stream_send_data(player, tmp);
2443 MMPLAYER_FREEIF(tmp->pcm_data);
2444 MMPLAYER_FREEIF(tmp);
2447 g_list_free(player->audio_stream_buff_list);
2448 player->audio_stream_buff_list = NULL;
2455 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2457 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2460 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2462 audio_stream.bitrate = a_buffer->bitrate;
2463 audio_stream.channel = a_buffer->channel;
2464 audio_stream.channel_mask = a_buffer->channel_mask;
2465 audio_stream.data_size = a_buffer->data_size;
2466 audio_stream.data = a_buffer->pcm_data;
2467 audio_stream.pcm_format = a_buffer->pcm_format;
2469 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2471 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2477 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2479 mmplayer_t *player = (mmplayer_t *)data;
2480 const gchar *pcm_format = NULL;
2483 guint64 channel_mask = 0;
2484 void *a_data = NULL;
2486 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2487 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2491 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2493 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2494 a_data = mapinfo.data;
2495 a_size = mapinfo.size;
2497 GstCaps *caps = gst_pad_get_current_caps(pad);
2498 GstStructure *structure = gst_caps_get_structure(caps, 0);
2500 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2502 pcm_format = gst_structure_get_string(structure, "format");
2503 gst_structure_get_int(structure, "rate", &rate);
2504 gst_structure_get_int(structure, "channels", &channel);
2505 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2506 gst_caps_unref(GST_CAPS(caps));
2508 /* In case of the sync is false, use buffer list. *
2509 * The num of buffer list depends on the num of audio channels */
2510 if (player->audio_stream_buff_list) {
2511 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2512 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2514 if (channel_mask == tmp->channel_mask) {
2516 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2518 if (tmp->data_size + a_size < tmp->buff_size) {
2519 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2520 tmp->data_size += a_size;
2522 /* send data to client */
2523 __mmplayer_audio_stream_send_data(player, tmp);
2525 if (a_size > tmp->buff_size) {
2526 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2527 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2528 if (tmp->pcm_data == NULL) {
2529 LOGE("failed to realloc data.");
2532 tmp->buff_size = a_size;
2534 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2535 memcpy(tmp->pcm_data, a_data, a_size);
2536 tmp->data_size = a_size;
2541 LOGE("data is empty in list.");
2547 /* create new audio stream data for newly found audio channel */
2548 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2549 if (a_buffer == NULL) {
2550 LOGE("failed to alloc data.");
2553 a_buffer->bitrate = rate;
2554 a_buffer->channel = channel;
2555 a_buffer->channel_mask = channel_mask;
2556 a_buffer->data_size = a_size;
2557 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2559 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2560 /* If sync is FALSE, use buffer list to reduce the IPC. */
2561 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2562 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2563 if (a_buffer->pcm_data == NULL) {
2564 LOGE("failed to alloc data.");
2565 MMPLAYER_FREEIF(a_buffer);
2568 memcpy(a_buffer->pcm_data, a_data, a_size);
2570 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2572 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2574 /* If sync is TRUE, send data directly. */
2575 a_buffer->pcm_data = a_data;
2576 __mmplayer_audio_stream_send_data(player, a_buffer);
2577 MMPLAYER_FREEIF(a_buffer);
2581 gst_buffer_unmap(buffer, &mapinfo);
2586 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2588 mmplayer_t *player = (mmplayer_t *)data;
2589 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2590 GstPad *sinkpad = NULL;
2591 GstElement *queue = NULL, *sink = NULL;
2594 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2596 queue = gst_element_factory_make("queue", NULL);
2597 if (queue == NULL) {
2598 LOGD("fail make queue");
2602 sink = gst_element_factory_make("fakesink", NULL);
2604 LOGD("fail make fakesink");
2608 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2610 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2611 LOGW("failed to link queue & sink");
2615 sinkpad = gst_element_get_static_pad(queue, "sink");
2617 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2618 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2622 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2624 gst_object_unref(sinkpad);
2625 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2626 g_object_set(sink, "sync", TRUE, NULL);
2627 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2629 /* keep the first sink reference only */
2630 if (!audiobin[MMPLAYER_A_SINK].gst) {
2631 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2632 audiobin[MMPLAYER_A_SINK].gst = sink;
2636 _mmplayer_add_signal_connection(player,
2638 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2640 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2643 __mmplayer_add_sink(player, sink, FALSE);
2645 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2646 LOGE("failed to sync state");
2650 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2651 LOGE("failed to sync state");
2659 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2661 gst_object_unref(GST_OBJECT(queue));
2665 gst_object_unref(GST_OBJECT(sink));
2669 gst_object_unref(GST_OBJECT(sinkpad));
2677 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2679 mmplayer_t *player = (mmplayer_t *)data;
2682 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2684 player->no_more_pad = TRUE;
2685 _mmplayer_pipeline_complete(NULL, player);
2692 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2694 #define MAX_PROPS_LEN 128
2695 mmplayer_gst_element_t *audiobin = NULL;
2696 gint latency_mode = 0;
2697 gchar *stream_type = NULL;
2698 gchar *latency = NULL;
2700 gchar stream_props[MAX_PROPS_LEN] = {0,};
2701 GstStructure *props = NULL;
2704 * It should be set after player creation through attribute.
2705 * But, it can not be changed during playing.
2708 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2710 audiobin = player->pipeline->audiobin;
2712 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2713 if (player->sound.mute) {
2714 LOGD("mute enabled");
2715 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2718 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2719 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2722 snprintf(stream_props, sizeof(stream_props) - 1,
2723 "props,application.process.id.origin=%d", player->client_pid);
2725 snprintf(stream_props, sizeof(stream_props) - 1,
2726 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2727 stream_type, stream_id, player->client_pid);
2729 props = gst_structure_from_string(stream_props, NULL);
2730 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2731 LOGI("props result[%s].", stream_props);
2732 gst_structure_free(props);
2734 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2736 switch (latency_mode) {
2737 case AUDIO_LATENCY_MODE_LOW:
2738 latency = g_strdup("low");
2740 case AUDIO_LATENCY_MODE_MID:
2741 latency = g_strdup("mid");
2743 case AUDIO_LATENCY_MODE_HIGH:
2744 latency = g_strdup("high");
2747 latency = g_strdup("mid");
2751 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2753 LOGD("audiosink property - latency=%s", latency);
2755 MMPLAYER_FREEIF(latency);
2761 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2763 mmplayer_gst_element_t *audiobin = NULL;
2766 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2767 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2769 audiobin = player->pipeline->audiobin;
2771 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2772 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2773 LOGE("failed to create media stream info");
2774 return MM_ERROR_PLAYER_INTERNAL;
2777 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2779 if (player->video360_yaw_radians <= M_PI &&
2780 player->video360_yaw_radians >= -M_PI &&
2781 player->video360_pitch_radians <= M_PI_2 &&
2782 player->video360_pitch_radians >= -M_PI_2) {
2783 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2784 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2785 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2786 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2787 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2788 "source-orientation-y", player->video360_metadata.init_view_heading,
2789 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2793 return MM_ERROR_NONE;
2797 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2799 mmplayer_gst_element_t *audiobin = NULL;
2800 GstPad *sink_pad = NULL;
2801 GstCaps *acaps = NULL;
2803 int pitch_control = 0;
2804 double pitch_value = 1.0;
2807 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2808 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2810 audiobin = player->pipeline->audiobin;
2812 LOGD("make element for normal audio playback");
2814 /* audio bin structure for playback. {} means optional.
2815 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2817 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2818 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2821 /* for pitch control */
2822 mm_attrs_multiple_get(player->attrs, NULL,
2823 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2824 MM_PLAYER_PITCH_VALUE, &pitch_value,
2827 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2828 if (pitch_control && (player->videodec_linked == 0)) {
2829 GstElementFactory *factory;
2831 factory = gst_element_factory_find("pitch");
2833 gst_object_unref(factory);
2836 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2839 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2840 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2842 LOGW("there is no pitch element");
2847 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2849 /* replaygain volume */
2850 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2851 if (player->sound.rg_enable)
2852 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2854 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2857 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2859 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2860 /* currently, only openalsink uses volume element */
2861 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2862 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2864 if (player->sound.mute) {
2865 LOGD("mute enabled");
2866 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2870 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2872 /* audio effect element. if audio effect is enabled */
2873 if ((strcmp(player->ini.audioeffect_element, ""))
2875 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2876 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2878 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2880 if ((!player->bypass_audio_effect)
2881 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2882 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2883 if (!_mmplayer_audio_effect_custom_apply(player))
2884 LOGI("apply audio effect(custom) setting success");
2888 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2889 && (player->set_mode.rich_audio)) {
2890 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2894 /* create audio sink */
2895 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2896 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2897 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2899 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2900 if (player->is_360_feature_enabled &&
2901 player->is_content_spherical &&
2903 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2904 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2905 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2907 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2909 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2911 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2912 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2913 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2914 gst_caps_unref(acaps);
2916 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2918 player->is_openal_plugin_used = TRUE;
2920 if (player->is_360_feature_enabled && player->is_content_spherical)
2921 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2922 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2925 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2926 (player->videodec_linked && player->ini.use_system_clock)) {
2927 LOGD("system clock will be used.");
2928 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2931 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2932 __mmplayer_gst_set_pulsesink_property(player);
2933 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2934 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2939 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2940 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2942 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2943 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2944 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2945 gst_object_unref(GST_OBJECT(sink_pad));
2947 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2950 return MM_ERROR_NONE;
2952 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2954 return MM_ERROR_PLAYER_INTERNAL;
2958 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2960 mmplayer_gst_element_t *audiobin = NULL;
2961 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2963 gchar *dst_format = NULL;
2965 int dst_samplerate = 0;
2966 int dst_channels = 0;
2967 GstCaps *caps = NULL;
2968 char *caps_str = NULL;
2971 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2972 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2974 audiobin = player->pipeline->audiobin;
2976 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2978 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2980 [case 1] extract interleave audio pcm without playback
2981 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2982 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2984 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2986 [case 2] deinterleave for each channel without playback
2987 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2988 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2990 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2991 - fakesink (sync or not)
2994 [case 3] [case 1(sync only)] + playback
2995 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2997 * src - ... - tee - queue1 - playback path
2998 - queue2 - [case1 pipeline with sync]
3000 [case 4] [case 2(sync only)] + playback
3001 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
3003 * src - ... - tee - queue1 - playback path
3004 - queue2 - [case2 pipeline with sync]
3008 /* 1. create tee and playback path
3009 'tee' should be added at first to copy the decoded stream
3011 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
3012 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
3013 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
3015 /* tee - path 1 : for playback path */
3016 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
3017 __mmplayer_gst_make_audio_playback_sink(player, bucket);
3019 /* tee - path 2 : for extract path */
3020 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
3021 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
3024 /* if there is tee, 'tee - path 2' is linked here */
3026 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
3029 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
3031 /* 2. decide the extract pcm format */
3032 mm_attrs_multiple_get(player->attrs, NULL,
3033 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
3034 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
3035 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
3038 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
3039 dst_format, dst_len, dst_samplerate, dst_channels);
3041 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
3042 mm_attrs_multiple_get(player->attrs, NULL,
3043 "content_audio_format", &dst_format, &dst_len, /* get string and len */
3044 "content_audio_samplerate", &dst_samplerate,
3045 "content_audio_channels", &dst_channels,
3048 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
3049 dst_format, dst_len, dst_samplerate, dst_channels);
3051 /* If there is no enough information, set it to platform default value. */
3052 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
3053 LOGD("set platform default format");
3054 dst_format = DEFAULT_PCM_OUT_FORMAT;
3056 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
3057 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
3060 /* 3. create capsfilter */
3061 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
3062 caps = gst_caps_new_simple("audio/x-raw",
3063 "format", G_TYPE_STRING, dst_format,
3064 "rate", G_TYPE_INT, dst_samplerate,
3065 "channels", G_TYPE_INT, dst_channels,
3068 caps_str = gst_caps_to_string(caps);
3069 LOGD("new caps : %s", caps_str);
3071 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
3074 gst_caps_unref(caps);
3075 MMPLAYER_FREEIF(caps_str);
3077 /* 4-1. create deinterleave to extract pcm for each channel */
3078 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3079 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3080 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3082 /* audiosink will be added after getting signal for each channel */
3083 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3084 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3085 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3086 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3087 player->no_more_pad = FALSE;
3089 /* 4-2. create fakesink to extract interleaved pcm */
3090 LOGD("add audio fakesink for interleaved audio");
3091 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3092 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3093 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3094 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3096 _mmplayer_add_signal_connection(player,
3097 G_OBJECT(audiobin[extract_sink_id].gst),
3098 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3100 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3103 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3107 return MM_ERROR_NONE;
3109 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3111 return MM_ERROR_PLAYER_INTERNAL;
3115 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3117 int ret = MM_ERROR_NONE;
3118 mmplayer_gst_element_t *audiobin = NULL;
3119 GList *element_bucket = NULL;
3122 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3123 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3125 audiobin = player->pipeline->audiobin;
3127 if (player->build_audio_offload) { /* skip all the audio filters */
3128 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3130 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3131 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3132 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3134 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3138 /* FIXME: need to mention the supportable condition at API reference */
3139 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3140 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3142 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3144 if (ret != MM_ERROR_NONE)
3147 LOGD("success to make audio bin element");
3148 *bucket = element_bucket;
3151 return MM_ERROR_NONE;
3154 LOGE("failed to make audio bin element");
3155 g_list_free(element_bucket);
3159 return MM_ERROR_PLAYER_INTERNAL;
3163 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3165 mmplayer_gst_element_t *first_element = NULL;
3166 mmplayer_gst_element_t *audiobin = NULL;
3168 GstPad *ghostpad = NULL;
3169 GList *element_bucket = NULL;
3173 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3176 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3178 LOGE("failed to allocate memory for audiobin");
3179 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3183 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3184 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3185 if (!audiobin[MMPLAYER_A_BIN].gst) {
3186 LOGE("failed to create audiobin");
3191 player->pipeline->audiobin = audiobin;
3193 /* create audio filters and audiosink */
3194 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3197 /* adding created elements to bin */
3198 LOGD("adding created elements to bin");
3199 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3202 /* linking elements in the bucket by added order. */
3203 LOGD("Linking elements in the bucket by added order.");
3204 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3207 /* get first element's sinkpad for creating ghostpad */
3208 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3209 if (!first_element) {
3210 LOGE("failed to get first elem");
3214 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3216 LOGE("failed to get pad from first element of audiobin");
3220 ghostpad = gst_ghost_pad_new("sink", pad);
3222 LOGE("failed to create ghostpad");
3226 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3227 LOGE("failed to add ghostpad to audiobin");
3231 gst_object_unref(pad);
3233 g_list_free(element_bucket);
3236 return MM_ERROR_NONE;
3239 LOGD("ERROR : releasing audiobin");
3242 gst_object_unref(GST_OBJECT(pad));
3245 gst_object_unref(GST_OBJECT(ghostpad));
3248 g_list_free(element_bucket);
3250 /* release element which are not added to bin */
3251 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3252 /* NOTE : skip bin */
3253 if (audiobin[i].gst) {
3254 GstObject *parent = NULL;
3255 parent = gst_element_get_parent(audiobin[i].gst);
3258 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3259 audiobin[i].gst = NULL;
3261 gst_object_unref(GST_OBJECT(parent));
3265 /* release audiobin with it's children */
3266 if (audiobin[MMPLAYER_A_BIN].gst)
3267 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3269 MMPLAYER_FREEIF(audiobin);
3271 player->pipeline->audiobin = NULL;
3273 return MM_ERROR_PLAYER_INTERNAL;
3277 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3279 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3283 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3285 int ret = MM_ERROR_NONE;
3287 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3288 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3290 MMPLAYER_VIDEO_BO_LOCK(player);
3292 if (player->video_bo_list) {
3293 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3294 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3295 if (tmp && tmp->bo == bo) {
3297 LOGD("release bo %p", bo);
3298 tbm_bo_unref(tmp->bo);
3299 MMPLAYER_VIDEO_BO_UNLOCK(player);
3300 MMPLAYER_VIDEO_BO_SIGNAL(player);
3305 /* hw codec is running or the list was reset for DRC. */
3306 LOGW("there is no bo list.");
3308 MMPLAYER_VIDEO_BO_UNLOCK(player);
3310 LOGW("failed to find bo %p", bo);
3314 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3320 tbm_bo_unref(tmp->bo);
3325 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3328 MMPLAYER_RETURN_IF_FAIL(player);
3330 MMPLAYER_VIDEO_BO_LOCK(player);
3331 if (player->video_bo_list) {
3332 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3333 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3334 player->video_bo_list = NULL;
3336 player->video_bo_size = 0;
3337 MMPLAYER_VIDEO_BO_UNLOCK(player);
3344 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3347 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3348 gboolean ret = TRUE;
3349 gint64 end_time = 0;
3351 /* check DRC, if it is, destroy the prev bo list to create again */
3352 if (player->video_bo_size != size) {
3353 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3354 __mmplayer_video_stream_destroy_bo_list(player);
3355 player->video_bo_size = size;
3358 MMPLAYER_VIDEO_BO_LOCK(player);
3360 if ((!player->video_bo_list) ||
3361 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3363 /* create bo list */
3365 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3367 if (player->video_bo_list) {
3368 /* if bo list did not created all, try it again. */
3369 idx = g_list_length(player->video_bo_list);
3370 LOGD("bo list exist(len: %d)", idx);
3373 for (; idx < player->ini.num_of_video_bo; idx++) {
3374 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3376 LOGE("Fail to alloc bo_info.");
3379 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3381 LOGE("Fail to tbm_bo_alloc.");
3382 MMPLAYER_FREEIF(bo_info);
3385 bo_info->used = FALSE;
3386 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3389 /* update video num buffers */
3390 LOGD("video_num_buffers : %d", idx);
3391 mm_player_set_attribute((MMHandleType)player, NULL,
3392 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3393 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3397 MMPLAYER_VIDEO_BO_UNLOCK(player);
3402 if (player->ini.video_bo_timeout > 0)
3403 end_time = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3406 /* get bo from list*/
3407 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3408 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3409 if (tmp && (tmp->used == FALSE)) {
3410 LOGD("found bo %p to use", tmp->bo);
3412 MMPLAYER_VIDEO_BO_UNLOCK(player);
3413 return tbm_bo_ref(tmp->bo);
3417 if (player->ini.video_bo_timeout <= 0) {
3418 MMPLAYER_VIDEO_BO_WAIT(player);
3420 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, end_time);
3422 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3428 MMPLAYER_VIDEO_BO_UNLOCK(player);
3433 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3435 mmplayer_t *player = (mmplayer_t *)data;
3437 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3439 /* send prerolled pkt */
3440 player->video_stream_prerolled = false;
3442 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3444 /* not to send prerolled pkt again */
3445 player->video_stream_prerolled = true;
3449 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3451 mmplayer_t *player = (mmplayer_t *)data;
3452 mmplayer_video_decoded_data_info_t *stream = NULL;
3453 GstMemory *mem = NULL;
3456 MMPLAYER_RETURN_IF_FAIL(player);
3457 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3459 if (player->video_stream_prerolled) {
3460 player->video_stream_prerolled = false;
3461 LOGD("skip the prerolled pkt not to send it again");
3465 /* clear stream data structure */
3466 stream = __mmplayer_create_stream_from_pad(pad);
3468 LOGE("failed to alloc stream");
3472 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3474 /* set size and timestamp */
3475 mem = gst_buffer_peek_memory(buffer, 0);
3476 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3477 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3479 /* check zero-copy */
3480 if (player->set_mode.video_zc &&
3481 player->set_mode.video_export &&
3482 gst_is_tizen_memory(mem)) {
3483 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3484 stream->internal_buffer = gst_buffer_ref(buffer);
3485 } else { /* sw codec */
3486 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3489 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3493 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3494 LOGE("failed to send video decoded data.");
3501 LOGE("release video stream resource.");
3502 if (gst_is_tizen_memory(mem)) {
3504 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3506 tbm_bo_unref(stream->bo[i]);
3509 /* unref gst buffer */
3510 if (stream->internal_buffer)
3511 gst_buffer_unref(stream->internal_buffer);
3514 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3516 MMPLAYER_FREEIF(stream);
3521 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3523 mmplayer_gst_element_t *videobin = NULL;
3526 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3528 videobin = player->pipeline->videobin;
3530 /* Set spatial media metadata and/or user settings to the element.
3532 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3533 "projection-type", player->video360_metadata.projection_type, NULL);
3535 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3536 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3538 if (player->video360_metadata.full_pano_width_pixels &&
3539 player->video360_metadata.full_pano_height_pixels &&
3540 player->video360_metadata.cropped_area_image_width &&
3541 player->video360_metadata.cropped_area_image_height) {
3542 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3543 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3544 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3545 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3546 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3547 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3548 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3552 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3553 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3554 "horizontal-fov", player->video360_horizontal_fov,
3555 "vertical-fov", player->video360_vertical_fov, NULL);
3558 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3559 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3560 "zoom", 1.0f / player->video360_zoom, NULL);
3563 if (player->video360_yaw_radians <= M_PI &&
3564 player->video360_yaw_radians >= -M_PI &&
3565 player->video360_pitch_radians <= M_PI_2 &&
3566 player->video360_pitch_radians >= -M_PI_2) {
3567 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3568 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3569 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3570 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3571 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3572 "pose-yaw", player->video360_metadata.init_view_heading,
3573 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3576 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3577 "passthrough", !player->is_video360_enabled, NULL);
3584 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3586 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3587 GList *element_bucket = NULL;
3590 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3592 /* create video360 filter */
3593 if (player->is_360_feature_enabled && player->is_content_spherical) {
3594 LOGD("create video360 element");
3595 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3596 __mmplayer_gst_set_video360_property(player);
3600 if ((surface_type != MM_DISPLAY_SURFACE_OVERLAY &&
3601 surface_type != MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) ||
3602 player->set_mode.video_zc) {
3603 LOGD("skip creating the videoconv and rotator");
3604 return MM_ERROR_NONE;
3607 /* in case of sw codec & overlay surface type, except 360 playback.
3608 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3609 LOGD("create video converter: %s", video_csc);
3610 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3613 *bucket = element_bucket;
3615 return MM_ERROR_NONE;
3617 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3618 g_list_free(element_bucket);
3622 return MM_ERROR_PLAYER_INTERNAL;
3626 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3628 gchar *factory_name = NULL;
3630 switch (surface_type) {
3631 case MM_DISPLAY_SURFACE_OVERLAY:
3633 case MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI:
3634 if (strlen(player->ini.videosink_element_overlay) > 0)
3635 factory_name = player->ini.videosink_element_overlay;
3637 case MM_DISPLAY_SURFACE_REMOTE:
3639 case MM_DISPLAY_SURFACE_NULL:
3640 if (strlen(player->ini.videosink_element_fake) > 0)
3641 factory_name = player->ini.videosink_element_fake;
3644 LOGE("unidentified surface type");
3648 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3649 return factory_name;
3653 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3655 gchar *factory_name = NULL;
3656 mmplayer_gst_element_t *videobin = NULL;
3661 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3663 videobin = player->pipeline->videobin;
3664 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3666 attrs = MMPLAYER_GET_ATTRS(player);
3668 LOGE("cannot get content attribute");
3669 return MM_ERROR_PLAYER_INTERNAL;
3672 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY || surface_type == MM_DISPLAY_SURFACE_OVERLAY_SYNC_UI) {
3673 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3674 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3675 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3676 "use-tbm", use_tbm, NULL);
3679 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3680 return MM_ERROR_PLAYER_INTERNAL;
3682 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3685 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3686 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3689 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3691 LOGD("disable last-sample");
3692 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3695 if (player->set_mode.video_export) {
3697 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3698 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3699 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3701 _mmplayer_add_signal_connection(player,
3702 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3703 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3705 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3708 _mmplayer_add_signal_connection(player,
3709 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3710 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3712 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3716 if (videobin[MMPLAYER_V_SINK].gst) {
3717 GstPad *sink_pad = NULL;
3718 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3720 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3721 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3722 gst_object_unref(GST_OBJECT(sink_pad));
3724 LOGE("failed to get sink pad from videosink");
3728 return MM_ERROR_NONE;
3733 * - video overlay surface(arm/x86) : tizenwlsink
3736 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3739 GList *element_bucket = NULL;
3740 mmplayer_gst_element_t *first_element = NULL;
3741 mmplayer_gst_element_t *videobin = NULL;
3742 gchar *videosink_factory_name = NULL;
3745 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3748 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3750 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3752 player->pipeline->videobin = videobin;
3755 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3756 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3757 if (!videobin[MMPLAYER_V_BIN].gst) {
3758 LOGE("failed to create videobin");
3762 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3765 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3766 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3768 /* additional setting for sink plug-in */
3769 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3770 LOGE("failed to set video property");
3774 /* store it as it's sink element */
3775 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3777 /* adding created elements to bin */
3778 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3779 LOGE("failed to add elements");
3783 /* Linking elements in the bucket by added order */
3784 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3785 LOGE("failed to link elements");
3789 /* get first element's sinkpad for creating ghostpad */
3790 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3791 if (!first_element) {
3792 LOGE("failed to get first element from bucket");
3796 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3798 LOGE("failed to get pad from first element");
3802 /* create ghostpad */
3803 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3804 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3805 LOGE("failed to add ghostpad to videobin");
3808 gst_object_unref(pad);
3810 /* done. free allocated variables */
3811 g_list_free(element_bucket);
3815 return MM_ERROR_NONE;
3818 LOGE("ERROR : releasing videobin");
3819 g_list_free(element_bucket);
3822 gst_object_unref(GST_OBJECT(pad));
3824 /* release videobin with it's children */
3825 if (videobin[MMPLAYER_V_BIN].gst)
3826 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3828 MMPLAYER_FREEIF(videobin);
3829 player->pipeline->videobin = NULL;
3831 return MM_ERROR_PLAYER_INTERNAL;
3835 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3837 GList *element_bucket = NULL;
3838 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3840 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3841 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3842 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3843 "signal-handoffs", FALSE,
3846 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3847 _mmplayer_add_signal_connection(player,
3848 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3849 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3851 G_CALLBACK(__mmplayer_update_subtitle),
3854 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3855 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3857 if (!player->play_subtitle) {
3858 LOGD("add textbin sink as sink element of whole pipeline.");
3859 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3862 /* adding created elements to bin */
3863 LOGD("adding created elements to bin");
3864 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3865 LOGE("failed to add elements");
3869 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3870 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3871 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3873 /* linking elements in the bucket by added order. */
3874 LOGD("Linking elements in the bucket by added order.");
3875 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3876 LOGE("failed to link elements");
3880 if (textbin[MMPLAYER_T_QUEUE].gst) {
3882 GstPad *ghostpad = NULL;
3884 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3886 LOGE("failed to get sink pad of text queue");
3890 ghostpad = gst_ghost_pad_new("text_sink", pad);
3891 gst_object_unref(pad);
3894 LOGE("failed to create ghostpad of textbin");
3898 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3899 LOGE("failed to add ghostpad to textbin");
3900 gst_object_unref(ghostpad);
3905 g_list_free(element_bucket);
3907 return MM_ERROR_NONE;
3911 g_list_free(element_bucket);
3913 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3914 LOGE("remove textbin sink from sink list");
3915 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3918 /* release element at __mmplayer_gst_create_text_sink_bin */
3919 return MM_ERROR_PLAYER_INTERNAL;
3923 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3925 mmplayer_gst_element_t *textbin = NULL;
3926 int surface_type = 0;
3931 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3934 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3936 LOGE("failed to allocate memory for textbin");
3937 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3941 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3942 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3943 if (!textbin[MMPLAYER_T_BIN].gst) {
3944 LOGE("failed to create textbin");
3949 player->pipeline->textbin = textbin;
3952 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3953 LOGD("surface type for subtitle : %d", surface_type);
3954 switch (surface_type) {
3955 case MM_DISPLAY_SURFACE_OVERLAY:
3956 case MM_DISPLAY_SURFACE_NULL:
3957 case MM_DISPLAY_SURFACE_REMOTE:
3958 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3959 LOGE("failed to make plain text elements");
3970 return MM_ERROR_NONE;
3974 LOGD("ERROR : releasing textbin");
3976 /* release signal */
3977 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3979 /* release element which are not added to bin */
3980 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3981 /* NOTE : skip bin */
3982 if (textbin[i].gst) {
3983 GstObject *parent = NULL;
3984 parent = gst_element_get_parent(textbin[i].gst);
3987 gst_object_unref(GST_OBJECT(textbin[i].gst));
3988 textbin[i].gst = NULL;
3990 gst_object_unref(GST_OBJECT(parent));
3995 /* release textbin with it's children */
3996 if (textbin[MMPLAYER_T_BIN].gst)
3997 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3999 MMPLAYER_FREEIF(textbin);
4000 player->pipeline->textbin = NULL;
4003 return MM_ERROR_PLAYER_INTERNAL;
4007 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
4009 mmplayer_gst_element_t *mainbin = NULL;
4010 mmplayer_gst_element_t *textbin = NULL;
4011 MMHandleType attrs = 0;
4012 GstElement *subsrc = NULL;
4013 GstElement *subparse = NULL;
4014 gchar *subtitle_uri = NULL;
4015 const gchar *charset = NULL;
4021 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
4023 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
4025 mainbin = player->pipeline->mainbin;
4027 attrs = MMPLAYER_GET_ATTRS(player);
4029 LOGE("cannot get content attribute");
4030 return MM_ERROR_PLAYER_INTERNAL;
4033 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
4034 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
4035 LOGE("subtitle uri is not proper filepath.");
4036 return MM_ERROR_PLAYER_INVALID_URI;
4039 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
4040 LOGE("failed to get storage info of subtitle path");
4041 return MM_ERROR_PLAYER_INVALID_URI;
4044 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
4046 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4047 player->subtitle_language_list = NULL;
4048 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4050 /* create the subtitle source */
4051 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
4053 LOGE("failed to create filesrc element");
4056 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
4058 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
4059 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
4061 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
4062 LOGW("failed to add queue");
4063 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
4064 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
4065 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
4070 subparse = gst_element_factory_make("subparse", "subtitle_parser");
4072 LOGE("failed to create subparse element");
4076 charset = _mmplayer_get_charset(subtitle_uri);
4078 LOGD("detected charset is %s", charset);
4079 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4082 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4083 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4085 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4086 LOGW("failed to add subparse");
4087 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4088 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4089 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4093 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4094 LOGW("failed to link subsrc and subparse");
4098 player->play_subtitle = TRUE;
4099 player->adjust_subtitle_pos = 0;
4101 LOGD("play subtitle using subtitle file");
4103 if (player->pipeline->textbin == NULL) {
4104 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4105 LOGE("failed to create text sink bin. continuing without text");
4109 textbin = player->pipeline->textbin;
4111 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4112 LOGW("failed to add textbin");
4114 /* release signal */
4115 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4117 /* release textbin with it's children */
4118 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4119 MMPLAYER_FREEIF(player->pipeline->textbin);
4120 player->pipeline->textbin = textbin = NULL;
4124 LOGD("link text input selector and textbin ghost pad");
4126 player->textsink_linked = 1;
4127 player->external_text_idx = 0;
4128 LOGI("textsink is linked");
4130 textbin = player->pipeline->textbin;
4131 LOGD("text bin has been created. reuse it.");
4132 player->external_text_idx = 1;
4135 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4136 LOGW("failed to link subparse and textbin");
4140 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4142 LOGE("failed to get sink pad from textsink to probe data");
4146 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4147 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4149 gst_object_unref(pad);
4152 /* create dot. for debugging */
4153 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4156 return MM_ERROR_NONE;
4159 /* release text pipeline resource */
4160 player->textsink_linked = 0;
4162 /* release signal */
4163 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4165 if (player->pipeline->textbin) {
4166 LOGE("remove textbin");
4168 /* release textbin with it's children */
4169 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4170 MMPLAYER_FREEIF(player->pipeline->textbin);
4171 player->pipeline->textbin = NULL;
4175 /* release subtitle elem */
4176 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4177 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4179 return MM_ERROR_PLAYER_INTERNAL;
4183 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4185 mmplayer_t *player = (mmplayer_t *)data;
4186 MMMessageParamType msg = {0, };
4187 GstClockTime duration = 0;
4188 gpointer text = NULL;
4189 guint text_size = 0;
4190 gboolean ret = TRUE;
4191 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4195 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4196 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4198 if (player->is_subtitle_force_drop) {
4199 LOGW("subtitle is dropped forcedly.");
4203 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4204 text = mapinfo.data;
4205 text_size = mapinfo.size;
4207 if (player->set_mode.subtitle_off) {
4208 LOGD("subtitle is OFF.");
4212 if (!text || (text_size == 0)) {
4213 LOGD("There is no subtitle to be displayed.");
4217 msg.data = (void *)text;
4219 duration = GST_BUFFER_DURATION(buffer);
4221 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4222 if (player->duration > GST_BUFFER_PTS(buffer))
4223 duration = player->duration - GST_BUFFER_PTS(buffer);
4226 LOGI("subtitle duration is invalid, subtitle duration change "
4227 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4229 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4231 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4233 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4234 gst_buffer_unmap(buffer, &mapinfo);
4241 static GstPadProbeReturn
4242 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4244 mmplayer_t *player = (mmplayer_t *)u_data;
4245 GstClockTime cur_timestamp = 0;
4246 gint64 adjusted_timestamp = 0;
4247 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4249 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4251 if (player->set_mode.subtitle_off) {
4252 LOGD("subtitle is OFF.");
4256 if (player->adjust_subtitle_pos == 0) {
4257 LOGD("nothing to do");
4261 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4262 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4264 if (adjusted_timestamp < 0) {
4265 LOGD("adjusted_timestamp under zero");
4270 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4271 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4272 GST_TIME_ARGS(cur_timestamp),
4273 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4275 return GST_PAD_PROBE_OK;
4279 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4283 /* check player and subtitlebin are created */
4284 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4285 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4287 if (position == 0) {
4288 LOGD("nothing to do");
4290 return MM_ERROR_NONE;
4293 /* check current position */
4294 player->adjust_subtitle_pos = position;
4296 LOGD("save adjust_subtitle_pos in player");
4300 return MM_ERROR_NONE;
4304 * This function is to create audio or video pipeline for playing.
4306 * @param player [in] handle of player
4308 * @return This function returns zero on success.
4313 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4315 int ret = MM_ERROR_NONE;
4316 mmplayer_gst_element_t *mainbin = NULL;
4317 MMHandleType attrs = 0;
4320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4322 /* get profile attribute */
4323 attrs = MMPLAYER_GET_ATTRS(player);
4325 LOGE("failed to get content attribute");
4329 /* create pipeline handles */
4330 if (player->pipeline) {
4331 LOGE("pipeline should be released before create new one");
4335 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4337 /* create mainbin */
4338 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4339 if (mainbin == NULL)
4342 /* create pipeline */
4343 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4344 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4345 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4346 LOGE("failed to create pipeline");
4351 player->pipeline->mainbin = mainbin;
4353 /* create the source and decoder elements */
4354 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4355 ret = _mmplayer_gst_build_es_pipeline(player);
4357 if (MMPLAYER_USE_DECODEBIN(player))
4358 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4360 ret = _mmplayer_gst_build_pipeline_with_src(player);
4363 if (ret != MM_ERROR_NONE) {
4364 LOGE("failed to create some elements");
4368 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4369 if (__mmplayer_check_subtitle(player)
4370 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4371 LOGE("failed to create text pipeline");
4374 ret = _mmplayer_gst_add_bus_watch(player);
4375 if (ret != MM_ERROR_NONE) {
4376 LOGE("failed to add bus watch");
4381 return MM_ERROR_NONE;
4384 _mmplayer_bus_watcher_remove(player);
4385 __mmplayer_gst_destroy_pipeline(player);
4386 return MM_ERROR_PLAYER_INTERNAL;
4390 __mmplayer_reset_gapless_state(mmplayer_t *player)
4393 MMPLAYER_RETURN_IF_FAIL(player
4395 && player->pipeline->audiobin
4396 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4398 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4405 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4408 int ret = MM_ERROR_NONE;
4412 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4414 /* cleanup stuffs */
4415 MMPLAYER_FREEIF(player->type);
4416 player->no_more_pad = FALSE;
4417 player->num_dynamic_pad = 0;
4419 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4420 player->subtitle_language_list = NULL;
4421 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4423 MMPLAYER_RECONFIGURE_LOCK(player);
4424 __mmplayer_reset_gapless_state(player);
4425 MMPLAYER_RECONFIGURE_UNLOCK(player);
4427 if (player->streamer) {
4428 _mm_player_streaming_initialize(player->streamer, FALSE);
4429 _mm_player_streaming_destroy(player->streamer);
4430 player->streamer = NULL;
4433 /* cleanup unlinked mime type */
4434 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4435 MMPLAYER_FREEIF(player->unlinked_video_mime);
4436 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4438 /* cleanup running stuffs */
4439 _mmplayer_cancel_eos_timer(player);
4441 /* cleanup gst stuffs */
4442 if (player->pipeline) {
4443 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4444 GstTagList *tag_list = player->pipeline->tag_list;
4446 /* first we need to disconnect all signal hander */
4447 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4450 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4451 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4452 gst_object_unref(bus);
4454 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4455 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4456 if (ret != MM_ERROR_NONE) {
4457 LOGE("fail to change state to NULL");
4458 return MM_ERROR_PLAYER_INTERNAL;
4461 LOGW("succeeded in changing state to NULL");
4463 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4466 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4467 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4469 MMPLAYER_FREEIF(player->pipeline->audiobin);
4470 MMPLAYER_FREEIF(player->pipeline->videobin);
4471 MMPLAYER_FREEIF(player->pipeline->textbin);
4472 MMPLAYER_FREEIF(mainbin);
4476 gst_tag_list_unref(tag_list);
4478 MMPLAYER_FREEIF(player->pipeline);
4480 MMPLAYER_FREEIF(player->album_art);
4482 if (player->type_caps) {
4483 gst_caps_unref(player->type_caps);
4484 player->type_caps = NULL;
4487 if (player->v_stream_caps) {
4488 gst_caps_unref(player->v_stream_caps);
4489 player->v_stream_caps = NULL;
4492 if (player->a_stream_caps) {
4493 gst_caps_unref(player->a_stream_caps);
4494 player->a_stream_caps = NULL;
4497 if (player->s_stream_caps) {
4498 gst_caps_unref(player->s_stream_caps);
4499 player->s_stream_caps = NULL;
4501 _mmplayer_track_destroy(player);
4503 if (player->sink_elements)
4504 g_list_free(player->sink_elements);
4505 player->sink_elements = NULL;
4507 if (player->bufmgr) {
4508 tbm_bufmgr_deinit(player->bufmgr);
4509 player->bufmgr = NULL;
4512 LOGW("finished destroy pipeline");
4520 __mmplayer_gst_realize(mmplayer_t *player)
4523 int ret = MM_ERROR_NONE;
4527 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4529 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4531 ret = __mmplayer_gst_create_pipeline(player);
4533 LOGE("failed to create pipeline");
4537 /* set pipeline state to READY */
4538 /* NOTE : state change to READY must be performed sync. */
4539 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4540 ret = _mmplayer_gst_set_state(player,
4541 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4543 if (ret != MM_ERROR_NONE) {
4544 /* return error if failed to set state */
4545 LOGE("failed to set READY state");
4549 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4551 /* create dot before error-return. for debugging */
4552 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4560 __mmplayer_gst_unrealize(mmplayer_t *player)
4562 int ret = MM_ERROR_NONE;
4566 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4568 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4569 MMPLAYER_PRINT_STATE(player);
4571 /* release miscellaneous information */
4572 __mmplayer_release_misc(player);
4574 /* destroy pipeline */
4575 ret = __mmplayer_gst_destroy_pipeline(player);
4576 if (ret != MM_ERROR_NONE) {
4577 LOGE("failed to destroy pipeline");
4581 /* release miscellaneous information.
4582 these info needs to be released after pipeline is destroyed. */
4583 __mmplayer_release_misc_post(player);
4585 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4593 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4598 LOGW("set_message_callback is called with invalid player handle");
4599 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4602 player->msg_cb = callback;
4603 player->msg_cb_param = user_param;
4605 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4609 return MM_ERROR_NONE;
4613 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4615 int ret = MM_ERROR_NONE;
4620 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4621 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4622 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4624 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4626 if (strstr(uri, "es_buff://")) {
4627 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4628 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4629 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4630 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4632 tmp = g_ascii_strdown(uri, strlen(uri));
4633 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4634 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4636 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4638 } else if (strstr(uri, "mms://")) {
4639 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4640 } else if ((path = strstr(uri, "mem://"))) {
4641 ret = __mmplayer_set_mem_uri(data, path, param);
4643 ret = __mmplayer_set_file_uri(data, uri);
4646 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4647 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4648 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4649 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4651 /* dump parse result */
4652 SECURE_LOGW("incoming uri : %s", uri);
4653 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4654 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4662 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4665 mmplayer_t *player = NULL;
4666 MMMessageParamType msg = {0, };
4668 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4673 LOGE("user_data is null");
4677 player = (mmplayer_t *)user_data;
4679 if (!player->pipeline || !player->attrs) {
4680 LOGW("not initialized");
4684 LOGD("cmd lock player, cmd state : %d", player->cmd);
4685 MMPLAYER_CMD_LOCK(player);
4686 LOGD("cmd locked player");
4688 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4689 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4690 LOGW("player already destroyed");
4691 MMPLAYER_CMD_UNLOCK(player);
4695 player->interrupted_by_resource = TRUE;
4697 MMPLAYER_POST_MSG(player, MM_MESSAGE_INTERRUPT_STARTED, NULL);
4699 /* get last play position */
4700 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4701 msg.union_type = MM_MSG_UNION_TIME;
4702 msg.time.elapsed = pos;
4703 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4705 LOGW("failed to get play position.");
4708 LOGD("video resource conflict so, resource will be freed by unrealizing");
4709 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4710 LOGE("failed to unrealize");
4712 MMPLAYER_CMD_UNLOCK(player);
4714 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4715 player->hw_resource[res_idx] = NULL;
4719 return TRUE; /* release all the resources */
4723 __mmplayer_initialize_video_roi(mmplayer_t *player)
4725 player->video_roi.scale_x = 0.0;
4726 player->video_roi.scale_y = 0.0;
4727 player->video_roi.scale_width = 1.0;
4728 player->video_roi.scale_height = 1.0;
4732 _mmplayer_create_player(MMHandleType handle)
4734 int ret = MM_ERROR_PLAYER_INTERNAL;
4735 bool enabled = false;
4737 mmplayer_t *player = MM_PLAYER_CAST(handle);
4741 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4743 /* initialize player state */
4744 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4745 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4746 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4747 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4749 /* check current state */
4750 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4752 /* construct attributes */
4753 player->attrs = _mmplayer_construct_attribute(handle);
4755 if (!player->attrs) {
4756 LOGE("Failed to construct attributes");
4760 /* initialize gstreamer with configured parameter */
4761 if (!__mmplayer_init_gstreamer(player)) {
4762 LOGE("Initializing gstreamer failed");
4763 _mmplayer_deconstruct_attribute(handle);
4767 /* create lock. note that g_tread_init() has already called in gst_init() */
4768 g_mutex_init(&player->fsink_lock);
4770 /* create update tag lock */
4771 g_mutex_init(&player->update_tag_lock);
4773 /* create gapless play mutex */
4774 g_mutex_init(&player->gapless_play_thread_mutex);
4776 /* create gapless play cond */
4777 g_cond_init(&player->gapless_play_thread_cond);
4779 /* create gapless play thread */
4780 player->gapless_play_thread =
4781 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4782 if (!player->gapless_play_thread) {
4783 LOGE("failed to create gapless play thread");
4784 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4785 g_mutex_clear(&player->gapless_play_thread_mutex);
4786 g_cond_clear(&player->gapless_play_thread_cond);
4790 player->bus_msg_q = g_queue_new();
4791 if (!player->bus_msg_q) {
4792 LOGE("failed to create queue for bus_msg");
4793 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4797 ret = _mmplayer_initialize_video_capture(player);
4798 if (ret != MM_ERROR_NONE) {
4799 LOGW("video capture is not supported");
4800 /* do not handle as error for headless profile */
4803 /* initialize resource manager */
4804 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4805 __resource_release_cb, player, &player->resource_manager)
4806 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4807 LOGE("failed to create resource manager");
4808 ret = MM_ERROR_PLAYER_INTERNAL;
4812 /* create video bo lock and cond */
4813 g_mutex_init(&player->video_bo_mutex);
4814 g_cond_init(&player->video_bo_cond);
4816 /* create subtitle info lock and cond */
4817 g_mutex_init(&player->subtitle_info_mutex);
4818 g_cond_init(&player->subtitle_info_cond);
4820 player->streaming_type = STREAMING_SERVICE_NONE;
4822 /* give default value of audio effect setting */
4823 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4824 player->sound.rg_enable = false;
4825 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4827 player->play_subtitle = FALSE;
4828 player->has_closed_caption = FALSE;
4829 player->pending_resume = FALSE;
4830 if (player->ini.dump_element_keyword[0][0] == '\0')
4831 player->ini.set_dump_element_flag = FALSE;
4833 player->ini.set_dump_element_flag = TRUE;
4835 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4836 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4837 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4839 /* Set video360 settings to their defaults for just-created player.
4842 player->is_360_feature_enabled = FALSE;
4843 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4844 LOGI("spherical feature info: %d", enabled);
4846 player->is_360_feature_enabled = TRUE;
4848 LOGE("failed to get spherical feature info");
4851 player->is_content_spherical = FALSE;
4852 player->is_video360_enabled = TRUE;
4853 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4854 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4855 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4856 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4857 player->video360_zoom = 1.0f;
4858 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4859 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4861 __mmplayer_initialize_video_roi(player);
4863 /* set player state to null */
4864 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4865 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4869 return MM_ERROR_NONE;
4873 g_mutex_clear(&player->fsink_lock);
4874 /* free update tag lock */
4875 g_mutex_clear(&player->update_tag_lock);
4876 g_queue_free(player->bus_msg_q);
4877 player->bus_msg_q = NULL;
4878 /* free gapless play thread */
4879 if (player->gapless_play_thread) {
4880 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4881 player->gapless_play_thread_exit = TRUE;
4882 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4883 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4885 g_thread_join(player->gapless_play_thread);
4886 player->gapless_play_thread = NULL;
4888 g_mutex_clear(&player->gapless_play_thread_mutex);
4889 g_cond_clear(&player->gapless_play_thread_cond);
4892 /* release attributes */
4893 _mmplayer_deconstruct_attribute(handle);
4901 __mmplayer_init_gstreamer(mmplayer_t *player)
4903 static gboolean initialized = FALSE;
4904 static const int max_argc = 50;
4906 gchar **argv = NULL;
4907 gchar **argv2 = NULL;
4913 LOGD("gstreamer already initialized.");
4918 argc = malloc(sizeof(int));
4919 argv = malloc(sizeof(gchar *) * max_argc);
4920 argv2 = malloc(sizeof(gchar *) * max_argc);
4922 if (!argc || !argv || !argv2)
4925 memset(argv, 0, sizeof(gchar *) * max_argc);
4926 memset(argv2, 0, sizeof(gchar *) * max_argc);
4930 argv[0] = g_strdup("mmplayer");
4933 for (i = 0; i < 5; i++) {
4934 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4935 if (strlen(player->ini.gst_param[i]) > 0) {
4936 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4941 /* we would not do fork for scanning plugins */
4942 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4945 /* check disable registry scan */
4946 if (player->ini.skip_rescan) {
4947 argv[*argc] = g_strdup("--gst-disable-registry-update");
4951 /* check disable segtrap */
4952 if (player->ini.disable_segtrap) {
4953 argv[*argc] = g_strdup("--gst-disable-segtrap");
4957 LOGD("initializing gstreamer with following parameter");
4958 LOGD("argc : %d", *argc);
4961 for (i = 0; i < arg_count; i++) {
4963 LOGD("argv[%d] : %s", i, argv2[i]);
4966 /* initializing gstreamer */
4967 if (!gst_init_check(argc, &argv, &err)) {
4968 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4975 for (i = 0; i < arg_count; i++) {
4977 LOGD("release - argv[%d] : %s", i, argv2[i]);
4979 MMPLAYER_FREEIF(argv2[i]);
4982 MMPLAYER_FREEIF(argv);
4983 MMPLAYER_FREEIF(argv2);
4984 MMPLAYER_FREEIF(argc);
4994 for (i = 0; i < arg_count; i++) {
4995 LOGD("free[%d] : %s", i, argv2[i]);
4996 MMPLAYER_FREEIF(argv2[i]);
4999 MMPLAYER_FREEIF(argv);
5000 MMPLAYER_FREEIF(argv2);
5001 MMPLAYER_FREEIF(argc);
5007 __mmplayer_check_async_state_transition(mmplayer_t *player)
5009 GstState element_state = GST_STATE_VOID_PENDING;
5010 GstState element_pending_state = GST_STATE_VOID_PENDING;
5011 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
5012 GstElement *element = NULL;
5013 gboolean async = FALSE;
5015 /* check player handle */
5016 MMPLAYER_RETURN_IF_FAIL(player &&
5018 player->pipeline->mainbin &&
5019 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
5022 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5024 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
5025 LOGD("don't need to check the pipeline state");
5029 MMPLAYER_PRINT_STATE(player);
5031 /* wait for state transition */
5032 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
5033 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
5035 if (ret == GST_STATE_CHANGE_FAILURE) {
5036 LOGE(" [%s] state : %s pending : %s",
5037 GST_ELEMENT_NAME(element),
5038 gst_element_state_get_name(element_state),
5039 gst_element_state_get_name(element_pending_state));
5041 /* dump state of all element */
5042 _mmplayer_dump_pipeline_state(player);
5047 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
5052 _mmplayer_destroy(MMHandleType handle)
5054 mmplayer_t *player = MM_PLAYER_CAST(handle);
5058 /* check player handle */
5059 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5061 /* destroy can called at anytime */
5062 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
5064 /* check async state transition */
5065 __mmplayer_check_async_state_transition(player);
5067 /* release gapless play thread */
5068 if (player->gapless_play_thread) {
5069 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
5070 player->gapless_play_thread_exit = TRUE;
5071 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
5072 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5074 LOGD("waiting for gapless play thread exit");
5075 g_thread_join(player->gapless_play_thread);
5076 g_mutex_clear(&player->gapless_play_thread_mutex);
5077 g_cond_clear(&player->gapless_play_thread_cond);
5078 LOGD("gapless play thread released");
5081 _mmplayer_release_video_capture(player);
5083 /* release miscellaneous information */
5084 __mmplayer_release_misc(player);
5086 /* release pipeline */
5087 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5088 LOGE("failed to destroy pipeline");
5089 return MM_ERROR_PLAYER_INTERNAL;
5092 __mmplayer_destroy_hw_resource(player);
5094 g_queue_free(player->bus_msg_q);
5096 /* release subtitle info lock and cond */
5097 g_mutex_clear(&player->subtitle_info_mutex);
5098 g_cond_clear(&player->subtitle_info_cond);
5100 __mmplayer_release_dump_list(player->dump_list);
5102 /* release miscellaneous information.
5103 these info needs to be released after pipeline is destroyed. */
5104 __mmplayer_release_misc_post(player);
5106 /* release attributes */
5107 _mmplayer_deconstruct_attribute(handle);
5109 if (player->uri_info.uri_list) {
5110 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5111 player->uri_info.uri_list = NULL;
5115 g_mutex_clear(&player->fsink_lock);
5118 g_mutex_clear(&player->update_tag_lock);
5120 /* release video bo lock and cond */
5121 g_mutex_clear(&player->video_bo_mutex);
5122 g_cond_clear(&player->video_bo_cond);
5126 return MM_ERROR_NONE;
5130 _mmplayer_realize(MMHandleType hplayer)
5132 mmplayer_t *player = (mmplayer_t *)hplayer;
5133 int ret = MM_ERROR_NONE;
5136 MMHandleType attrs = 0;
5140 /* check player handle */
5141 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5143 /* check current state */
5144 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5146 attrs = MMPLAYER_GET_ATTRS(player);
5148 LOGE("fail to get attributes.");
5149 return MM_ERROR_PLAYER_INTERNAL;
5151 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5152 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5154 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5155 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5157 if (ret != MM_ERROR_NONE) {
5158 LOGE("failed to parse profile");
5163 if (uri && (strstr(uri, "es_buff://"))) {
5164 if (strstr(uri, "es_buff://push_mode"))
5165 player->es_player_push_mode = TRUE;
5167 player->es_player_push_mode = FALSE;
5170 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5171 LOGW("mms protocol is not supported format.");
5172 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5175 if (MMPLAYER_IS_STREAMING(player))
5176 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5178 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5180 player->smooth_streaming = FALSE;
5181 player->videodec_linked = 0;
5182 player->audiodec_linked = 0;
5183 player->textsink_linked = 0;
5184 player->is_external_subtitle_present = FALSE;
5185 player->is_external_subtitle_added_now = FALSE;
5186 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5187 player->video360_metadata.is_spherical = -1;
5188 player->is_openal_plugin_used = FALSE;
5189 player->subtitle_language_list = NULL;
5190 player->is_subtitle_force_drop = FALSE;
5192 _mmplayer_track_initialize(player);
5193 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5195 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5196 gint prebuffer_ms = 0, rebuffer_ms = 0;
5198 player->streamer = _mm_player_streaming_create();
5199 _mm_player_streaming_initialize(player->streamer, TRUE);
5201 mm_attrs_multiple_get(player->attrs, NULL,
5202 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5203 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5205 if (prebuffer_ms > 0) {
5206 prebuffer_ms = MAX(prebuffer_ms, 1000);
5207 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5210 if (rebuffer_ms > 0) {
5211 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5212 rebuffer_ms = MAX(rebuffer_ms, 1000);
5213 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5216 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5217 player->streamer->buffering_req.rebuffer_time);
5220 /* realize pipeline */
5221 ret = __mmplayer_gst_realize(player);
5222 if (ret != MM_ERROR_NONE)
5223 LOGE("fail to realize the player.");
5225 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5233 _mmplayer_unrealize(MMHandleType hplayer)
5235 mmplayer_t *player = (mmplayer_t *)hplayer;
5236 int ret = MM_ERROR_NONE;
5237 int rm_ret = MM_ERROR_NONE;
5238 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5242 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5244 MMPLAYER_CMD_UNLOCK(player);
5245 _mmplayer_bus_watcher_remove(player);
5246 /* destroy the gst bus msg thread which is created during realize.
5247 this funct have to be called before getting cmd lock. */
5248 _mmplayer_bus_msg_thread_destroy(player);
5249 MMPLAYER_CMD_LOCK(player);
5251 /* check current state */
5252 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5254 /* check async state transition */
5255 __mmplayer_check_async_state_transition(player);
5257 /* unrealize pipeline */
5258 ret = __mmplayer_gst_unrealize(player);
5260 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5261 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5262 if (rm_ret != MM_ERROR_NONE)
5263 LOGE("failed to release [%d] resources", res_idx);
5266 player->interrupted_by_resource = FALSE;
5273 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5275 mmplayer_t *player = (mmplayer_t *)hplayer;
5277 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5279 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5283 _mmplayer_get_state(MMHandleType hplayer, int *state)
5285 mmplayer_t *player = (mmplayer_t *)hplayer;
5287 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5289 *state = MMPLAYER_CURRENT_STATE(player);
5291 return MM_ERROR_NONE;
5295 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5297 GstElement *vol_element = NULL;
5298 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5301 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5302 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5304 /* check pipeline handle */
5305 if (!player->pipeline || !player->pipeline->audiobin) {
5306 LOGD("'%s' will be applied when audiobin is created", prop_name);
5308 /* NOTE : stored value will be used in create_audiobin
5309 * returning MM_ERROR_NONE here makes application to able to
5310 * set audio volume or mute at anytime.
5312 return MM_ERROR_NONE;
5315 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5316 volume_elem_id = MMPLAYER_A_SINK;
5318 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5320 LOGE("failed to get vol element %d", volume_elem_id);
5321 return MM_ERROR_PLAYER_INTERNAL;
5324 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5326 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5327 LOGE("there is no '%s' property", prop_name);
5328 return MM_ERROR_PLAYER_INTERNAL;
5331 if (!strcmp(prop_name, "volume")) {
5332 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5333 } else if (!strcmp(prop_name, "mute")) {
5334 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5336 LOGE("invalid property %s", prop_name);
5337 return MM_ERROR_PLAYER_INTERNAL;
5340 return MM_ERROR_NONE;
5344 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5346 int ret = MM_ERROR_NONE;
5347 mmplayer_t *player = (mmplayer_t *)hplayer;
5350 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5352 LOGD("volume = %f", volume);
5354 /* invalid factor range or not */
5355 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5356 LOGE("Invalid volume value");
5357 return MM_ERROR_INVALID_ARGUMENT;
5360 player->sound.volume = volume;
5362 ret = __mmplayer_gst_set_volume_property(player, "volume");
5369 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5371 mmplayer_t *player = (mmplayer_t *)hplayer;
5375 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5376 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5378 *volume = player->sound.volume;
5380 LOGD("current vol = %f", *volume);
5383 return MM_ERROR_NONE;
5387 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5389 int ret = MM_ERROR_NONE;
5390 mmplayer_t *player = (mmplayer_t *)hplayer;
5393 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5395 LOGD("mute = %d", mute);
5397 player->sound.mute = mute;
5399 ret = __mmplayer_gst_set_volume_property(player, "mute");
5406 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5408 mmplayer_t *player = (mmplayer_t *)hplayer;
5412 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5413 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5415 *mute = player->sound.mute;
5417 LOGD("current mute = %d", *mute);
5421 return MM_ERROR_NONE;
5425 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5427 mmplayer_t *player = (mmplayer_t *)hplayer;
5431 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5433 player->audio_stream_changed_cb = callback;
5434 player->audio_stream_changed_cb_user_param = user_param;
5435 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5439 return MM_ERROR_NONE;
5443 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5445 mmplayer_t *player = (mmplayer_t *)hplayer;
5449 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5451 player->audio_decoded_cb = callback;
5452 player->audio_decoded_cb_user_param = user_param;
5453 player->audio_extract_opt = opt;
5454 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5458 return MM_ERROR_NONE;
5462 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5464 mmplayer_t *player = (mmplayer_t *)hplayer;
5468 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5470 if (callback && !player->bufmgr)
5471 player->bufmgr = tbm_bufmgr_init(-1);
5473 player->set_mode.video_export = (callback) ? true : false;
5474 player->video_decoded_cb = callback;
5475 player->video_decoded_cb_user_param = user_param;
5477 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5481 return MM_ERROR_NONE;
5485 _mmplayer_start(MMHandleType hplayer)
5487 mmplayer_t *player = (mmplayer_t *)hplayer;
5488 gint ret = MM_ERROR_NONE;
5492 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5494 /* check current state */
5495 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5497 /* start pipeline */
5498 ret = _mmplayer_gst_start(player);
5499 if (ret != MM_ERROR_NONE)
5500 LOGE("failed to start player.");
5502 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5503 LOGD("force playing start even during buffering");
5504 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5512 /* NOTE: post "not supported codec message" to application
5513 * when one codec is not found during AUTOPLUGGING in MSL.
5514 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5515 * And, if any codec is not found, don't send message here.
5516 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5519 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5521 MMMessageParamType msg_param;
5522 memset(&msg_param, 0, sizeof(MMMessageParamType));
5523 gboolean post_msg_direct = FALSE;
5527 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5529 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5530 player->not_supported_codec, player->can_support_codec);
5532 if (player->not_found_demuxer) {
5533 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5534 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5536 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5537 MMPLAYER_FREEIF(msg_param.data);
5539 return MM_ERROR_NONE;
5542 if (player->not_supported_codec) {
5543 if (player->can_support_codec) {
5544 // There is one codec to play
5545 post_msg_direct = TRUE;
5547 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5548 post_msg_direct = TRUE;
5551 if (post_msg_direct) {
5552 MMMessageParamType msg_param;
5553 memset(&msg_param, 0, sizeof(MMMessageParamType));
5555 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5556 LOGW("not found AUDIO codec, posting error code to application.");
5558 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5559 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5560 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5561 LOGW("not found VIDEO codec, posting error code to application.");
5563 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5564 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5567 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5569 MMPLAYER_FREEIF(msg_param.data);
5571 return MM_ERROR_NONE;
5573 // no any supported codec case
5574 LOGW("not found any codec, posting error code to application.");
5576 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5577 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5578 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5580 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5581 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5584 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5586 MMPLAYER_FREEIF(msg_param.data);
5592 return MM_ERROR_NONE;
5595 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5597 GstState element_state = GST_STATE_VOID_PENDING;
5598 GstState element_pending_state = GST_STATE_VOID_PENDING;
5599 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5600 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5602 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5604 MMPLAYER_RECONFIGURE_LOCK(player);
5605 if (!player->gapless.reconfigure) {
5606 MMPLAYER_RECONFIGURE_UNLOCK(player);
5610 LOGI("reconfigure is under process");
5611 MMPLAYER_RECONFIGURE_WAIT(player);
5612 MMPLAYER_RECONFIGURE_UNLOCK(player);
5613 LOGI("reconfigure is completed.");
5615 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5616 &element_state, &element_pending_state, timeout * GST_SECOND);
5617 if (result == GST_STATE_CHANGE_FAILURE)
5618 LOGW("failed to get pipeline state in %d sec", timeout);
5623 /* NOTE : it should be able to call 'stop' anytime*/
5625 _mmplayer_stop(MMHandleType hplayer)
5627 mmplayer_t *player = (mmplayer_t *)hplayer;
5628 int ret = MM_ERROR_NONE;
5632 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5634 /* check current state */
5635 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5637 /* need to wait till the rebuilding pipeline is completed */
5638 __mmplayer_check_pipeline_reconfigure_state(player);
5639 MMPLAYER_RECONFIGURE_LOCK(player);
5640 __mmplayer_reset_gapless_state(player);
5641 MMPLAYER_RECONFIGURE_UNLOCK(player);
5643 /* NOTE : application should not wait for EOS after calling STOP */
5644 _mmplayer_cancel_eos_timer(player);
5647 player->seek_state = MMPLAYER_SEEK_NONE;
5650 ret = _mmplayer_gst_stop(player);
5652 if (ret != MM_ERROR_NONE)
5653 LOGE("failed to stop player.");
5661 _mmplayer_pause(MMHandleType hplayer)
5663 mmplayer_t *player = (mmplayer_t *)hplayer;
5664 gint64 pos_nsec = 0;
5665 gboolean async = FALSE;
5666 gint ret = MM_ERROR_NONE;
5670 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5672 /* check current state */
5673 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5675 /* check pipeline reconfigure state */
5676 __mmplayer_check_pipeline_reconfigure_state(player);
5678 switch (MMPLAYER_CURRENT_STATE(player)) {
5679 case MM_PLAYER_STATE_READY:
5681 /* check prepare async or not.
5682 * In the case of streaming playback, it's recommended to avoid blocking wait.
5684 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5685 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5687 /* Changing back sync of rtspsrc to async */
5688 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5689 LOGD("async prepare working mode for rtsp");
5695 case MM_PLAYER_STATE_PLAYING:
5697 /* NOTE : store current point to overcome some bad operation
5698 *(returning zero when getting current position in paused state) of some
5701 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5702 LOGW("getting current position failed in paused");
5704 player->last_position = pos_nsec;
5706 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5707 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5708 This causes problem is position calculation during normal pause resume scenarios also.
5709 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5710 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5711 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5712 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5718 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5719 LOGD("doing async pause in case of ms buff src");
5723 /* pause pipeline */
5724 ret = _mmplayer_gst_pause(player, async);
5725 if (ret != MM_ERROR_NONE) {
5726 LOGE("failed to pause player. ret : 0x%x", ret);
5727 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5731 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5732 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5733 LOGE("failed to update display_rotation");
5737 return MM_ERROR_NONE;
5740 /* in case of streaming, pause could take long time.*/
5742 _mmplayer_abort_pause(MMHandleType hplayer)
5744 mmplayer_t *player = (mmplayer_t *)hplayer;
5745 int ret = MM_ERROR_NONE;
5749 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5751 player->pipeline->mainbin,
5752 MM_ERROR_PLAYER_NOT_INITIALIZED);
5754 if (player->pipeline->videobin && player->pipeline->videobin[MMPLAYER_V_BIN].gst) {
5755 LOGD("set the videobin state to READY");
5756 ret = _mmplayer_gst_set_state(player, player->pipeline->videobin[MMPLAYER_V_BIN].gst,
5757 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5761 if (player->pipeline->audiobin && player->pipeline->audiobin[MMPLAYER_A_BIN].gst) {
5762 LOGD("set the audiobin state to READY");
5763 ret = _mmplayer_gst_set_state(player, player->pipeline->audiobin[MMPLAYER_A_BIN].gst,
5764 GST_STATE_READY, TRUE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5768 LOGD("set the pipeline state to READY");
5769 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5770 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5772 if (ret != MM_ERROR_NONE) {
5773 LOGE("fail to change state to READY");
5774 return MM_ERROR_PLAYER_INTERNAL;
5777 LOGD("succeeded in changing state to READY");
5782 _mmplayer_resume(MMHandleType hplayer)
5784 mmplayer_t *player = (mmplayer_t *)hplayer;
5785 int ret = MM_ERROR_NONE;
5786 gboolean async = FALSE;
5790 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5792 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5793 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5794 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5798 /* Changing back sync mode rtspsrc to async */
5799 LOGD("async resume for rtsp case");
5803 /* check current state */
5804 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5806 ret = _mmplayer_gst_resume(player, async);
5807 if (ret != MM_ERROR_NONE)
5808 LOGE("failed to resume player.");
5810 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5811 LOGD("force resume even during buffering");
5812 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5821 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5823 mmplayer_t *player = (mmplayer_t *)hplayer;
5824 gint64 pos_nsec = 0;
5825 int ret = MM_ERROR_NONE;
5827 signed long long start = 0, stop = 0;
5828 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5831 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5832 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5834 /* The sound of video is not supported under 0.0 and over 2.0. */
5835 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5836 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5839 _mmplayer_set_mute(hplayer, mute);
5841 if (player->playback_rate == rate)
5842 return MM_ERROR_NONE;
5844 /* If the position is reached at start potion during fast backward, EOS is posted.
5845 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5847 player->playback_rate = rate;
5849 current_state = MMPLAYER_CURRENT_STATE(player);
5851 if (current_state != MM_PLAYER_STATE_PAUSED)
5852 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5854 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5856 if ((current_state == MM_PLAYER_STATE_PAUSED)
5857 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5858 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5859 pos_nsec = player->last_position;
5864 stop = GST_CLOCK_TIME_NONE;
5866 start = GST_CLOCK_TIME_NONE;
5870 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5871 player->playback_rate,
5873 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5874 GST_SEEK_TYPE_SET, start,
5875 GST_SEEK_TYPE_SET, stop)) {
5876 LOGE("failed to set speed playback");
5877 return MM_ERROR_PLAYER_SEEK;
5880 LOGD("succeeded to set speed playback as %0.1f", rate);
5884 return MM_ERROR_NONE;;
5888 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5890 mmplayer_t *player = (mmplayer_t *)hplayer;
5891 int ret = MM_ERROR_NONE;
5895 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5897 /* check pipeline reconfigure state */
5898 __mmplayer_check_pipeline_reconfigure_state(player);
5900 ret = _mmplayer_gst_set_position(player, position, FALSE);
5908 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5910 mmplayer_t *player = (mmplayer_t *)hplayer;
5911 int ret = MM_ERROR_NONE;
5913 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5914 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5916 if (g_strrstr(player->type, "video/mpegts"))
5917 __mmplayer_update_duration_value(player);
5919 *duration = player->duration;
5924 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5926 mmplayer_t *player = (mmplayer_t *)hplayer;
5927 int ret = MM_ERROR_NONE;
5929 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5931 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5937 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5939 mmplayer_t *player = (mmplayer_t *)hplayer;
5940 int ret = MM_ERROR_NONE;
5944 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5946 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5954 __mmplayer_is_midi_type(gchar *str_caps)
5956 if ((g_strrstr(str_caps, "audio/midi")) ||
5957 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5958 (g_strrstr(str_caps, "application/x-smaf")) ||
5959 (g_strrstr(str_caps, "audio/x-imelody")) ||
5960 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5961 (g_strrstr(str_caps, "audio/xmf")) ||
5962 (g_strrstr(str_caps, "audio/mxmf"))) {
5971 __mmplayer_is_only_mp3_type(gchar *str_caps)
5973 if (g_strrstr(str_caps, "application/x-id3") ||
5974 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5980 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5982 GstStructure *caps_structure = NULL;
5983 gint samplerate = 0;
5987 MMPLAYER_RETURN_IF_FAIL(player && caps);
5989 caps_structure = gst_caps_get_structure(caps, 0);
5991 /* set stream information */
5992 gst_structure_get_int(caps_structure, "rate", &samplerate);
5993 gst_structure_get_int(caps_structure, "channels", &channels);
5995 mm_player_set_attribute((MMHandleType)player, NULL,
5996 "content_audio_samplerate", samplerate,
5997 "content_audio_channels", channels, NULL);
5999 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
6003 __mmplayer_update_content_type_info(mmplayer_t *player)
6006 MMPLAYER_RETURN_IF_FAIL(player && player->type);
6008 if (__mmplayer_is_midi_type(player->type)) {
6009 player->bypass_audio_effect = TRUE;
6013 if (!player->streamer) {
6014 LOGD("no need to check streaming type");
6018 if (g_strrstr(player->type, "application/x-hls")) {
6019 /* If it can't know exact type when it parses uri because of redirection case,
6020 * it will be fixed by typefinder or when doing autoplugging.
6022 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
6023 player->streamer->is_adaptive_streaming = TRUE;
6024 } else if (g_strrstr(player->type, "application/dash+xml")) {
6025 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
6026 player->streamer->is_adaptive_streaming = TRUE;
6029 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
6030 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
6031 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
6033 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
6034 if (player->streamer->is_adaptive_streaming)
6035 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
6037 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
6041 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
6046 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
6047 GstCaps *caps, gpointer data)
6049 mmplayer_t *player = (mmplayer_t *)data;
6053 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
6055 /* store type string */
6056 if (player->type_caps) {
6057 gst_caps_unref(player->type_caps);
6058 player->type_caps = NULL;
6061 player->type_caps = gst_caps_copy(caps);
6062 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
6064 MMPLAYER_FREEIF(player->type);
6065 player->type = gst_caps_to_string(caps);
6067 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
6068 player, player->type, probability, gst_caps_get_size(caps));
6070 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
6071 (g_strrstr(player->type, "audio/x-raw-int"))) {
6072 LOGE("not support media format");
6074 if (player->msg_posted == FALSE) {
6075 MMMessageParamType msg_param;
6076 memset(&msg_param, 0, sizeof(MMMessageParamType));
6078 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
6079 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6081 /* don't post more if one was sent already */
6082 player->msg_posted = TRUE;
6087 __mmplayer_update_content_type_info(player);
6089 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6092 pad = gst_element_get_static_pad(tf, "src");
6094 LOGE("fail to get typefind src pad.");
6098 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6099 gboolean async = FALSE;
6100 LOGE("failed to autoplug %s", player->type);
6102 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6104 if (async && player->msg_posted == FALSE)
6105 __mmplayer_handle_missed_plugin(player);
6107 gst_object_unref(GST_OBJECT(pad));
6114 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6116 GstElement *decodebin = NULL;
6120 /* create decodebin */
6121 decodebin = gst_element_factory_make("decodebin", NULL);
6124 LOGE("fail to create decodebin");
6128 /* raw pad handling signal */
6129 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6130 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6132 /* no-more-pad pad handling signal */
6133 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6134 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6136 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6137 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6139 /* This signal is emitted when a pad for which there is no further possible
6140 decoding is added to the decodebin.*/
6141 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6142 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6144 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6145 before looking for any elements that can handle that stream.*/
6146 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6147 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6149 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6150 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6151 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6153 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6154 before looking for any elements that can handle that stream.*/
6155 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6156 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6158 /* This signal is emitted once decodebin has finished decoding all the data.*/
6159 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6160 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6162 /* This signal is emitted when a element is added to the bin.*/
6163 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6164 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6171 __mmplayer_gst_make_queue2(mmplayer_t *player)
6173 GstElement *queue2 = NULL;
6174 gint64 dur_bytes = 0L;
6175 mmplayer_gst_element_t *mainbin = NULL;
6176 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6179 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6181 mainbin = player->pipeline->mainbin;
6183 queue2 = gst_element_factory_make("queue2", "queue2");
6185 LOGE("failed to create buffering queue element");
6189 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6190 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6192 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6194 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6195 * skip the pull mode(file or ring buffering) setting. */
6196 if (dur_bytes > 0) {
6197 if (!g_strrstr(player->type, "video/mpegts")) {
6198 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6199 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6205 _mm_player_streaming_set_queue2(player->streamer,
6209 (guint64)dur_bytes); /* no meaning at the moment */
6215 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6217 mmplayer_gst_element_t *mainbin = NULL;
6218 GstElement *decodebin = NULL;
6219 GstElement *queue2 = NULL;
6220 GstPad *sinkpad = NULL;
6221 GstPad *qsrcpad = NULL;
6224 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6226 mainbin = player->pipeline->mainbin;
6228 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6230 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6231 LOGW("need to check: muxed buffer is not null");
6234 queue2 = __mmplayer_gst_make_queue2(player);
6236 LOGE("failed to make queue2");
6240 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6241 LOGE("failed to add buffering queue");
6245 sinkpad = gst_element_get_static_pad(queue2, "sink");
6246 qsrcpad = gst_element_get_static_pad(queue2, "src");
6248 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6249 LOGE("failed to link [%s:%s]-[%s:%s]",
6250 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6254 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6255 LOGE("failed to sync queue2 state with parent");
6259 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6260 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6264 gst_object_unref(GST_OBJECT(sinkpad));
6268 /* create decodebin */
6269 decodebin = _mmplayer_gst_make_decodebin(player);
6271 LOGE("failed to make decodebin");
6275 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6276 LOGE("failed to add decodebin");
6280 /* to force caps on the decodebin element and avoid reparsing stuff by
6281 * typefind. It also avoids a deadlock in the way typefind activates pads in
6282 * the state change */
6283 g_object_set(decodebin, "sink-caps", caps, NULL);
6285 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6287 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6288 LOGE("failed to link [%s:%s]-[%s:%s]",
6289 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6293 gst_object_unref(GST_OBJECT(sinkpad));
6295 gst_object_unref(GST_OBJECT(qsrcpad));
6298 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6299 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6301 /* set decodebin property about buffer in streaming playback. *
6302 * in case of HLS/DASH, it does not need to have big buffer *
6303 * because it is kind of adaptive streaming. */
6304 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6305 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6306 gint high_percent = 0;
6308 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6309 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6311 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6313 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6315 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6316 "high-percent", high_percent,
6317 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6318 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6319 "max-size-buffers", 0, NULL); // disable or automatic
6322 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6323 LOGE("failed to sync decodebin state with parent");
6334 gst_object_unref(GST_OBJECT(sinkpad));
6337 gst_object_unref(GST_OBJECT(qsrcpad));
6340 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6341 * You need to explicitly set elements to the NULL state before
6342 * dropping the final reference, to allow them to clean up.
6344 gst_element_set_state(queue2, GST_STATE_NULL);
6346 /* And, it still has a parent "player".
6347 * You need to let the parent manage the object instead of unreffing the object directly.
6349 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6350 LOGE("failed to remove queue2");
6351 gst_object_unref(queue2);
6357 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6358 * You need to explicitly set elements to the NULL state before
6359 * dropping the final reference, to allow them to clean up.
6361 gst_element_set_state(decodebin, GST_STATE_NULL);
6363 /* And, it still has a parent "player".
6364 * You need to let the parent manage the object instead of unreffing the object directly.
6367 if (!gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6368 LOGE("failed to remove decodebin");
6369 gst_object_unref(decodebin);
6378 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6382 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6383 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6385 LOGD("class : %s, mime : %s", factory_class, mime);
6387 /* add missing plugin */
6388 /* NOTE : msl should check missing plugin for image mime type.
6389 * Some motion jpeg clips can have playable audio track.
6390 * So, msl have to play audio after displaying popup written video format not supported.
6392 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6393 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6394 LOGD("not found demuxer");
6395 player->not_found_demuxer = TRUE;
6396 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6402 if (!g_strrstr(factory_class, "Demuxer")) {
6403 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6404 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6405 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6407 /* check that clip have multi tracks or not */
6408 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6409 LOGD("video plugin is already linked");
6411 LOGW("add VIDEO to missing plugin");
6412 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6413 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6415 } else if (g_str_has_prefix(mime, "audio")) {
6416 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6417 LOGD("audio plugin is already linked");
6419 LOGW("add AUDIO to missing plugin");
6420 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6421 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6429 return MM_ERROR_NONE;
6433 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6435 mmplayer_t *player = (mmplayer_t *)data;
6439 MMPLAYER_RETURN_IF_FAIL(player);
6441 /* remove fakesink. */
6442 if (!_mmplayer_gst_remove_fakesink(player,
6443 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6444 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6445 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6446 * source element are not same. To overcome this situation, this function will called
6447 * several places and several times. Therefore, this is not an error case.
6452 LOGD("[handle: %p] pipeline has completely constructed", player);
6454 if ((player->msg_posted == FALSE) &&
6455 (player->cmd >= MMPLAYER_COMMAND_START))
6456 __mmplayer_handle_missed_plugin(player);
6458 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6462 __mmplayer_check_profile(void)
6465 static int profile_tv = -1;
6467 if (__builtin_expect(profile_tv != -1, 1))
6470 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6471 switch (*profileName) {
6486 __mmplayer_get_next_uri(mmplayer_t *player)
6488 mmplayer_parse_profile_t profile;
6490 guint num_of_list = 0;
6493 num_of_list = g_list_length(player->uri_info.uri_list);
6494 uri_idx = player->uri_info.uri_idx;
6496 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6497 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6498 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6500 LOGW("next uri does not exist");
6504 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6505 LOGE("failed to parse profile");
6509 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6510 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6511 LOGW("uri type is not supported(%d)", profile.uri_type);
6515 LOGD("success to find next uri %d", uri_idx);
6519 if (!uri || uri_idx == num_of_list) {
6520 LOGE("failed to find next uri");
6524 player->uri_info.uri_idx = uri_idx;
6525 if (mm_player_set_attribute((MMHandleType)player, NULL,
6526 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6527 LOGE("failed to set attribute");
6531 SECURE_LOGD("next playback uri: %s", uri);
6536 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6538 #define REPEAT_COUNT_INFINITE -1
6539 #define REPEAT_COUNT_MIN 2
6540 #define ORIGINAL_URI_ONLY 1
6542 MMHandleType attrs = 0;
6546 guint num_of_uri = 0;
6547 int profile_tv = -1;
6551 LOGD("checking for gapless play option");
6553 if (player->build_audio_offload) {
6554 LOGE("offload path is not supportable.");
6558 if (player->pipeline->textbin) {
6559 LOGE("subtitle path is enabled. gapless play is not supported.");
6563 attrs = MMPLAYER_GET_ATTRS(player);
6565 LOGE("fail to get attributes.");
6569 mm_attrs_multiple_get(player->attrs, NULL,
6570 "content_video_found", &video,
6571 "profile_play_count", &count,
6572 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6574 /* gapless playback is not supported in case of video at TV profile. */
6575 profile_tv = __mmplayer_check_profile();
6576 if (profile_tv && video) {
6577 LOGW("not support video gapless playback");
6581 /* check repeat count in case of audio */
6583 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6584 LOGW("gapless is disabled");
6588 num_of_uri = g_list_length(player->uri_info.uri_list);
6590 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6592 if (num_of_uri == ORIGINAL_URI_ONLY) {
6593 /* audio looping path */
6594 if (count >= REPEAT_COUNT_MIN) {
6595 /* decrease play count */
6596 /* we succeeded to rewind. update play count and then wait for next EOS */
6598 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6599 } else if (count != REPEAT_COUNT_INFINITE) {
6600 LOGD("there is no next uri and no repeat");
6603 LOGD("looping cnt %d", count);
6605 /* gapless playback path */
6606 if (!__mmplayer_get_next_uri(player)) {
6607 LOGE("failed to get next uri");
6614 LOGE("unable to play gapless path. EOS will be posted soon");
6619 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6621 GstPad *sinkpad = g_value_get_object (item);
6622 GstElement *element = GST_ELEMENT(user_data);
6623 if (!sinkpad || !element) {
6624 LOGE("invalid parameter");
6628 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6629 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6633 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6635 mmplayer_gst_element_t *sinkbin = NULL;
6636 main_element_id_e concatId = MMPLAYER_M_NUM;
6637 main_element_id_e sinkId = MMPLAYER_M_NUM;
6638 gboolean send_notice = FALSE;
6639 GstElement *element;
6643 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6645 LOGD("type %d", type);
6648 case MM_PLAYER_TRACK_TYPE_AUDIO:
6649 concatId = MMPLAYER_M_A_CONCAT;
6650 sinkId = MMPLAYER_A_BIN;
6651 sinkbin = player->pipeline->audiobin;
6653 case MM_PLAYER_TRACK_TYPE_VIDEO:
6654 concatId = MMPLAYER_M_V_CONCAT;
6655 sinkId = MMPLAYER_V_BIN;
6656 sinkbin = player->pipeline->videobin;
6659 case MM_PLAYER_TRACK_TYPE_TEXT:
6660 concatId = MMPLAYER_M_T_CONCAT;
6661 sinkId = MMPLAYER_T_BIN;
6662 sinkbin = player->pipeline->textbin;
6665 LOGE("requested type is not supportable");
6670 element = player->pipeline->mainbin[concatId].gst;
6674 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6675 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6676 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6677 if (srcpad && sinkpad) {
6678 /* after getting drained signal there is no data flows, so no need to do pad_block */
6679 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6680 gst_pad_unlink(srcpad, sinkpad);
6682 /* send custom event to sink pad to handle it at video sink */
6684 LOGD("send custom event to sinkpad");
6685 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6686 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6687 gst_pad_send_event(sinkpad, event);
6690 gst_object_unref(srcpad);
6691 gst_object_unref(sinkpad);
6694 LOGD("release concat request pad");
6695 /* release and unref requests pad from the selector */
6696 iter = gst_element_iterate_sink_pads(element);
6697 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6698 gst_iterator_resync(iter);
6699 gst_iterator_free(iter);
6705 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6707 mmplayer_track_t *selector = &player->track[type];
6708 mmplayer_gst_element_t *sinkbin = NULL;
6709 main_element_id_e selectorId = MMPLAYER_M_NUM;
6710 main_element_id_e sinkId = MMPLAYER_M_NUM;
6711 GstPad *srcpad = NULL;
6712 GstPad *sinkpad = NULL;
6713 gboolean send_notice = FALSE;
6716 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6718 LOGD("type %d", type);
6721 case MM_PLAYER_TRACK_TYPE_AUDIO:
6722 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6723 sinkId = MMPLAYER_A_BIN;
6724 sinkbin = player->pipeline->audiobin;
6726 case MM_PLAYER_TRACK_TYPE_VIDEO:
6727 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6728 sinkId = MMPLAYER_V_BIN;
6729 sinkbin = player->pipeline->videobin;
6732 case MM_PLAYER_TRACK_TYPE_TEXT:
6733 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6734 sinkId = MMPLAYER_T_BIN;
6735 sinkbin = player->pipeline->textbin;
6738 LOGE("requested type is not supportable");
6743 if (player->pipeline->mainbin[selectorId].gst) {
6746 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6748 if (selector->event_probe_id != 0)
6749 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6750 selector->event_probe_id = 0;
6752 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6753 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6755 if (srcpad && sinkpad) {
6756 /* after getting drained signal there is no data flows, so no need to do pad_block */
6757 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6758 gst_pad_unlink(srcpad, sinkpad);
6760 /* send custom event to sink pad to handle it at video sink */
6762 LOGD("send custom event to sinkpad");
6763 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6764 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6765 gst_pad_send_event(sinkpad, event);
6769 gst_object_unref(sinkpad);
6772 gst_object_unref(srcpad);
6775 LOGD("selector release");
6777 /* release and unref requests pad from the selector */
6778 for (n = 0; n < selector->streams->len; n++) {
6779 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6780 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6783 g_ptr_array_set_size(selector->streams, 0);
6785 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6786 if (!gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst),
6787 player->pipeline->mainbin[selectorId].gst)) {
6788 LOGE("failed to remove selector");
6789 gst_object_unref(player->pipeline->mainbin[selectorId].gst);
6792 player->pipeline->mainbin[selectorId].gst = NULL;
6800 __mmplayer_deactivate_old_path(mmplayer_t *player)
6803 MMPLAYER_RETURN_IF_FAIL(player);
6805 if (MMPLAYER_USE_DECODEBIN(player)) {
6806 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6807 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6808 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6809 LOGE("deactivate selector error");
6813 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6814 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6815 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6816 LOGE("deactivate concat error");
6821 _mmplayer_track_destroy(player);
6822 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6824 if (player->streamer) {
6825 _mm_player_streaming_initialize(player->streamer, FALSE);
6826 _mm_player_streaming_destroy(player->streamer);
6827 player->streamer = NULL;
6830 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6836 if (!player->msg_posted) {
6837 MMMessageParamType msg = {0,};
6840 msg.code = MM_ERROR_PLAYER_INTERNAL;
6841 LOGE("gapless_uri_play> deactivate error");
6843 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6844 player->msg_posted = TRUE;
6850 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6852 int result = MM_ERROR_NONE;
6853 mmplayer_t *player = (mmplayer_t *)hplayer;
6856 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6857 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6859 if (mm_player_set_attribute(hplayer, NULL,
6860 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6861 LOGE("failed to set attribute");
6862 result = MM_ERROR_PLAYER_INTERNAL;
6864 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6865 LOGE("failed to add the original uri in the uri list.");
6873 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6875 mmplayer_t *player = (mmplayer_t *)hplayer;
6876 guint num_of_list = 0;
6880 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6881 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6883 if (player->pipeline && player->pipeline->textbin) {
6884 LOGE("subtitle path is enabled.");
6885 return MM_ERROR_PLAYER_INVALID_STATE;
6888 num_of_list = g_list_length(player->uri_info.uri_list);
6890 if (is_first_path) {
6891 if (num_of_list == 0) {
6892 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6893 SECURE_LOGD("add original path : %s", uri);
6895 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6896 player->uri_info.uri_list = g_list_prepend(
6897 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6898 SECURE_LOGD("change original path : %s", uri);
6901 MMHandleType attrs = 0;
6902 attrs = MMPLAYER_GET_ATTRS(player);
6904 if (num_of_list == 0) {
6905 char *original_uri = NULL;
6908 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6910 if (!original_uri) {
6911 LOGE("there is no original uri.");
6912 return MM_ERROR_PLAYER_INVALID_STATE;
6915 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6916 player->uri_info.uri_idx = 0;
6918 SECURE_LOGD("add original path at first : %s", original_uri);
6922 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6923 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6927 return MM_ERROR_NONE;
6931 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6933 mmplayer_t *player = (mmplayer_t *)hplayer;
6934 char *next_uri = NULL;
6935 guint num_of_list = 0;
6938 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6940 num_of_list = g_list_length(player->uri_info.uri_list);
6942 if (num_of_list > 0) {
6943 gint uri_idx = player->uri_info.uri_idx;
6945 if (uri_idx < num_of_list - 1)
6950 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6951 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6953 *uri = g_strdup(next_uri);
6957 return MM_ERROR_NONE;
6961 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6962 GstCaps *caps, gpointer data)
6964 mmplayer_t *player = (mmplayer_t *)data;
6965 const gchar *klass = NULL;
6966 const gchar *mime = NULL;
6967 gchar *caps_str = NULL;
6969 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6970 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6971 caps_str = gst_caps_to_string(caps);
6973 LOGW("unknown type of caps : %s from %s",
6974 caps_str, GST_ELEMENT_NAME(elem));
6976 MMPLAYER_FREEIF(caps_str);
6978 /* There is no available codec. */
6979 __mmplayer_check_not_supported_codec(player, klass, mime);
6983 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6984 GstCaps *caps, gpointer data)
6986 mmplayer_t *player = (mmplayer_t *)data;
6987 const char *mime = NULL;
6988 gboolean ret = TRUE;
6990 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6991 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6993 if (g_str_has_prefix(mime, "audio")) {
6994 GstStructure *caps_structure = NULL;
6995 gint samplerate = 0;
6997 gchar *caps_str = NULL;
6999 caps_structure = gst_caps_get_structure(caps, 0);
7000 gst_structure_get_int(caps_structure, "rate", &samplerate);
7001 gst_structure_get_int(caps_structure, "channels", &channels);
7003 if ((channels > 0 && samplerate == 0)) {
7004 LOGD("exclude audio...");
7008 caps_str = gst_caps_to_string(caps);
7009 /* set it directly because not sent by TAG */
7010 if (g_strrstr(caps_str, "mobile-xmf"))
7011 mm_player_set_attribute((MMHandleType)player, NULL,
7012 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
7014 MMPLAYER_FREEIF(caps_str);
7015 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
7016 if((MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) || (MMPLAYER_IS_DASH_STREAMING(player))) {
7017 LOGD("video is already linked, allow the stream switch");
7020 LOGD("video is already linked");
7024 LOGD("found new stream");
7031 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
7033 gboolean ret = FALSE;
7034 GDBusConnection *conn = NULL;
7036 GVariant *result = NULL;
7037 const gchar *dbus_device_type = NULL;
7038 const gchar *dbus_ret = NULL;
7041 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
7043 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
7048 result = g_dbus_connection_call_sync(conn,
7049 "org.pulseaudio.Server",
7050 "/org/pulseaudio/StreamManager",
7051 "org.pulseaudio.StreamManager",
7052 "GetCurrentMediaRoutingPath",
7053 g_variant_new("(s)", "out"),
7054 G_VARIANT_TYPE("(ss)"),
7055 G_DBUS_CALL_FLAGS_NONE,
7059 if (!result || err) {
7060 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
7065 /* device type is listed in stream-map.json at mmfw-sysconf */
7066 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
7068 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
7069 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
7072 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
7073 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
7074 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
7075 LOGD("audio offload is supportable");
7081 LOGD("audio offload is not supportable");
7084 g_variant_unref(result);
7086 g_object_unref(conn);
7091 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
7093 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
7094 gint64 position = 0;
7096 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
7097 player->pipeline && player->pipeline->mainbin);
7099 MMPLAYER_CMD_LOCK(player);
7100 current_state = MMPLAYER_CURRENT_STATE(player);
7102 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7103 LOGW("getting current position failed in paused");
7105 _mmplayer_unrealize((MMHandleType)player);
7106 _mmplayer_realize((MMHandleType)player);
7108 _mmplayer_set_position((MMHandleType)player, position);
7110 /* async not to be blocked in streaming case */
7111 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7113 _mmplayer_pause((MMHandleType)player);
7115 if (current_state == MM_PLAYER_STATE_PLAYING)
7116 _mmplayer_start((MMHandleType)player);
7117 MMPLAYER_CMD_UNLOCK(player);
7119 LOGD("rebuilding audio pipeline is completed.");
7122 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7124 mmplayer_t *player = (mmplayer_t *)user_data;
7125 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7126 gboolean is_supportable = FALSE;
7128 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7129 LOGW("failed to get device type");
7131 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7133 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7134 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7135 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7136 LOGD("ignore this dev connected info");
7140 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7141 if (player->build_audio_offload == is_supportable) {
7142 LOGD("keep current pipeline without re-building");
7146 /* rebuild pipeline */
7147 LOGD("re-build pipeline - offload: %d", is_supportable);
7148 player->build_audio_offload = FALSE;
7149 __mmplayer_rebuild_audio_pipeline(player);
7155 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7157 unsigned int id = 0;
7159 if (player->audio_device_cb_id != 0) {
7160 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7164 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7165 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7166 LOGD("added device connected cb (%u)", id);
7167 player->audio_device_cb_id = id;
7169 LOGW("failed to add device connected cb");
7176 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7178 mmplayer_t *player = (mmplayer_t *)hplayer;
7181 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7182 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7184 *activated = player->build_audio_offload;
7186 LOGD("offload activated : %d", (int)*activated);
7189 return MM_ERROR_NONE;
7193 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7196 this function need to be updated according to the supported media format
7197 @see player->ini.audio_offload_media_format */
7199 if (__mmplayer_is_only_mp3_type(player->type)) {
7200 LOGD("offload supportable media format type");
7208 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7210 gboolean ret = FALSE;
7211 GstElementFactory *factory = NULL;
7214 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7216 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7217 if (!__mmplayer_is_offload_supported_type(player))
7220 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7221 LOGD("there is no audio offload sink");
7225 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7226 LOGW("there is no audio device type to support offload");
7230 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7232 LOGW("there is no installed audio offload sink element");
7235 gst_object_unref(factory);
7237 if (_mmplayer_acquire_hw_resource(player,
7238 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7239 LOGE("failed to acquire audio offload decoder resource");
7243 if (!__mmplayer_add_audio_device_connected_cb(player))
7246 if (!__mmplayer_is_audio_offload_device_type(player))
7249 LOGD("audio offload can be built");
7254 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7260 static GstAutoplugSelectResult
7261 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7263 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7264 int audio_offload = 0;
7266 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7267 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7269 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7270 LOGD("expose audio path to build offload output path");
7271 player->build_audio_offload = TRUE;
7272 /* update codec info */
7273 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7274 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7275 player->audiodec_linked = 1;
7277 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7281 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7282 And need to consider the multi-track audio content.
7283 There is no HW audio decoder in public. */
7285 /* set stream information */
7286 if (!player->audiodec_linked)
7287 _mmplayer_set_audio_attrs(player, caps);
7289 /* update codec info */
7290 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7291 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7292 player->audiodec_linked = 1;
7294 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7296 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7297 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7299 /* mark video decoder for acquire */
7300 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7301 LOGW("video decoder resource is already acquired, skip it.");
7302 ret = GST_AUTOPLUG_SELECT_SKIP;
7306 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7307 LOGE("failed to acquire video decoder resource");
7308 ret = GST_AUTOPLUG_SELECT_SKIP;
7311 player->interrupted_by_resource = FALSE;
7314 /* update codec info */
7315 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7316 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7317 player->videodec_linked = 1;
7325 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7326 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7328 #define DEFAULT_IDX 0xFFFF
7329 #define MIN_FACTORY_NUM 2
7330 mmplayer_t *player = (mmplayer_t *)data;
7331 GValueArray *new_factories = NULL;
7332 GValue val = { 0, };
7333 GstElementFactory *factory = NULL;
7334 const gchar *klass = NULL;
7335 gchar *factory_name = NULL;
7336 guint hw_dec_idx = DEFAULT_IDX;
7337 guint first_sw_dec_idx = DEFAULT_IDX;
7338 guint last_sw_dec_idx = DEFAULT_IDX;
7339 guint new_pos = DEFAULT_IDX;
7340 guint rm_pos = DEFAULT_IDX;
7341 int audio_codec_type;
7342 int video_codec_type;
7343 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7345 if (factories->n_values < MIN_FACTORY_NUM)
7348 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7349 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7352 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7354 for (int i = 0 ; i < factories->n_values ; i++) {
7355 gchar *hw_dec_info = NULL;
7356 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7358 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7360 LOGW("failed to get factory object");
7363 klass = gst_element_factory_get_klass(factory);
7364 factory_name = GST_OBJECT_NAME(factory);
7367 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7369 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7370 if (!player->need_audio_dec_sorting) {
7371 LOGD("sorting is not required");
7374 codec_type = audio_codec_type;
7375 hw_dec_info = player->ini.audiocodec_element_hw;
7376 sw_dec_info = player->ini.audiocodec_element_sw;
7377 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7378 if (!player->need_video_dec_sorting) {
7379 LOGD("sorting is not required");
7382 codec_type = video_codec_type;
7383 hw_dec_info = player->ini.videocodec_element_hw;
7384 sw_dec_info = player->ini.videocodec_element_sw;
7389 if (g_strrstr(factory_name, hw_dec_info)) {
7392 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7393 if (strstr(factory_name, sw_dec_info[j])) {
7394 last_sw_dec_idx = i;
7395 if (first_sw_dec_idx == DEFAULT_IDX) {
7396 first_sw_dec_idx = i;
7401 if (first_sw_dec_idx == DEFAULT_IDX)
7402 LOGW("unknown codec %s", factory_name);
7406 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7409 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7410 if (hw_dec_idx < first_sw_dec_idx)
7412 new_pos = first_sw_dec_idx;
7413 rm_pos = hw_dec_idx + 1;
7414 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7415 if (last_sw_dec_idx < hw_dec_idx)
7417 new_pos = last_sw_dec_idx + 1;
7418 rm_pos = hw_dec_idx;
7423 /* change position - insert H/W decoder according to the new position */
7424 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7426 LOGW("failed to get factory object");
7429 new_factories = g_value_array_copy(factories);
7430 g_value_init (&val, G_TYPE_OBJECT);
7431 g_value_set_object (&val, factory);
7432 g_value_array_insert(new_factories, new_pos, &val);
7433 g_value_unset (&val);
7434 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7436 for (int i = 0 ; i < new_factories->n_values ; i++) {
7437 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7439 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7440 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7442 LOGE("[Re-arranged] failed to get factory object");
7445 return new_factories;
7449 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7450 GstCaps *caps, GstElementFactory *factory, gpointer data)
7452 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7453 mmplayer_t *player = (mmplayer_t *)data;
7455 gchar *factory_name = NULL;
7456 gchar *caps_str = NULL;
7457 const gchar *klass = NULL;
7460 factory_name = GST_OBJECT_NAME(factory);
7461 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7462 caps_str = gst_caps_to_string(caps);
7464 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7466 /* store type string */
7467 if (player->type == NULL) {
7468 player->type = gst_caps_to_string(caps);
7469 __mmplayer_update_content_type_info(player);
7472 /* filtering exclude keyword */
7473 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7474 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7475 LOGW("skipping [%s] by exclude keyword [%s]",
7476 factory_name, player->ini.exclude_element_keyword[idx]);
7478 result = GST_AUTOPLUG_SELECT_SKIP;
7483 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7484 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7485 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7486 factory_name, player->ini.unsupported_codec_keyword[idx]);
7487 result = GST_AUTOPLUG_SELECT_SKIP;
7492 /* exclude webm format */
7493 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7494 * because webm format is not supportable.
7495 * If webm is disabled in "autoplug-continue", there is no state change
7496 * failure or error because the decodebin will expose the pad directly.
7497 * It make MSL invoke _prepare_async_callback.
7498 * So, we need to disable webm format in "autoplug-select" */
7499 if (caps_str && strstr(caps_str, "webm")) {
7500 LOGW("webm is not supported");
7501 result = GST_AUTOPLUG_SELECT_SKIP;
7505 /* check factory class for filtering */
7506 /* NOTE : msl don't need to use image plugins.
7507 * So, those plugins should be skipped for error handling.
7509 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7510 LOGD("skipping [%s] by not required", factory_name);
7511 result = GST_AUTOPLUG_SELECT_SKIP;
7515 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7516 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7517 // TO CHECK : subtitle if needed, add subparse exception.
7518 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7519 result = GST_AUTOPLUG_SELECT_SKIP;
7523 if (g_strrstr(factory_name, "mpegpsdemux")) {
7524 LOGD("skipping PS container - not support");
7525 result = GST_AUTOPLUG_SELECT_SKIP;
7529 if (g_strrstr(factory_name, "mssdemux"))
7530 player->smooth_streaming = TRUE;
7532 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7533 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7536 GstStructure *str = NULL;
7537 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7539 /* don't make video because of not required */
7540 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7541 (!player->set_mode.video_export)) {
7542 LOGD("no need video decoding, expose pad");
7543 result = GST_AUTOPLUG_SELECT_EXPOSE;
7547 /* get w/h for omx state-tune */
7548 /* FIXME: deprecated? */
7549 str = gst_caps_get_structure(caps, 0);
7550 gst_structure_get_int(str, "width", &width);
7553 if (player->v_stream_caps) {
7554 gst_caps_unref(player->v_stream_caps);
7555 player->v_stream_caps = NULL;
7558 player->v_stream_caps = gst_caps_copy(caps);
7559 LOGD("take caps for video state tune");
7560 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7564 if (g_strrstr(klass, "Codec/Decoder")) {
7565 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7566 if (result != GST_AUTOPLUG_SELECT_TRY) {
7567 LOGW("skip add decoder");
7573 MMPLAYER_FREEIF(caps_str);
7579 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7582 int ret = MM_ERROR_NONE;
7583 mmplayer_t *player = (mmplayer_t *)data;
7584 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7585 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7588 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7590 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7592 if (MMPLAYER_USE_DECODEBIN(player))
7595 if (!videobin || !g_str_has_prefix(GST_PAD_NAME (pad), "video"))
7598 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7600 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7601 LOGE("failed to remove videobin");
7602 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7605 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7606 LOGE("failed to remove video concat");
7607 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7610 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7611 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7612 MMPLAYER_FREEIF(player->pipeline->videobin);
7614 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7615 if (ret != MM_ERROR_NONE)
7616 LOGE("failed to release overlay resources");
7618 player->videodec_linked = 0;
7620 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7625 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7627 mmplayer_t *player = (mmplayer_t *)data;
7630 MMPLAYER_RETURN_IF_FAIL(player);
7632 LOGD("got about to finish signal");
7634 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7635 LOGW("Fail to get cmd lock");
7639 if (!__mmplayer_verify_gapless_play_path(player)) {
7640 LOGD("decoding is finished.");
7641 MMPLAYER_CMD_UNLOCK(player);
7645 _mmplayer_set_reconfigure_state(player, TRUE);
7646 MMPLAYER_CMD_UNLOCK(player);
7648 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL);
7649 __mmplayer_deactivate_old_path(player);
7655 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7657 mmplayer_t *player = (mmplayer_t *)data;
7658 GstIterator *iter = NULL;
7659 GValue item = { 0, };
7661 gboolean done = FALSE;
7662 gboolean is_all_drained = TRUE;
7665 MMPLAYER_RETURN_IF_FAIL(player);
7667 LOGD("got drained signal");
7669 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7670 LOGW("Fail to get cmd lock");
7674 if (!__mmplayer_verify_gapless_play_path(player)) {
7675 LOGD("decoding is finished.");
7676 MMPLAYER_CMD_UNLOCK(player);
7680 _mmplayer_set_reconfigure_state(player, TRUE);
7681 MMPLAYER_CMD_UNLOCK(player);
7683 /* check decodebin src pads whether they received EOS or not */
7684 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7687 switch (gst_iterator_next(iter, &item)) {
7688 case GST_ITERATOR_OK:
7689 pad = g_value_get_object(&item);
7690 if (pad && !GST_PAD_IS_EOS(pad)) {
7691 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7692 is_all_drained = FALSE;
7695 g_value_reset(&item);
7697 case GST_ITERATOR_RESYNC:
7698 gst_iterator_resync(iter);
7700 case GST_ITERATOR_ERROR:
7701 case GST_ITERATOR_DONE:
7706 g_value_unset(&item);
7707 gst_iterator_free(iter);
7709 if (!is_all_drained) {
7710 LOGD("Wait util the all pads get EOS.");
7715 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7716 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7718 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7719 MMPLAYER_POST_MSG(player, MM_MESSAGE_FLUSH_BUFFER, NULL); /* post message for gapless */
7720 __mmplayer_deactivate_old_path(player);
7726 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7728 mmplayer_t *player = (mmplayer_t *)data;
7729 const gchar *klass = NULL;
7730 gchar *factory_name = NULL;
7732 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7733 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7735 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7737 if (__mmplayer_add_dump_buffer_probe(player, element))
7738 LOGD("add buffer probe");
7740 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7741 gchar *selected = NULL;
7742 selected = g_strdup(GST_ELEMENT_NAME(element));
7743 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7745 /* update codec info */
7746 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7747 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7748 player->audiodec_linked = 1;
7749 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7750 /* update codec info */
7751 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7752 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7753 player->videodec_linked = 1;
7756 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7757 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7758 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7760 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7761 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7763 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7764 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7765 "max-video-width", player->adaptive_info.limit.width,
7766 "max-video-height", player->adaptive_info.limit.height, NULL);
7768 } else if (g_strrstr(klass, "Demuxer")) {
7770 LOGD("plugged element is demuxer. take it");
7772 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7773 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7774 } else if (g_strrstr(klass, "Parser") && (g_strrstr(klass, "Video"))) {
7775 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].id = MMPLAYER_M_V_PARSE;
7776 player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst = element;
7779 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7780 int surface_type = 0;
7782 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7785 // to support trust-zone only
7786 if (g_strrstr(factory_name, "asfdemux")) {
7787 LOGD("set file-location %s", player->profile.uri);
7788 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7789 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7790 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7791 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7792 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7793 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7794 (__mmplayer_is_only_mp3_type(player->type))) {
7795 LOGD("[mpegaudioparse] set streaming pull mode.");
7796 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7798 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7799 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7802 if (g_strrstr(factory_name, "omxdec_h264") || g_strrstr(factory_name, "v4l2h264dec")) {
7803 GstElement *video_parse = player->pipeline->mainbin[MMPLAYER_M_V_PARSE].gst;
7804 if (video_parse && (g_object_class_find_property(G_OBJECT_GET_CLASS(video_parse), "config-interval"))) {
7805 g_object_set(G_OBJECT(video_parse), "config-interval", -1, NULL);
7806 LOGD("Send SPS and PPS Insertion every IDR frame");
7810 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7811 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7812 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7814 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7815 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7817 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7818 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7819 (MMPLAYER_IS_DASH_STREAMING(player))) {
7820 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7821 _mm_player_streaming_set_multiqueue(player->streamer, element);
7822 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7831 __mmplayer_release_misc(mmplayer_t *player)
7834 bool cur_mode = player->set_mode.rich_audio;
7837 MMPLAYER_RETURN_IF_FAIL(player);
7839 player->sent_bos = FALSE;
7840 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7842 player->seek_state = MMPLAYER_SEEK_NONE;
7844 player->total_bitrate = 0;
7845 player->total_maximum_bitrate = 0;
7847 player->not_found_demuxer = 0;
7849 player->last_position = 0;
7850 player->duration = 0;
7851 player->http_content_size = 0;
7852 player->not_supported_codec = MISSING_PLUGIN_NONE;
7853 player->can_support_codec = FOUND_PLUGIN_NONE;
7854 player->pending_seek.is_pending = false;
7855 player->pending_seek.pos = 0;
7856 player->msg_posted = FALSE;
7857 player->has_many_types = FALSE;
7858 player->is_subtitle_force_drop = FALSE;
7859 player->play_subtitle = FALSE;
7860 player->adjust_subtitle_pos = 0;
7861 player->has_closed_caption = FALSE;
7862 player->set_mode.video_export = false;
7863 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7864 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7866 player->set_mode.rich_audio = cur_mode;
7868 if (player->audio_device_cb_id > 0 &&
7869 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7870 LOGW("failed to remove audio device_connected_callback");
7871 player->audio_device_cb_id = 0;
7873 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7874 player->bitrate[i] = 0;
7875 player->maximum_bitrate[i] = 0;
7878 /* free memory related to audio effect */
7879 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7881 if (player->adaptive_info.var_list) {
7882 g_list_free_full(player->adaptive_info.var_list, g_free);
7883 player->adaptive_info.var_list = NULL;
7886 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7887 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7888 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7890 /* Reset video360 settings to their defaults in case if the pipeline is to be
7893 player->video360_metadata.is_spherical = -1;
7894 player->is_openal_plugin_used = FALSE;
7896 player->is_content_spherical = FALSE;
7897 player->is_video360_enabled = TRUE;
7898 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7899 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7900 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7901 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7902 player->video360_zoom = 1.0f;
7903 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7904 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7906 player->sound.rg_enable = false;
7908 __mmplayer_initialize_video_roi(player);
7913 __mmplayer_release_misc_post(mmplayer_t *player)
7915 gchar *original_uri = NULL;
7918 /* player->pipeline is already released before. */
7919 MMPLAYER_RETURN_IF_FAIL(player);
7921 player->video_decoded_cb = NULL;
7922 player->video_decoded_cb_user_param = NULL;
7923 player->video_stream_prerolled = false;
7925 player->audio_decoded_cb = NULL;
7926 player->audio_decoded_cb_user_param = NULL;
7927 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7929 player->audio_stream_changed_cb = NULL;
7930 player->audio_stream_changed_cb_user_param = NULL;
7932 mm_player_set_attribute((MMHandleType)player, NULL,
7933 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7935 /* clean found audio decoders */
7936 if (player->audio_decoders) {
7937 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7938 player->audio_decoders = NULL;
7941 /* clean the uri list except original uri */
7942 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7944 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7945 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7946 g_list_free_full(tmp, (GDestroyNotify)g_free);
7949 LOGW("failed to get original uri info");
7951 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7952 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7953 MMPLAYER_FREEIF(original_uri);
7956 /* clear the audio stream buffer list */
7957 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7959 /* clear the video stream bo list */
7960 __mmplayer_video_stream_destroy_bo_list(player);
7961 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7963 if (player->profile.input_mem.buf) {
7964 free(player->profile.input_mem.buf);
7965 player->profile.input_mem.buf = NULL;
7967 player->profile.input_mem.len = 0;
7968 player->profile.input_mem.offset = 0;
7970 player->uri_info.uri_idx = 0;
7975 __mmplayer_check_subtitle(mmplayer_t *player)
7977 MMHandleType attrs = 0;
7978 char *subtitle_uri = NULL;
7982 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7984 /* get subtitle attribute */
7985 attrs = MMPLAYER_GET_ATTRS(player);
7989 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7990 if (!subtitle_uri || !strlen(subtitle_uri))
7993 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7994 player->is_external_subtitle_present = TRUE;
8002 _mmplayer_cancel_eos_timer(mmplayer_t *player)
8004 MMPLAYER_RETURN_IF_FAIL(player);
8006 if (player->eos_timer) {
8007 LOGD("cancel eos timer");
8008 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
8009 player->eos_timer = 0;
8016 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
8020 MMPLAYER_RETURN_IF_FAIL(player);
8021 MMPLAYER_RETURN_IF_FAIL(sink);
8024 player->sink_elements = g_list_prepend(player->sink_elements, sink);
8026 player->sink_elements = g_list_append(player->sink_elements, sink);
8032 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
8036 MMPLAYER_RETURN_IF_FAIL(player);
8037 MMPLAYER_RETURN_IF_FAIL(sink);
8039 player->sink_elements = g_list_remove(player->sink_elements, sink);
8045 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
8046 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
8048 mmplayer_signal_item_t *item = NULL;
8051 MMPLAYER_RETURN_IF_FAIL(player);
8053 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
8054 LOGE("invalid signal type [%d]", type);
8058 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
8060 LOGE("cannot connect signal [%s]", signal);
8065 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
8066 player->signals[type] = g_list_append(player->signals[type], item);
8072 /* NOTE : be careful with calling this api. please refer to below glib comment
8073 * glib comment : Note that there is a bug in GObject that makes this function much
8074 * less useful than it might seem otherwise. Once gobject is disposed, the callback
8075 * will no longer be called, but, the signal handler is not currently disconnected.
8076 * If the instance is itself being freed at the same time than this doesn't matter,
8077 * since the signal will automatically be removed, but if instance persists,
8078 * then the signal handler will leak. You should not remove the signal yourself
8079 * because in a future versions of GObject, the handler will automatically be
8082 * It's possible to work around this problem in a way that will continue to work
8083 * with future versions of GObject by checking that the signal handler is still
8084 * connected before disconnected it:
8086 * if (g_signal_handler_is_connected(instance, id))
8087 * g_signal_handler_disconnect(instance, id);
8090 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
8092 GList *sig_list = NULL;
8093 mmplayer_signal_item_t *item = NULL;
8097 MMPLAYER_RETURN_IF_FAIL(player);
8099 LOGD("release signals type : %d", type);
8101 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
8102 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
8103 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
8104 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
8105 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8106 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8110 sig_list = player->signals[type];
8112 for (; sig_list; sig_list = sig_list->next) {
8113 item = sig_list->data;
8115 if (item && item->obj) {
8116 if (g_signal_handler_is_connected(item->obj, item->sig))
8117 g_signal_handler_disconnect(item->obj, item->sig);
8120 MMPLAYER_FREEIF(item);
8123 g_list_free(player->signals[type]);
8124 player->signals[type] = NULL;
8132 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8134 mmplayer_t *player = 0;
8135 int prev_display_surface_type = 0;
8139 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8141 player = MM_PLAYER_CAST(handle);
8143 /* check video sinkbin is created */
8144 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8145 LOGW("Videosink is already created");
8146 return MM_ERROR_NONE;
8149 LOGD("videosink element is not yet ready");
8151 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8152 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8154 return MM_ERROR_INVALID_ARGUMENT;
8157 /* load previous attributes */
8158 if (player->attrs) {
8159 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8160 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8161 if (prev_display_surface_type == surface_type) {
8162 LOGD("incoming display surface type is same as previous one, do nothing..");
8164 return MM_ERROR_NONE;
8167 LOGE("failed to load attributes");
8169 return MM_ERROR_PLAYER_INTERNAL;
8172 /* videobin is not created yet, so we just set attributes related to display surface */
8173 LOGD("store display attribute for given surface type(%d)", surface_type);
8174 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8175 "display_overlay", wl_surface_id, NULL);
8178 return MM_ERROR_NONE;
8181 /* Note : if silent is true, then subtitle would not be displayed. :*/
8183 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8185 mmplayer_t *player = (mmplayer_t *)hplayer;
8189 /* check player handle */
8190 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8192 player->set_mode.subtitle_off = silent;
8194 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8198 return MM_ERROR_NONE;
8202 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8204 mmplayer_gst_element_t *mainbin = NULL;
8205 mmplayer_gst_element_t *textbin = NULL;
8206 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8207 GstState current_state = GST_STATE_VOID_PENDING;
8208 GstState element_state = GST_STATE_VOID_PENDING;
8209 GstState element_pending_state = GST_STATE_VOID_PENDING;
8211 GstEvent *event = NULL;
8212 int result = MM_ERROR_NONE;
8214 GstClock *curr_clock = NULL;
8215 GstClockTime base_time, start_time, curr_time;
8220 /* check player handle */
8221 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8223 player->pipeline->mainbin &&
8224 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8226 mainbin = player->pipeline->mainbin;
8227 textbin = player->pipeline->textbin;
8229 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8231 // sync clock with current pipeline
8232 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8233 curr_time = gst_clock_get_time(curr_clock);
8235 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8236 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8238 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8239 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8241 if (current_state > GST_STATE_READY) {
8242 // sync state with current pipeline
8243 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8244 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8245 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8247 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8248 if (GST_STATE_CHANGE_FAILURE == ret) {
8249 LOGE("fail to state change.");
8250 result = MM_ERROR_PLAYER_INTERNAL;
8254 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8255 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8258 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8259 gst_object_unref(curr_clock);
8262 // seek to current position
8263 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8264 result = MM_ERROR_PLAYER_INVALID_STATE;
8265 LOGE("gst_element_query_position failed, invalid state");
8269 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8270 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);
8272 _mmplayer_gst_send_event_to_sink(player, event);
8274 result = MM_ERROR_PLAYER_INTERNAL;
8275 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8279 /* sync state with current pipeline */
8280 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8281 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8282 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8284 return MM_ERROR_NONE;
8287 /* release text pipeline resource */
8288 player->textsink_linked = 0;
8290 /* release signal */
8291 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8293 /* release textbin with it's children */
8294 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8295 MMPLAYER_FREEIF(player->pipeline->textbin);
8296 player->pipeline->textbin = NULL;
8298 /* release subtitle elem */
8299 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8300 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8306 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8308 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8309 GstState current_state = GST_STATE_VOID_PENDING;
8311 MMHandleType attrs = 0;
8312 mmplayer_gst_element_t *mainbin = NULL;
8313 mmplayer_gst_element_t *textbin = NULL;
8315 gchar *subtitle_uri = NULL;
8316 int result = MM_ERROR_NONE;
8317 const gchar *charset = NULL;
8321 /* check player handle */
8322 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8324 player->pipeline->mainbin &&
8325 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8326 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8328 mainbin = player->pipeline->mainbin;
8329 textbin = player->pipeline->textbin;
8331 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8332 if (current_state < GST_STATE_READY) {
8333 result = MM_ERROR_PLAYER_INVALID_STATE;
8334 LOGE("Pipeline is not in proper state");
8338 attrs = MMPLAYER_GET_ATTRS(player);
8340 LOGE("cannot get content attribute");
8341 result = MM_ERROR_PLAYER_INTERNAL;
8345 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8346 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8347 LOGE("subtitle uri is not proper filepath");
8348 result = MM_ERROR_PLAYER_INVALID_URI;
8352 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8353 LOGE("failed to get storage info of subtitle path");
8354 result = MM_ERROR_PLAYER_INVALID_URI;
8358 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8359 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8361 if (!strcmp(filepath, subtitle_uri)) {
8362 LOGD("subtitle path is not changed");
8365 if (mm_player_set_attribute((MMHandleType)player, NULL,
8366 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8367 LOGE("failed to set attribute");
8372 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8373 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8374 player->subtitle_language_list = NULL;
8375 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8377 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8378 if (ret != GST_STATE_CHANGE_SUCCESS) {
8379 LOGE("failed to change state of textbin to READY");
8380 result = MM_ERROR_PLAYER_INTERNAL;
8384 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8385 if (ret != GST_STATE_CHANGE_SUCCESS) {
8386 LOGE("failed to change state of subparse to READY");
8387 result = MM_ERROR_PLAYER_INTERNAL;
8391 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8392 if (ret != GST_STATE_CHANGE_SUCCESS) {
8393 LOGE("failed to change state of filesrc to READY");
8394 result = MM_ERROR_PLAYER_INTERNAL;
8398 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8400 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8402 charset = _mmplayer_get_charset(filepath);
8404 LOGD("detected charset is %s", charset);
8405 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8408 result = _mmplayer_sync_subtitle_pipeline(player);
8415 /* API to switch between external subtitles */
8417 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8419 int result = MM_ERROR_NONE;
8420 mmplayer_t *player = (mmplayer_t *)hplayer;
8425 /* check player handle */
8426 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8428 /* filepath can be null in idle state */
8430 /* check file path */
8431 if ((path = strstr(filepath, "file://")))
8432 result = _mmplayer_exist_file_path(path + 7);
8434 result = _mmplayer_exist_file_path(filepath);
8436 if (result != MM_ERROR_NONE) {
8437 LOGE("invalid subtitle path 0x%X", result);
8438 return result; /* file not found or permission denied */
8442 if (!player->pipeline) {
8444 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8445 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8446 LOGE("failed to set attribute");
8447 return MM_ERROR_PLAYER_INTERNAL;
8450 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8451 /* check filepath */
8452 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8454 if (!__mmplayer_check_subtitle(player)) {
8455 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8456 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8457 LOGE("failed to set attribute");
8458 return MM_ERROR_PLAYER_INTERNAL;
8461 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8462 LOGE("fail to create text pipeline");
8463 return MM_ERROR_PLAYER_INTERNAL;
8466 result = _mmplayer_sync_subtitle_pipeline(player);
8468 result = __mmplayer_change_external_subtitle_language(player, filepath);
8471 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8472 player->is_external_subtitle_added_now = TRUE;
8474 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8475 if (!player->subtitle_language_list) {
8476 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8477 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8478 LOGW("subtitle language list is not updated yet");
8480 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8488 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8490 guint active_idx = 0;
8491 GstStream *stream = NULL;
8492 GList *streams = NULL;
8493 GstCaps *caps = NULL;
8496 LOGD("Switching Streams... type: %d, index: %d", type, index);
8498 player->track[type].active_track_index = index;
8500 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8501 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8502 LOGD("track type:%d, total: %d, active: %d", i,
8503 player->track[i].total_track_num, player->track[i].active_track_index);
8504 if (player->track[i].total_track_num > 0 &&
8505 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8506 active_idx = player->track[i].active_track_index;
8507 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8508 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8509 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8511 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8512 caps = gst_stream_get_caps(stream);
8514 _mmplayer_set_audio_attrs(player, caps);
8515 gst_caps_unref(caps);
8522 LOGD("send select stream event");
8523 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst,
8524 gst_event_new_select_streams(streams));
8525 g_list_free(streams);
8528 /* in paused state, seek to current pos to flush mq buffer and release waiting task */
8529 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
8530 gint64 pos_nsec = GST_CLOCK_TIME_NONE;
8532 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
8533 pos_nsec = player->last_position;
8535 LOGD("current pos %" GST_TIME_FORMAT ", rate = %f", GST_TIME_ARGS(pos_nsec), player->playback_rate);
8537 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8538 player->playback_rate, GST_FORMAT_TIME,
8539 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
8540 GST_SEEK_TYPE_SET, pos_nsec, GST_SEEK_TYPE_SET, GST_CLOCK_TIME_NONE)) {
8541 LOGW("failed to seek");
8542 return MM_ERROR_PLAYER_INTERNAL;
8547 return MM_ERROR_NONE;
8551 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8553 int result = MM_ERROR_NONE;
8554 gchar *change_pad_name = NULL;
8555 GstPad *sinkpad = NULL;
8556 mmplayer_gst_element_t *mainbin = NULL;
8557 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8558 GstCaps *caps = NULL;
8559 gint total_track_num = 0;
8563 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8564 MM_ERROR_PLAYER_NOT_INITIALIZED);
8566 LOGD("Change Track(%d) to %d", type, index);
8568 mainbin = player->pipeline->mainbin;
8570 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8571 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8572 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8573 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8575 /* Changing Video Track is not supported. */
8576 LOGE("Track Type Error");
8580 if (mainbin[elem_idx].gst == NULL) {
8581 result = MM_ERROR_PLAYER_NO_OP;
8582 LOGD("Req track doesn't exist");
8586 total_track_num = player->track[type].total_track_num;
8587 if (total_track_num <= 0) {
8588 result = MM_ERROR_PLAYER_NO_OP;
8589 LOGD("Language list is not available");
8593 if ((index < 0) || (index >= total_track_num)) {
8594 result = MM_ERROR_INVALID_ARGUMENT;
8595 LOGD("Not a proper index : %d", index);
8599 /*To get the new pad from the selector*/
8600 change_pad_name = g_strdup_printf("sink_%u", index);
8601 if (change_pad_name == NULL) {
8602 result = MM_ERROR_PLAYER_INTERNAL;
8603 LOGD("Pad does not exists");
8607 LOGD("new active pad name: %s", change_pad_name);
8609 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8610 if (sinkpad == NULL) {
8611 LOGD("sinkpad is NULL");
8612 result = MM_ERROR_PLAYER_INTERNAL;
8616 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8617 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8619 caps = gst_pad_get_current_caps(sinkpad);
8620 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8623 gst_object_unref(sinkpad);
8625 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8626 _mmplayer_set_audio_attrs(player, caps);
8629 gst_caps_unref(caps);
8632 MMPLAYER_FREEIF(change_pad_name);
8637 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8639 int result = MM_ERROR_NONE;
8640 mmplayer_t *player = NULL;
8641 mmplayer_gst_element_t *mainbin = NULL;
8643 gint current_active_index = 0;
8645 GstState current_state = GST_STATE_VOID_PENDING;
8650 player = (mmplayer_t *)hplayer;
8651 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8653 if (!player->pipeline) {
8654 LOGE("Track %d pre setting -> %d", type, index);
8656 player->track[type].active_track_index = index;
8660 mainbin = player->pipeline->mainbin;
8662 current_active_index = player->track[type].active_track_index;
8664 /*If index is same as running index no need to change the pad*/
8665 if (current_active_index == index)
8668 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8669 result = MM_ERROR_PLAYER_INVALID_STATE;
8673 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8674 if (current_state < GST_STATE_PAUSED) {
8675 result = MM_ERROR_PLAYER_INVALID_STATE;
8676 LOGW("Pipeline not in proper state");
8680 if (MMPLAYER_USE_DECODEBIN(player))
8681 result = __mmplayer_change_selector_pad(player, type, index);
8683 result = __mmplayer_switch_stream(player, type, index);
8685 if (result != MM_ERROR_NONE) {
8686 LOGE("failed to change track");
8690 player->track[type].active_track_index = index;
8692 if (MMPLAYER_USE_DECODEBIN(player)) {
8693 GstEvent *event = NULL;
8694 if (current_state == GST_STATE_PLAYING) {
8695 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8696 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8697 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8699 _mmplayer_gst_send_event_to_sink(player, event);
8701 result = MM_ERROR_PLAYER_INTERNAL;
8712 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8714 mmplayer_t *player = (mmplayer_t *)hplayer;
8718 /* check player handle */
8719 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8721 *silent = player->set_mode.subtitle_off;
8723 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8727 return MM_ERROR_NONE;
8731 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8733 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8734 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8736 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8737 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8741 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8742 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8743 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8744 mmplayer_dump_t *dump_s;
8745 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8746 if (dump_s == NULL) {
8747 LOGE("malloc fail");
8751 dump_s->dump_element_file = NULL;
8752 dump_s->dump_pad = NULL;
8753 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8755 if (dump_s->dump_pad) {
8756 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8757 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]);
8758 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8759 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);
8760 /* add list for removed buffer probe and close FILE */
8761 player->dump_list = g_list_append(player->dump_list, dump_s);
8762 LOGD("%s sink pad added buffer probe for dump", factory_name);
8765 MMPLAYER_FREEIF(dump_s);
8766 LOGE("failed to get %s sink pad added", factory_name);
8773 static GstPadProbeReturn
8774 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8776 FILE *dump_data = (FILE *)u_data;
8778 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8779 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8781 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8783 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8785 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8787 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8789 gst_buffer_unmap(buffer, &probe_info);
8791 return GST_PAD_PROBE_OK;
8795 __mmplayer_release_dump_list(GList *dump_list)
8797 GList *d_list = dump_list;
8802 for (; d_list; d_list = g_list_next(d_list)) {
8803 mmplayer_dump_t *dump_s = d_list->data;
8804 if (dump_s->dump_pad) {
8805 if (dump_s->probe_handle_id)
8806 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8807 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8809 if (dump_s->dump_element_file) {
8810 fclose(dump_s->dump_element_file);
8811 dump_s->dump_element_file = NULL;
8813 MMPLAYER_FREEIF(dump_s);
8815 g_list_free(dump_list);
8820 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8822 mmplayer_t *player = (mmplayer_t *)hplayer;
8826 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8827 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8829 *exist = (bool)player->has_closed_caption;
8833 return MM_ERROR_NONE;
8837 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8842 LOGD("unref internal gst buffer %p", buffer);
8844 gst_buffer_unref((GstBuffer *)buffer);
8851 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8853 mmplayer_t *player = (mmplayer_t *)hplayer;
8857 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8858 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8860 if (MMPLAYER_IS_STREAMING(player))
8861 *timeout = (int)player->ini.live_state_change_timeout;
8863 *timeout = (int)player->ini.localplayback_state_change_timeout;
8865 LOGD("timeout = %d", *timeout);
8868 return MM_ERROR_NONE;
8872 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8876 MMPLAYER_RETURN_IF_FAIL(player);
8878 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8880 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8881 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8882 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8883 player->storage_info[i].id = -1;
8884 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8886 if (path_type != MMPLAYER_PATH_MAX)
8895 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8897 int ret = MM_ERROR_NONE;
8898 mmplayer_t *player = (mmplayer_t *)hplayer;
8899 MMMessageParamType msg_param = {0, };
8902 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8904 LOGW("state changed storage %d:%d", id, state);
8906 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8907 return MM_ERROR_NONE;
8909 /* FIXME: text path should be handled separately. */
8910 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8911 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8912 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8913 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8914 LOGW("external storage is removed");
8916 if (player->msg_posted == FALSE) {
8917 memset(&msg_param, 0, sizeof(MMMessageParamType));
8918 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8919 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8920 player->msg_posted = TRUE;
8923 /* unrealize the player */
8924 ret = _mmplayer_unrealize(hplayer);
8925 if (ret != MM_ERROR_NONE)
8926 LOGE("failed to unrealize");
8934 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8936 int ret = MM_ERROR_NONE;
8937 mmplayer_t *player = (mmplayer_t *)hplayer;
8938 int idx = 0, total = 0;
8939 gchar *result = NULL, *tmp = NULL;
8942 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8943 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8945 total = *num = g_list_length(player->adaptive_info.var_list);
8947 LOGW("There is no stream variant info.");
8951 result = g_strdup("");
8952 for (idx = 0 ; idx < total ; idx++) {
8953 stream_variant_t *v_data = NULL;
8954 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8957 gchar data[64] = {0};
8958 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8960 tmp = g_strconcat(result, data, NULL);
8964 LOGW("There is no variant data in %d", idx);
8969 *var_info = (char *)result;
8971 LOGD("variant info %d:%s", *num, *var_info);
8977 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8979 int ret = MM_ERROR_NONE;
8980 mmplayer_t *player = (mmplayer_t *)hplayer;
8983 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8985 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8987 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8988 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8989 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8991 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8992 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8993 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8994 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8996 /* FIXME: seek to current position for applying new variant limitation */
9005 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
9007 int ret = MM_ERROR_NONE;
9008 mmplayer_t *player = (mmplayer_t *)hplayer;
9011 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9012 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
9014 *bandwidth = player->adaptive_info.limit.bandwidth;
9015 *width = player->adaptive_info.limit.width;
9016 *height = player->adaptive_info.limit.height;
9018 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
9025 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
9027 int ret = MM_ERROR_NONE;
9028 mmplayer_t *player = (mmplayer_t *)hplayer;
9031 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
9032 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
9033 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
9035 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
9037 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
9038 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
9039 else /* live case */
9040 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
9042 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
9049 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
9051 #define IDX_FIRST_SW_CODEC 0
9052 mmplayer_t *player = (mmplayer_t *)hplayer;
9053 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9054 const char *attr_name = NULL;
9055 const char *default_type = NULL;
9056 const char *element_hw = NULL;
9057 const char *element_sw = NULL;
9060 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9062 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
9064 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
9065 switch (stream_type) {
9066 case MM_PLAYER_STREAM_TYPE_AUDIO:
9067 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
9068 default_type = player->ini.audiocodec_default_type;
9069 element_hw = player->ini.audiocodec_element_hw;
9070 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
9072 case MM_PLAYER_STREAM_TYPE_VIDEO:
9073 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
9074 default_type = player->ini.videocodec_default_type;
9075 element_hw = player->ini.videocodec_element_hw;
9076 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
9079 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
9080 return MM_ERROR_COMMON_INVALID_ARGUMENT;
9084 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
9086 if (!strcmp(default_type, "sw"))
9087 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
9089 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
9091 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
9092 codec_type = default_codec_type;
9094 /* to support codec selection, codec info have to be added in ini file.
9095 in case of hw codec is selected, filter elements should be applied
9096 depending on the hw capabilities. */
9097 if (codec_type != default_codec_type) {
9098 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
9099 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
9100 LOGE("There is no codec for type %d", codec_type);
9101 return MM_ERROR_PLAYER_NO_OP;
9104 LOGD("sorting is required");
9105 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
9106 player->need_audio_dec_sorting = TRUE;
9108 player->need_video_dec_sorting = TRUE;
9111 LOGD("update %s codec_type to %d", attr_name, codec_type);
9112 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
9115 return MM_ERROR_NONE;
9119 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
9121 mmplayer_t *player = (mmplayer_t *)hplayer;
9122 GstElement *rg_vol_element = NULL;
9126 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9128 player->sound.rg_enable = enabled;
9130 /* just hold rgvolume enable value if pipeline is not ready */
9131 if (!player->pipeline || !player->pipeline->audiobin) {
9132 LOGD("pipeline is not ready. holding rgvolume enable value");
9133 return MM_ERROR_NONE;
9136 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9138 if (!rg_vol_element) {
9139 LOGD("rgvolume element is not created");
9140 return MM_ERROR_PLAYER_INTERNAL;
9144 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9146 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9150 return MM_ERROR_NONE;
9154 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9156 mmplayer_t *player = (mmplayer_t *)hplayer;
9157 GstElement *rg_vol_element = NULL;
9158 gboolean enable = FALSE;
9162 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9163 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9165 /* just hold enable_rg value if pipeline is not ready */
9166 if (!player->pipeline || !player->pipeline->audiobin) {
9167 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9168 *enabled = player->sound.rg_enable;
9169 return MM_ERROR_NONE;
9172 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9174 if (!rg_vol_element) {
9175 LOGD("rgvolume element is not created");
9176 return MM_ERROR_PLAYER_INTERNAL;
9179 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9180 *enabled = (bool)enable;
9184 return MM_ERROR_NONE;
9188 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9190 mmplayer_t *player = (mmplayer_t *)hplayer;
9191 MMHandleType attrs = 0;
9193 int ret = MM_ERROR_NONE;
9197 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9199 attrs = MMPLAYER_GET_ATTRS(player);
9200 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9202 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9204 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9205 return MM_ERROR_PLAYER_INTERNAL;
9208 player->video_roi.scale_x = scale_x;
9209 player->video_roi.scale_y = scale_y;
9210 player->video_roi.scale_width = scale_width;
9211 player->video_roi.scale_height = scale_height;
9213 /* check video sinkbin is created */
9214 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9215 return MM_ERROR_NONE;
9217 if (!gst_video_overlay_set_video_roi_area(
9218 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9219 scale_x, scale_y, scale_width, scale_height))
9220 ret = MM_ERROR_PLAYER_INTERNAL;
9222 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9223 scale_x, scale_y, scale_width, scale_height);
9231 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9233 mmplayer_t *player = (mmplayer_t *)hplayer;
9234 int ret = MM_ERROR_NONE;
9238 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9239 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9241 *scale_x = player->video_roi.scale_x;
9242 *scale_y = player->video_roi.scale_y;
9243 *scale_width = player->video_roi.scale_width;
9244 *scale_height = player->video_roi.scale_height;
9246 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9247 *scale_x, *scale_y, *scale_width, *scale_height);
9253 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9255 mmplayer_t *player = (mmplayer_t *)hplayer;
9259 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9261 player->client_pid = pid;
9263 LOGD("client pid[%d] %p", pid, player);
9267 return MM_ERROR_NONE;
9271 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9273 mmplayer_t *player = (mmplayer_t *)hplayer;
9274 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9275 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9280 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9283 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9285 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9287 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9288 return MM_ERROR_NONE;
9290 /* in case of audio codec default type is HW */
9292 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9293 if (player->ini.support_audio_effect)
9294 return MM_ERROR_NONE;
9295 elem_id = MMPLAYER_A_FILTER;
9297 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9298 if (player->ini.support_replaygain_control)
9299 return MM_ERROR_NONE;
9300 elem_id = MMPLAYER_A_RGVOL;
9302 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9303 if (player->ini.support_pitch_control)
9304 return MM_ERROR_NONE;
9305 elem_id = MMPLAYER_A_PITCH;
9307 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9308 if (player->ini.support_audio_effect)
9309 return MM_ERROR_NONE;
9311 /* default case handling is not required */
9314 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9315 LOGW("audio control option [%d] is not available", opt);
9318 /* setting pcm exporting option is allowed before READY state */
9319 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9320 return MM_ERROR_PLAYER_INVALID_STATE;
9322 /* check whether the audio filter exist or not after READY state,
9323 because the sw codec could be added during auto-plugging in some cases */
9324 if (!player->pipeline ||
9325 !player->pipeline->audiobin ||
9326 !player->pipeline->audiobin[elem_id].gst) {
9327 LOGW("there is no audio elem [%d]", elem_id);
9332 LOGD("audio control opt %d, available %d", opt, *available);
9336 return MM_ERROR_NONE;
9340 __mmplayer_update_duration_value(mmplayer_t *player)
9342 gboolean ret = FALSE;
9343 gint64 dur_nsec = 0;
9344 LOGD("try to update duration");
9346 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9347 player->duration = dur_nsec;
9348 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9352 if (player->duration < 0) {
9353 LOGW("duration is Non-Initialized !!!");
9354 player->duration = 0;
9357 /* update streaming service type */
9358 player->streaming_type = _mmplayer_get_stream_service_type(player);
9360 /* check duration is OK */
9361 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9362 /* FIXIT : find another way to get duration here. */
9363 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9369 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9371 /* update audio params
9372 NOTE : We need original audio params and it can be only obtained from src pad of audio
9373 decoder. Below code only valid when we are not using 'resampler' just before
9374 'audioconverter'. */
9375 GstCaps *caps_a = NULL;
9377 gint samplerate = 0, channels = 0;
9378 GstStructure *p = NULL;
9379 GstElement *aconv = NULL;
9381 LOGD("try to update audio attrs");
9383 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9385 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9386 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9387 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9388 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9390 LOGE("there is no audio converter");
9394 pad = gst_element_get_static_pad(aconv, "sink");
9397 LOGW("failed to get pad from audio converter");
9401 caps_a = gst_pad_get_current_caps(pad);
9403 LOGW("not ready to get audio caps");
9404 gst_object_unref(pad);
9408 p = gst_caps_get_structure(caps_a, 0);
9409 gst_structure_get_int(p, "rate", &samplerate);
9410 gst_structure_get_int(p, "channels", &channels);
9412 mm_player_set_attribute((MMHandleType)player, NULL,
9413 "content_audio_samplerate", samplerate,
9414 "content_audio_channels", channels, NULL);
9416 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9418 gst_caps_unref(caps_a);
9419 gst_object_unref(pad);
9425 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9427 LOGD("try to update video attrs");
9429 GstCaps *caps_v = NULL;
9433 GstStructure *p = NULL;
9435 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9436 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9438 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9440 LOGD("no videosink sink pad");
9444 caps_v = gst_pad_get_current_caps(pad);
9445 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9446 if (!caps_v && player->v_stream_caps) {
9447 caps_v = player->v_stream_caps;
9448 gst_caps_ref(caps_v);
9452 LOGD("no negotiated caps from videosink");
9453 gst_object_unref(pad);
9457 p = gst_caps_get_structure(caps_v, 0);
9458 gst_structure_get_int(p, "width", &width);
9459 gst_structure_get_int(p, "height", &height);
9461 mm_player_set_attribute((MMHandleType)player, NULL,
9462 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9464 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9466 SECURE_LOGD("width : %d height : %d", width, height);
9468 gst_caps_unref(caps_v);
9469 gst_object_unref(pad);
9472 mm_player_set_attribute((MMHandleType)player, NULL,
9473 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9474 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9481 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9483 gboolean ret = FALSE;
9484 guint64 data_size = 0;
9488 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9489 if (!player->duration)
9492 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9493 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9494 if (stat(path, &sb) == 0)
9495 data_size = (guint64)sb.st_size;
9497 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9498 data_size = player->http_content_size;
9501 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9504 guint64 bitrate = 0;
9505 guint64 msec_dur = 0;
9507 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9509 bitrate = data_size * 8 * 1000 / msec_dur;
9510 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9511 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9512 mm_player_set_attribute((MMHandleType)player, NULL,
9513 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9516 LOGD("player duration is less than 0");
9520 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9521 if (player->total_bitrate) {
9522 mm_player_set_attribute((MMHandleType)player, NULL,
9523 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9532 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9534 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9535 data->uri_type = uri_type;
9539 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9541 int ret = MM_ERROR_PLAYER_INVALID_URI;
9543 char *buffer = NULL;
9544 char *seperator = strchr(path, ',');
9545 char ext[100] = {0,}, size[100] = {0,};
9548 if ((buffer = strstr(path, "ext="))) {
9549 buffer += strlen("ext=");
9551 if (strlen(buffer)) {
9552 strncpy(ext, buffer, 99);
9554 if ((seperator = strchr(ext, ','))
9555 || (seperator = strchr(ext, ' '))
9556 || (seperator = strchr(ext, '\0'))) {
9557 seperator[0] = '\0';
9562 if ((buffer = strstr(path, "size="))) {
9563 buffer += strlen("size=");
9565 if (strlen(buffer) > 0) {
9566 strncpy(size, buffer, 99);
9568 if ((seperator = strchr(size, ','))
9569 || (seperator = strchr(size, ' '))
9570 || (seperator = strchr(size, '\0'))) {
9571 seperator[0] = '\0';
9574 mem_size = atoi(size);
9579 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9581 if (mem_size && param) {
9582 if (data->input_mem.buf)
9583 free(data->input_mem.buf);
9584 data->input_mem.buf = malloc(mem_size);
9586 if (data->input_mem.buf) {
9587 memcpy(data->input_mem.buf, param, mem_size);
9588 data->input_mem.len = mem_size;
9589 ret = MM_ERROR_NONE;
9591 LOGE("failed to alloc mem %d", mem_size);
9592 ret = MM_ERROR_PLAYER_INTERNAL;
9595 data->input_mem.offset = 0;
9596 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9603 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9605 gchar *location = NULL;
9608 int ret = MM_ERROR_NONE;
9610 if ((path = strstr(uri, "file://"))) {
9611 location = g_filename_from_uri(uri, NULL, &err);
9612 if (!location || (err != NULL)) {
9613 LOGE("Invalid URI '%s' for filesrc: %s", path,
9614 (err != NULL) ? err->message : "unknown error");
9618 MMPLAYER_FREEIF(location);
9620 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9621 return MM_ERROR_PLAYER_INVALID_URI;
9623 LOGD("path from uri: %s", location);
9626 path = (location != NULL) ? (location) : ((char *)uri);
9629 ret = _mmplayer_exist_file_path(path);
9631 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9632 if (ret == MM_ERROR_NONE) {
9633 if (_mmplayer_is_sdp_file(path)) {
9634 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9635 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9636 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9638 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9639 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9641 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9642 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9644 LOGE("invalid uri, could not play..");
9645 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9648 MMPLAYER_FREEIF(location);
9653 static mmplayer_video_decoded_data_info_t *
9654 __mmplayer_create_stream_from_pad(GstPad *pad)
9656 GstCaps *caps = NULL;
9657 GstStructure *structure = NULL;
9658 unsigned int fourcc = 0;
9659 const gchar *string_format = NULL;
9660 mmplayer_video_decoded_data_info_t *stream = NULL;
9662 MMPixelFormatType format;
9665 caps = gst_pad_get_current_caps(pad);
9667 LOGE("Caps is NULL.");
9672 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9674 structure = gst_caps_get_structure(caps, 0);
9675 gst_structure_get_int(structure, "width", &width);
9676 gst_structure_get_int(structure, "height", &height);
9677 string_format = gst_structure_get_string(structure, "format");
9680 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9681 format = _mmplayer_get_pixtype(fourcc);
9682 gst_video_info_from_caps(&info, caps);
9683 gst_caps_unref(caps);
9686 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9687 LOGE("Wrong condition!!");
9691 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9693 LOGE("failed to alloc mem for video data");
9697 stream->width = width;
9698 stream->height = height;
9699 stream->format = format;
9700 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9706 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9708 unsigned int pitch = 0;
9709 unsigned int size = 0;
9711 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9714 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9715 bo = gst_tizen_memory_get_bos(mem, index);
9717 stream->bo[index] = tbm_bo_ref(bo);
9719 LOGE("failed to get bo for index %d", index);
9722 for (index = 0; index < stream->plane_num; index++) {
9723 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9724 stream->stride[index] = pitch;
9726 stream->elevation[index] = size / pitch;
9728 stream->elevation[index] = stream->height;
9733 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9735 if (stream->format == MM_PIXEL_FORMAT_I420) {
9736 int ret = TBM_SURFACE_ERROR_NONE;
9737 tbm_surface_h surface;
9738 tbm_surface_info_s info;
9740 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9742 ret = tbm_surface_get_info(surface, &info);
9743 if (ret != TBM_SURFACE_ERROR_NONE) {
9744 tbm_surface_destroy(surface);
9748 tbm_surface_destroy(surface);
9749 stream->stride[0] = info.planes[0].stride;
9750 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9751 stream->stride[1] = info.planes[1].stride;
9752 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9753 stream->stride[2] = info.planes[2].stride;
9754 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9755 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9756 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9757 stream->stride[0] = stream->width * 4;
9758 stream->elevation[0] = stream->height;
9759 stream->bo_size = stream->stride[0] * stream->height;
9761 LOGE("Not support format %d", stream->format);
9769 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9771 tbm_bo_handle thandle;
9773 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9774 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9775 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9779 unsigned char *src = NULL;
9780 unsigned char *dest = NULL;
9781 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9783 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9785 LOGE("fail to gst_memory_map");
9789 if (!mapinfo.data) {
9790 LOGE("data pointer is wrong");
9794 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9795 if (!stream->bo[0]) {
9796 LOGE("Fail to tbm_bo_alloc!!");
9800 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9802 LOGE("thandle pointer is wrong");
9806 if (stream->format == MM_PIXEL_FORMAT_I420) {
9807 src_stride[0] = GST_ROUND_UP_4(stream->width);
9808 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9809 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9810 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9813 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9814 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9816 for (i = 0; i < 3; i++) {
9817 src = mapinfo.data + src_offset[i];
9818 dest = thandle.ptr + dest_offset[i];
9823 for (j = 0; j < stream->height >> k; j++) {
9824 memcpy(dest, src, stream->width>>k);
9825 src += src_stride[i];
9826 dest += stream->stride[i];
9829 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9830 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9832 LOGE("Not support format %d", stream->format);
9836 tbm_bo_unmap(stream->bo[0]);
9837 gst_memory_unmap(mem, &mapinfo);
9843 tbm_bo_unmap(stream->bo[0]);
9846 gst_memory_unmap(mem, &mapinfo);
9852 __mmplayer_set_pause_state(mmplayer_t *player)
9854 if (player->sent_bos)
9857 /* rtsp case, get content attrs by GstMessage */
9858 if (MMPLAYER_IS_RTSP_STREAMING(player))
9861 /* it's first time to update all content attrs. */
9862 _mmplayer_update_content_attrs(player, ATTR_ALL);
9866 __mmplayer_set_playing_state(mmplayer_t *player)
9868 gchar *audio_codec = NULL;
9870 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9871 /* initialize because auto resume is done well. */
9872 player->resumed_by_rewind = FALSE;
9873 player->playback_rate = 1.0;
9876 if (player->sent_bos)
9879 /* try to get content metadata */
9881 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9882 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9883 * legacy mmfw-player api
9885 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9887 if ((player->cmd == MMPLAYER_COMMAND_START)
9888 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9889 __mmplayer_handle_missed_plugin(player);
9892 /* check audio codec field is set or not
9893 * we can get it from typefinder or codec's caps.
9895 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9897 /* The codec format can't be sent for audio only case like amr, mid etc.
9898 * Because, parser don't make related TAG.
9899 * So, if it's not set yet, fill it with found data.
9902 if (g_strrstr(player->type, "audio/midi"))
9903 audio_codec = "MIDI";
9904 else if (g_strrstr(player->type, "audio/x-amr"))
9905 audio_codec = "AMR";
9906 else if (g_strrstr(player->type, "audio/mpeg")
9907 && !g_strrstr(player->type, "mpegversion=(int)1"))
9908 audio_codec = "AAC";
9910 audio_codec = "unknown";
9912 if (mm_player_set_attribute((MMHandleType)player, NULL,
9913 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9914 LOGE("failed to set attribute");
9916 LOGD("set audio codec type with caps");