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 MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time);
807 MMPLAYER_BUS_WATCHER_UNLOCK(player);
809 g_mutex_clear(&player->bus_watcher_mutex);
810 g_cond_clear(&player->bus_watcher_cond);
817 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
819 mmplayer_t *player = (mmplayer_t *)hplayer;
820 GstMessage *msg = NULL;
821 GQueue *queue = NULL;
824 MMPLAYER_RETURN_IF_FAIL(player);
826 /* destroy the gst bus msg thread */
827 if (player->bus_msg_thread) {
828 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
829 player->bus_msg_thread_exit = TRUE;
830 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
831 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
833 LOGD("gst bus msg thread exit.");
834 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
835 player->bus_msg_thread = NULL;
837 g_mutex_clear(&player->bus_msg_thread_mutex);
838 g_cond_clear(&player->bus_msg_thread_cond);
841 g_mutex_lock(&player->bus_msg_q_lock);
842 queue = player->bus_msg_q;
843 while (!g_queue_is_empty(queue)) {
844 msg = (GstMessage *)g_queue_pop_head(queue);
849 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
850 gst_message_unref(msg);
852 g_mutex_unlock(&player->bus_msg_q_lock);
858 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
860 GstElement *parent = NULL;
862 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
863 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
866 MMPLAYER_FSINK_LOCK(player);
868 /* get parent of fakesink */
869 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
871 LOGD("fakesink already removed");
875 gst_element_set_locked_state(fakesink->gst, TRUE);
877 /* setting the state to NULL never returns async
878 * so no need to wait for completion of state transition
880 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
881 LOGE("fakesink state change failure!");
882 /* FIXIT : should I return here? or try to proceed to next? */
885 /* remove fakesink from it's parent */
886 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
887 LOGE("failed to remove fakesink");
889 gst_object_unref(parent);
894 gst_object_unref(parent);
896 LOGD("state-holder removed");
898 gst_element_set_locked_state(fakesink->gst, FALSE);
900 MMPLAYER_FSINK_UNLOCK(player);
905 gst_element_set_locked_state(fakesink->gst, FALSE);
907 MMPLAYER_FSINK_UNLOCK(player);
911 static GstPadProbeReturn
912 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
914 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
915 return GST_PAD_PROBE_OK;
919 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
921 gint64 stop_running_time = 0;
922 gint64 position_running_time = 0;
926 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
927 if ((player->gapless.update_segment[idx] == TRUE) ||
928 !(player->track[idx].event_probe_id)) {
930 LOGW("[%d] skip", idx);
935 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
937 gst_segment_to_running_time(&player->gapless.segment[idx],
938 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
939 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
941 gst_segment_to_running_time(&player->gapless.segment[idx],
942 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
944 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
946 gst_segment_to_running_time(&player->gapless.segment[idx],
947 GST_FORMAT_TIME, player->duration);
950 position_running_time =
951 gst_segment_to_running_time(&player->gapless.segment[idx],
952 GST_FORMAT_TIME, player->gapless.segment[idx].position);
954 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
955 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
957 GST_TIME_ARGS(stop_running_time),
958 GST_TIME_ARGS(position_running_time),
959 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
960 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
962 position_running_time = MAX(position_running_time, stop_running_time);
963 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
964 GST_FORMAT_TIME, player->gapless.segment[idx].start);
965 position_running_time = MAX(0, position_running_time);
966 position = MAX(position, position_running_time);
970 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
971 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
972 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
974 player->gapless.start_time[stream_type] += position;
980 static GstPadProbeReturn
981 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
983 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
984 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
985 mmplayer_t *player = (mmplayer_t *)data;
986 GstCaps *caps = NULL;
987 GstStructure *str = NULL;
988 const gchar *name = NULL;
989 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
990 gboolean caps_ret = TRUE;
992 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
993 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
994 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
995 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
996 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
999 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1003 if (strstr(name, "audio")) {
1004 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1005 } else if (strstr(name, "video")) {
1006 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1008 /* text track is not supportable */
1009 LOGE("invalid name %s", name);
1013 switch (GST_EVENT_TYPE(event)) {
1016 /* in case of gapless, drop eos event not to send it to sink */
1017 if (player->gapless.reconfigure && !player->msg_posted) {
1018 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1019 ret = GST_PAD_PROBE_DROP;
1023 case GST_EVENT_STREAM_START:
1025 __mmplayer_gst_selector_update_start_time(player, stream_type);
1028 case GST_EVENT_FLUSH_STOP:
1030 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1031 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1032 player->gapless.start_time[stream_type] = 0;
1035 case GST_EVENT_SEGMENT:
1040 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1041 gst_event_copy_segment(event, &segment);
1043 if (segment.format != GST_FORMAT_TIME)
1046 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1047 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1048 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1049 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1050 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1051 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1053 /* keep the all the segment ev to cover the seeking */
1054 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1055 player->gapless.update_segment[stream_type] = TRUE;
1057 if (!player->gapless.running)
1060 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1062 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1064 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1065 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1066 gst_event_unref(event);
1067 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1073 gdouble proportion = 0.0;
1074 GstClockTimeDiff diff = 0;
1075 GstClockTime timestamp = 0;
1076 gint64 running_time_diff = -1;
1077 GstQOSType type = 0;
1078 GstEvent *tmpev = NULL;
1080 running_time_diff = player->gapless.segment[stream_type].base;
1082 if (running_time_diff <= 0) /* don't need to adjust */
1085 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1086 gst_event_unref(event);
1088 if (timestamp < running_time_diff) {
1089 LOGW("QOS event from previous group");
1090 ret = GST_PAD_PROBE_DROP;
1095 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1096 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1097 stream_type, GST_TIME_ARGS(timestamp),
1098 GST_TIME_ARGS(running_time_diff),
1099 GST_TIME_ARGS(timestamp - running_time_diff));
1102 timestamp -= running_time_diff;
1104 /* That case is invalid for QoS events */
1105 if (diff < 0 && -diff > timestamp) {
1106 LOGW("QOS event from previous group");
1107 ret = GST_PAD_PROBE_DROP;
1111 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1112 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1122 gst_caps_unref(caps);
1126 /* create fakesink for audio or video path without audiobin or videobin */
1128 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1130 GstElement *pipeline = NULL;
1131 GstElement *fakesink = NULL;
1132 GstPad *sinkpad = NULL;
1135 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1137 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1140 fakesink = gst_element_factory_make("fakesink", NULL);
1141 if (fakesink == NULL) {
1142 LOGE("failed to create fakesink");
1146 /* store it as it's sink element */
1147 __mmplayer_add_sink(player, fakesink, FALSE);
1149 gst_bin_add(GST_BIN(pipeline), fakesink);
1152 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1154 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1156 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1157 LOGE("failed to link fakesink");
1158 gst_object_unref(GST_OBJECT(fakesink));
1162 if (strstr(name, "video")) {
1163 if (player->v_stream_caps) {
1164 gst_caps_unref(player->v_stream_caps);
1165 player->v_stream_caps = NULL;
1167 if (player->ini.set_dump_element_flag)
1168 __mmplayer_add_dump_buffer_probe(player, fakesink);
1171 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1172 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1176 gst_object_unref(GST_OBJECT(sinkpad));
1183 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1185 GstElement *pipeline = NULL;
1186 GstElement *concat = NULL;
1189 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1191 concat = gst_element_factory_make("concat", NULL);
1193 LOGE("failed to create concat");
1197 LOGD("Create concat [%d] element", elem_idx);
1199 player->pipeline->mainbin[elem_idx].id = elem_idx;
1200 player->pipeline->mainbin[elem_idx].gst = concat;
1202 gst_element_set_state(concat, GST_STATE_PAUSED);
1204 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1205 gst_bin_add(GST_BIN(pipeline), concat);
1212 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1214 GstElement *pipeline = NULL;
1215 GstElement *selector = NULL;
1216 GstPad *srcpad = NULL;
1219 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1221 selector = gst_element_factory_make("input-selector", NULL);
1223 LOGE("failed to create input-selector");
1226 g_object_set(selector, "sync-streams", TRUE, NULL);
1228 player->pipeline->mainbin[elem_idx].id = elem_idx;
1229 player->pipeline->mainbin[elem_idx].gst = selector;
1231 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1233 srcpad = gst_element_get_static_pad(selector, "src");
1235 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1236 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1237 __mmplayer_gst_selector_blocked, NULL, NULL);
1238 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1239 __mmplayer_gst_selector_event_probe, player, NULL);
1241 gst_element_set_state(selector, GST_STATE_PAUSED);
1243 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1244 gst_bin_add(GST_BIN(pipeline), selector);
1246 gst_object_unref(GST_OBJECT(srcpad));
1253 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1255 mmplayer_t *player = (mmplayer_t *)data;
1256 GstElement *combiner = NULL;
1257 GstCaps *caps = NULL;
1258 GstStructure *str = NULL;
1259 const gchar *name = NULL;
1260 GstPad *sinkpad = NULL;
1261 gboolean first_track = FALSE;
1262 gboolean caps_ret = TRUE;
1264 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1265 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1268 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1269 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1271 LOGD("pad-added signal handling");
1273 /* get mimetype from caps */
1274 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1278 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1280 LOGD("detected mimetype : %s", name);
1283 if (strstr(name, "video")) {
1285 gchar *caps_str = NULL;
1287 caps_str = gst_caps_to_string(caps);
1288 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1289 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1290 player->set_mode.video_zc = true;
1292 MMPLAYER_FREEIF(caps_str);
1294 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1295 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1297 LOGD("surface type : %d", stype);
1299 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1300 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1304 /* in case of exporting video frame, it requires the 360 video filter.
1305 * it will be handled in _no_more_pads(). */
1306 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1307 __mmplayer_gst_make_fakesink(player, pad, name);
1311 if (MMPLAYER_USE_DECODEBIN(player)) {
1312 LOGD("video selector is required");
1313 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1315 LOGD("video concat is required");
1316 elem_idx = MMPLAYER_M_V_CONCAT;
1318 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1319 } else if (strstr(name, "audio")) {
1320 gint samplerate = 0;
1323 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1324 if (player->build_audio_offload)
1325 player->no_more_pad = TRUE; /* remove state holder */
1326 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1330 gst_structure_get_int(str, "rate", &samplerate);
1331 gst_structure_get_int(str, "channels", &channels);
1333 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1334 __mmplayer_gst_make_fakesink(player, pad, name);
1337 if (MMPLAYER_USE_DECODEBIN(player)) {
1338 LOGD("audio selector is required");
1339 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1341 LOGD("audio concat is required");
1342 elem_idx = MMPLAYER_M_A_CONCAT;
1344 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1346 } else if (strstr(name, "text")) {
1347 if (MMPLAYER_USE_DECODEBIN(player)) {
1348 LOGD("text selector is required");
1349 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1351 LOGD("text concat is required");
1352 elem_idx = MMPLAYER_M_T_CONCAT;
1354 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1356 LOGE("invalid caps info");
1360 /* check selector and create it */
1361 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1362 if (MMPLAYER_USE_DECODEBIN(player))
1363 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1365 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1371 LOGD("Combiner element is already created.");
1375 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1377 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1379 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1380 LOGE("failed to link combiner");
1381 gst_object_unref(GST_OBJECT(combiner));
1386 if (MMPLAYER_USE_DECODEBIN(player)) {
1387 LOGD("this track will be activated");
1388 g_object_set(combiner, "active-pad", sinkpad, NULL);
1392 if (MMPLAYER_USE_DECODEBIN(player)) {
1393 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1395 /* apply the text track information */
1396 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1397 mm_player_set_attribute((MMHandleType)player, NULL,
1398 "content_text_track_num", player->track[stream_type].total_track_num,
1399 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1400 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1407 gst_caps_unref(caps);
1410 gst_object_unref(GST_OBJECT(sinkpad));
1418 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1420 GstPad *srcpad = NULL;
1423 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1425 LOGD("type %d", type);
1428 LOGD("there is no %d track", type);
1432 srcpad = gst_element_get_static_pad(combiner, "src");
1434 LOGE("failed to get srcpad from combiner");
1438 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1440 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1442 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1443 if (player->track[type].block_id) {
1444 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1445 player->track[type].block_id = 0;
1449 gst_object_unref(GST_OBJECT(srcpad));
1458 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1460 gint active_index = 0;
1463 MMPLAYER_RETURN_IF_FAIL(player);
1465 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1467 /* change track to active pad */
1468 active_index = player->track[type].active_track_index;
1469 if ((active_index != DEFAULT_TRACK_INDEX) &&
1470 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1471 LOGW("failed to change %d type track to %d", type, active_index);
1472 player->track[type].active_track_index = DEFAULT_TRACK_INDEX;
1476 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1477 mm_player_set_attribute((MMHandleType)player, NULL,
1478 "content_text_track_num", player->track[type].total_track_num,
1479 "current_text_track_index", player->track[type].active_track_index, NULL);
1486 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1489 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1491 if (!audio_selector) {
1492 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1494 /* in case the source is changed, output can be changed. */
1495 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1496 LOGD("remove previous audiobin if it exist");
1498 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1499 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1501 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1502 MMPLAYER_FREEIF(player->pipeline->audiobin);
1505 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1506 _mmplayer_pipeline_complete(NULL, player);
1511 /* apply the audio track information */
1512 if (MMPLAYER_USE_DECODEBIN(player))
1513 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1515 /* create audio sink path */
1516 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1517 LOGE("failed to create audio sink path");
1526 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1529 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1531 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1532 LOGD("text path is not supported");
1536 /* apply the text track information */
1537 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1539 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1540 player->has_closed_caption = TRUE;
1542 /* create text decode path */
1543 player->no_more_pad = TRUE;
1545 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1546 LOGE("failed to create text sink path");
1555 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1557 gint64 dur_bytes = 0L;
1560 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1561 player->pipeline->mainbin && player->streamer, FALSE);
1563 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1564 LOGE("fail to get duration.");
1566 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1567 * use file information was already set on Q2 when it was created. */
1568 _mm_player_streaming_set_queue2(player->streamer,
1569 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1570 TRUE, /* use_buffering */
1571 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1572 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1579 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1581 mmplayer_t *player = NULL;
1582 GstElement *video_selector = NULL;
1583 GstElement *audio_selector = NULL;
1584 GstElement *text_selector = NULL;
1587 player = (mmplayer_t *)data;
1589 LOGD("no-more-pad signal handling");
1591 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1592 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1593 LOGW("player is shutting down");
1597 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1598 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1599 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1600 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1601 LOGE("failed to set queue2 buffering");
1606 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1607 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1608 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1610 if (!video_selector && !audio_selector && !text_selector) {
1611 LOGW("there is no selector");
1612 player->no_more_pad = TRUE;
1616 /* create video path followed by video-select */
1617 if (video_selector && !audio_selector && !text_selector)
1618 player->no_more_pad = TRUE;
1620 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1623 /* create audio path followed by audio-select */
1624 if (audio_selector && !text_selector)
1625 player->no_more_pad = TRUE;
1627 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1630 /* create text path followed by text-select */
1631 __mmplayer_create_text_sink_path(player, text_selector);
1634 _mmplayer_set_reconfigure_state(player, FALSE);
1639 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1641 gboolean ret = FALSE;
1642 GstElement *pipeline = NULL;
1643 GstPad *sinkpad = NULL;
1646 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1647 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1649 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1651 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1653 LOGE("failed to get pad from sinkbin");
1659 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1660 LOGE("failed to link sinkbin for reusing");
1661 goto EXIT; /* exit either pass or fail */
1665 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1666 LOGE("failed to set state(READY) to sinkbin");
1671 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1672 LOGE("failed to add sinkbin to pipeline");
1677 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1678 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1683 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1684 LOGE("failed to set state(PAUSED) to sinkbin");
1693 gst_object_unref(GST_OBJECT(sinkpad));
1701 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1703 mmplayer_t *player = NULL;
1704 GstCaps *caps = NULL;
1705 gchar *caps_str = NULL;
1706 GstStructure *str = NULL;
1707 const gchar *name = NULL;
1708 GstElement *sinkbin = NULL;
1709 gboolean reusing = FALSE;
1710 gboolean caps_ret = TRUE;
1711 gchar *sink_pad_name = "sink";
1714 player = (mmplayer_t *)data;
1717 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1718 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1719 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1721 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1725 gst_caps_unref(caps);
1726 caps = gst_caps_ref(ref_caps);
1729 caps_str = gst_caps_to_string(caps);
1731 LOGD("detected mimetype : %s", name);
1733 if (strstr(name, "audio")) {
1734 if (player->pipeline->audiobin == NULL) {
1735 const gchar *audio_format = gst_structure_get_string(str, "format");
1737 LOGD("original audio format %s", audio_format);
1738 mm_player_set_attribute((MMHandleType)player, NULL,
1739 "content_audio_format", audio_format, strlen(audio_format), NULL);
1742 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1743 LOGE("failed to create audiobin. continuing without audio");
1747 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1748 LOGD("creating audiobin success");
1751 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1752 LOGD("reusing audiobin");
1753 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1755 } else if (strstr(name, "video")) {
1756 /* 1. zero copy is updated at _decode_pad_added()
1757 * 2. NULL surface type is handled in _decode_pad_added() */
1758 LOGD("zero copy %d", player->set_mode.video_zc);
1759 if (player->pipeline->videobin == NULL) {
1760 int surface_type = 0;
1761 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1762 LOGD("display_surface_type (%d)", surface_type);
1764 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1765 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1766 LOGE("failed to acquire video overlay resource");
1770 player->interrupted_by_resource = FALSE;
1772 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1773 LOGE("failed to create videobin. continuing without video");
1777 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1778 LOGD("creating videosink bin success");
1781 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1782 LOGD("re-using videobin");
1783 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1785 } else if (strstr(name, "text")) {
1786 if (player->pipeline->textbin == NULL) {
1787 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1788 LOGE("failed to create text sink bin. continuing without text");
1792 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1793 player->textsink_linked = 1;
1794 LOGD("creating textsink bin success");
1796 if (!player->textsink_linked) {
1797 LOGD("re-using textbin");
1799 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1800 player->textsink_linked = 1;
1802 /* linked textbin exist which means that the external subtitle path exist already */
1803 LOGW("ignoring internal subtitle since external subtitle is available");
1806 sink_pad_name = "text_sink";
1808 LOGW("unknown mime type %s, ignoring it", name);
1812 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1815 LOGD("[handle: %p] success to create and link sink bin", player);
1817 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1818 * streaming task. if the task blocked, then buffer will not flow to the next element
1819 *(autoplugging element). so this is special hack for streaming. please try to remove it
1821 /* dec stream count. we can remove fakesink if it's zero */
1822 if (player->num_dynamic_pad)
1823 player->num_dynamic_pad--;
1825 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1827 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1828 _mmplayer_pipeline_complete(NULL, player);
1832 MMPLAYER_FREEIF(caps_str);
1835 gst_caps_unref(caps);
1841 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1843 int required_angle = 0; /* Angle required for straight view */
1844 int rotation_angle = 0;
1846 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1847 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1849 /* Counter clockwise */
1850 switch (orientation) {
1855 required_angle = 270;
1858 required_angle = 180;
1861 required_angle = 90;
1865 rotation_angle = display_angle + required_angle;
1866 if (rotation_angle >= 360)
1867 rotation_angle -= 360;
1869 /* check if supported or not */
1870 if (rotation_angle % 90) {
1871 LOGD("not supported rotation angle = %d", rotation_angle);
1875 switch (rotation_angle) {
1877 *value = MM_DISPLAY_ROTATION_NONE;
1880 *value = MM_DISPLAY_ROTATION_90;
1883 *value = MM_DISPLAY_ROTATION_180;
1886 *value = MM_DISPLAY_ROTATION_270;
1890 LOGD("setting rotation property value : %d", *value);
1896 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1898 int display_rotation = 0;
1899 gchar *org_orient = NULL;
1900 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1903 LOGE("cannot get content attribute");
1904 return MM_ERROR_PLAYER_INTERNAL;
1907 if (display_angle) {
1908 /* update user rotation */
1909 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1911 /* Counter clockwise */
1912 switch (display_rotation) {
1913 case MM_DISPLAY_ROTATION_NONE:
1916 case MM_DISPLAY_ROTATION_90:
1917 *display_angle = 90;
1919 case MM_DISPLAY_ROTATION_180:
1920 *display_angle = 180;
1922 case MM_DISPLAY_ROTATION_270:
1923 *display_angle = 270;
1926 LOGW("wrong angle type : %d", display_rotation);
1929 LOGD("check user angle: %d", *display_angle);
1933 /* Counter clockwise */
1934 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1937 if (!strcmp(org_orient, "rotate-90"))
1939 else if (!strcmp(org_orient, "rotate-180"))
1941 else if (!strcmp(org_orient, "rotate-270"))
1944 LOGD("original rotation is %s", org_orient);
1946 LOGD("content_video_orientation get fail");
1949 LOGD("check orientation: %d", *orientation);
1952 return MM_ERROR_NONE;
1955 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1957 int rotation_value = 0;
1958 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1959 int display_angle = 0;
1962 /* check video sinkbin is created */
1963 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1966 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1968 /* get rotation value to set */
1969 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1970 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1971 LOGD("set video param : rotate %d", rotation_value);
1974 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1976 MMHandleType attrs = 0;
1980 /* check video sinkbin is created */
1981 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1984 attrs = MMPLAYER_GET_ATTRS(player);
1985 MMPLAYER_RETURN_IF_FAIL(attrs);
1987 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1988 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1989 LOGD("set video param : visible %d", visible);
1992 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1994 MMHandleType attrs = 0;
1995 int display_method = 0;
1998 /* check video sinkbin is created */
1999 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2002 attrs = MMPLAYER_GET_ATTRS(player);
2003 MMPLAYER_RETURN_IF_FAIL(attrs);
2005 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2006 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2007 LOGD("set video param : method %d", display_method);
2010 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2012 MMHandleType attrs = 0;
2016 /* check video sinkbin is created */
2017 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2020 attrs = MMPLAYER_GET_ATTRS(player);
2021 MMPLAYER_RETURN_IF_FAIL(attrs);
2023 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2024 MMPLAYER_RETURN_IF_FAIL(handle);
2026 gst_video_overlay_set_video_roi_area(
2027 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2028 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2029 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2030 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2033 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2035 MMHandleType attrs = 0;
2040 int win_roi_width = 0;
2041 int win_roi_height = 0;
2044 /* check video sinkbin is created */
2045 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2048 attrs = MMPLAYER_GET_ATTRS(player);
2049 MMPLAYER_RETURN_IF_FAIL(attrs);
2051 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2052 MMPLAYER_RETURN_IF_FAIL(handle);
2054 /* It should be set after setting window */
2055 mm_attrs_multiple_get(attrs, NULL,
2056 "display_win_roi_x", &win_roi_x,
2057 "display_win_roi_y", &win_roi_y,
2058 "display_win_roi_width", &win_roi_width,
2059 "display_win_roi_height", &win_roi_height, NULL);
2061 /* After setting window handle, set display roi area */
2062 gst_video_overlay_set_display_roi_area(
2063 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2064 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2065 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2066 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2069 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2071 MMHandleType attrs = 0;
2074 /* check video sinkbin is created */
2075 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2078 attrs = MMPLAYER_GET_ATTRS(player);
2079 MMPLAYER_RETURN_IF_FAIL(attrs);
2081 /* common case if using overlay surface */
2082 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2083 MMPLAYER_RETURN_IF_FAIL(handle);
2085 /* default is using wl_surface_id */
2086 LOGD("set video param : wl_surface_id %d", handle);
2087 gst_video_overlay_set_wl_window_wl_surface_id(
2088 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2093 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2095 gboolean update_all_param = FALSE;
2099 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2100 LOGW("videosink is not ready yet");
2101 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2104 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2105 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2106 return MM_ERROR_PLAYER_INTERNAL;
2109 LOGD("param_name : %s", param_name);
2110 if (!g_strcmp0(param_name, "update_all_param"))
2111 update_all_param = TRUE;
2113 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2114 __mmplayer_video_param_set_display_overlay(player);
2115 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2116 __mmplayer_video_param_set_display_method(player);
2117 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2118 __mmplayer_video_param_set_display_visible(player);
2119 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2120 __mmplayer_video_param_set_display_rotation(player);
2121 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2122 __mmplayer_video_param_set_roi_area(player);
2123 if (update_all_param)
2124 __mmplayer_video_param_set_video_roi_area(player);
2128 return MM_ERROR_NONE;
2131 static int __mmplayer_set_disable_overlay_option(mmplayer_t *player, bool disable)
2133 gboolean disable_overlay = FALSE;
2136 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2137 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2138 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2140 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2141 LOGW("Display control is not supported");
2142 return MM_ERROR_PLAYER_INTERNAL;
2145 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2147 if (disable == (bool)disable_overlay) {
2148 LOGE("It's the same with current setting: (%d)", disable);
2149 return MM_ERROR_NONE;
2153 LOGE("disable overlay");
2154 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2156 /* release overlay resource */
2157 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2158 LOGE("failed to release overlay resource");
2159 return MM_ERROR_PLAYER_INTERNAL;
2162 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2163 LOGE("failed to acquire video overlay resource");
2164 return MM_ERROR_PLAYER_INTERNAL;
2166 player->interrupted_by_resource = FALSE;
2168 LOGD("enable overlay");
2169 __mmplayer_video_param_set_display_overlay(player);
2170 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2174 return MM_ERROR_NONE;
2178 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2180 int ret = MM_ERROR_NONE;
2181 mmplayer_t *player = (mmplayer_t *)hplayer;
2184 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2186 if (MMPLAYER_USE_DECODEBIN(player)) {
2187 ret = __mmplayer_set_disable_overlay_option(player, audio_only);
2192 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2193 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2194 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2196 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, INVALID_TRACK_INDEX);
2198 /* release decoder resource */
2199 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
2200 LOGE("failed to release video decoder resources");
2201 return MM_ERROR_PLAYER_INTERNAL;
2203 player->can_support_codec &= ~FOUND_PLUGIN_VIDEO;
2205 __mmplayer_switch_stream(player, MM_PLAYER_TRACK_TYPE_VIDEO, DEFAULT_TRACK_INDEX);
2209 mm_player_set_attribute(hplayer, NULL, MM_PLAYER_AUDIO_ONLY, (int)audio_only, (char *)NULL);
2216 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2218 GList *bucket = element_bucket;
2219 mmplayer_gst_element_t *element = NULL;
2220 mmplayer_gst_element_t *prv_element = NULL;
2221 GstElement *tee_element = NULL;
2222 gint successful_link_count = 0;
2226 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2228 prv_element = (mmplayer_gst_element_t *)bucket->data;
2229 bucket = bucket->next;
2231 for (; bucket; bucket = bucket->next) {
2232 element = (mmplayer_gst_element_t *)bucket->data;
2234 if (element && element->gst) {
2235 if (prv_element && prv_element->gst) {
2236 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2238 prv_element->gst = tee_element;
2240 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2241 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2242 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2246 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2247 LOGD("linking [%s] to [%s] success",
2248 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2249 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2250 successful_link_count++;
2251 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2252 LOGD("keep audio-tee element for next audio pipeline branch");
2253 tee_element = prv_element->gst;
2256 LOGD("linking [%s] to [%s] failed",
2257 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2258 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2264 prv_element = element;
2269 return successful_link_count;
2273 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2275 GList *bucket = element_bucket;
2276 mmplayer_gst_element_t *element = NULL;
2277 int successful_add_count = 0;
2281 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2282 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2284 for (; bucket; bucket = bucket->next) {
2285 element = (mmplayer_gst_element_t *)bucket->data;
2287 if (element && element->gst) {
2288 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2289 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2290 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2291 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2294 successful_add_count++;
2300 return successful_add_count;
2304 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2306 mmplayer_t *player = (mmplayer_t *)data;
2307 GstCaps *caps = NULL;
2308 GstStructure *str = NULL;
2310 gboolean caps_ret = TRUE;
2314 MMPLAYER_RETURN_IF_FAIL(pad);
2315 MMPLAYER_RETURN_IF_FAIL(unused);
2316 MMPLAYER_RETURN_IF_FAIL(data);
2318 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2322 LOGD("name = %s", name);
2324 if (strstr(name, "audio")) {
2325 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2327 if (player->audio_stream_changed_cb) {
2328 LOGE("call the audio stream changed cb");
2329 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2331 } else if (strstr(name, "video")) {
2332 if ((name = gst_structure_get_string(str, "format")))
2333 player->set_mode.video_zc = name[0] == 'S';
2335 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2336 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2338 LOGW("invalid caps info");
2343 gst_caps_unref(caps);
2351 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2356 MMPLAYER_RETURN_IF_FAIL(player);
2358 if (player->audio_stream_buff_list) {
2359 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2360 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2363 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2364 __mmplayer_audio_stream_send_data(player, tmp);
2366 MMPLAYER_FREEIF(tmp->pcm_data);
2367 MMPLAYER_FREEIF(tmp);
2370 g_list_free(player->audio_stream_buff_list);
2371 player->audio_stream_buff_list = NULL;
2378 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2380 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2383 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2385 audio_stream.bitrate = a_buffer->bitrate;
2386 audio_stream.channel = a_buffer->channel;
2387 audio_stream.channel_mask = a_buffer->channel_mask;
2388 audio_stream.data_size = a_buffer->data_size;
2389 audio_stream.data = a_buffer->pcm_data;
2390 audio_stream.pcm_format = a_buffer->pcm_format;
2392 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2394 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2400 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2402 mmplayer_t *player = (mmplayer_t *)data;
2403 const gchar *pcm_format = NULL;
2406 guint64 channel_mask = 0;
2407 void *a_data = NULL;
2409 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2410 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2414 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2416 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2417 a_data = mapinfo.data;
2418 a_size = mapinfo.size;
2420 GstCaps *caps = gst_pad_get_current_caps(pad);
2421 GstStructure *structure = gst_caps_get_structure(caps, 0);
2423 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2425 pcm_format = gst_structure_get_string(structure, "format");
2426 gst_structure_get_int(structure, "rate", &rate);
2427 gst_structure_get_int(structure, "channels", &channel);
2428 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2429 gst_caps_unref(GST_CAPS(caps));
2431 /* In case of the sync is false, use buffer list. *
2432 * The num of buffer list depends on the num of audio channels */
2433 if (player->audio_stream_buff_list) {
2434 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2435 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2437 if (channel_mask == tmp->channel_mask) {
2439 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2441 if (tmp->data_size + a_size < tmp->buff_size) {
2442 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2443 tmp->data_size += a_size;
2445 /* send data to client */
2446 __mmplayer_audio_stream_send_data(player, tmp);
2448 if (a_size > tmp->buff_size) {
2449 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2450 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2451 if (tmp->pcm_data == NULL) {
2452 LOGE("failed to realloc data.");
2455 tmp->buff_size = a_size;
2457 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2458 memcpy(tmp->pcm_data, a_data, a_size);
2459 tmp->data_size = a_size;
2464 LOGE("data is empty in list.");
2470 /* create new audio stream data for newly found audio channel */
2471 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2472 if (a_buffer == NULL) {
2473 LOGE("failed to alloc data.");
2476 a_buffer->bitrate = rate;
2477 a_buffer->channel = channel;
2478 a_buffer->channel_mask = channel_mask;
2479 a_buffer->data_size = a_size;
2480 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2482 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2483 /* If sync is FALSE, use buffer list to reduce the IPC. */
2484 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2485 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2486 if (a_buffer->pcm_data == NULL) {
2487 LOGE("failed to alloc data.");
2488 MMPLAYER_FREEIF(a_buffer);
2491 memcpy(a_buffer->pcm_data, a_data, a_size);
2493 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2495 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2497 /* If sync is TRUE, send data directly. */
2498 a_buffer->pcm_data = a_data;
2499 __mmplayer_audio_stream_send_data(player, a_buffer);
2500 MMPLAYER_FREEIF(a_buffer);
2504 gst_buffer_unmap(buffer, &mapinfo);
2509 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2511 mmplayer_t *player = (mmplayer_t *)data;
2512 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2513 GstPad *sinkpad = NULL;
2514 GstElement *queue = NULL, *sink = NULL;
2517 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2519 queue = gst_element_factory_make("queue", NULL);
2520 if (queue == NULL) {
2521 LOGD("fail make queue");
2525 sink = gst_element_factory_make("fakesink", NULL);
2527 LOGD("fail make fakesink");
2531 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2533 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2534 LOGW("failed to link queue & sink");
2538 sinkpad = gst_element_get_static_pad(queue, "sink");
2540 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2541 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2545 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2547 gst_object_unref(sinkpad);
2548 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2549 g_object_set(sink, "sync", TRUE, NULL);
2550 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2552 /* keep the first sink reference only */
2553 if (!audiobin[MMPLAYER_A_SINK].gst) {
2554 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2555 audiobin[MMPLAYER_A_SINK].gst = sink;
2559 _mmplayer_add_signal_connection(player,
2561 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2563 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2566 __mmplayer_add_sink(player, sink, FALSE);
2568 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2569 LOGE("failed to sync state");
2573 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2574 LOGE("failed to sync state");
2582 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2584 gst_object_unref(GST_OBJECT(queue));
2588 gst_object_unref(GST_OBJECT(sink));
2592 gst_object_unref(GST_OBJECT(sinkpad));
2600 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2602 mmplayer_t *player = (mmplayer_t *)data;
2605 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2607 player->no_more_pad = TRUE;
2608 _mmplayer_pipeline_complete(NULL, player);
2615 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2617 #define MAX_PROPS_LEN 128
2618 mmplayer_gst_element_t *audiobin = NULL;
2619 gint latency_mode = 0;
2620 gchar *stream_type = NULL;
2621 gchar *latency = NULL;
2623 gchar stream_props[MAX_PROPS_LEN] = {0,};
2624 GstStructure *props = NULL;
2627 * It should be set after player creation through attribute.
2628 * But, it can not be changed during playing.
2631 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2633 audiobin = player->pipeline->audiobin;
2635 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2636 if (player->sound.mute) {
2637 LOGD("mute enabled");
2638 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2641 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2642 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2645 snprintf(stream_props, sizeof(stream_props) - 1,
2646 "props,application.process.id.origin=%d", player->client_pid);
2648 snprintf(stream_props, sizeof(stream_props) - 1,
2649 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2650 stream_type, stream_id, player->client_pid);
2652 props = gst_structure_from_string(stream_props, NULL);
2653 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2654 LOGI("props result[%s].", stream_props);
2655 gst_structure_free(props);
2657 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2659 switch (latency_mode) {
2660 case AUDIO_LATENCY_MODE_LOW:
2661 latency = g_strdup("low");
2663 case AUDIO_LATENCY_MODE_MID:
2664 latency = g_strdup("mid");
2666 case AUDIO_LATENCY_MODE_HIGH:
2667 latency = g_strdup("high");
2670 latency = g_strdup("mid");
2674 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2676 LOGD("audiosink property - latency=%s", latency);
2678 MMPLAYER_FREEIF(latency);
2684 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2686 mmplayer_gst_element_t *audiobin = NULL;
2689 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2690 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2692 audiobin = player->pipeline->audiobin;
2694 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2695 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2696 LOGE("failed to create media stream info");
2697 return MM_ERROR_PLAYER_INTERNAL;
2700 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2702 if (player->video360_yaw_radians <= M_PI &&
2703 player->video360_yaw_radians >= -M_PI &&
2704 player->video360_pitch_radians <= M_PI_2 &&
2705 player->video360_pitch_radians >= -M_PI_2) {
2706 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2707 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2708 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2709 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2710 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2711 "source-orientation-y", player->video360_metadata.init_view_heading,
2712 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2716 return MM_ERROR_NONE;
2720 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2722 mmplayer_gst_element_t *audiobin = NULL;
2723 GstPad *sink_pad = NULL;
2724 GstCaps *acaps = NULL;
2726 int pitch_control = 0;
2727 double pitch_value = 1.0;
2730 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2731 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2733 audiobin = player->pipeline->audiobin;
2735 LOGD("make element for normal audio playback");
2737 /* audio bin structure for playback. {} means optional.
2738 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2740 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2741 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2744 /* for pitch control */
2745 mm_attrs_multiple_get(player->attrs, NULL,
2746 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2747 MM_PLAYER_PITCH_VALUE, &pitch_value,
2750 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2751 if (pitch_control && (player->videodec_linked == 0)) {
2752 GstElementFactory *factory;
2754 factory = gst_element_factory_find("pitch");
2756 gst_object_unref(factory);
2759 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2762 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2763 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2765 LOGW("there is no pitch element");
2770 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2772 /* replaygain volume */
2773 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2774 if (player->sound.rg_enable)
2775 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2777 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2780 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2782 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2783 /* currently, only openalsink uses volume element */
2784 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2785 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2787 if (player->sound.mute) {
2788 LOGD("mute enabled");
2789 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2793 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2795 /* audio effect element. if audio effect is enabled */
2796 if ((strcmp(player->ini.audioeffect_element, ""))
2798 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2799 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2801 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2803 if ((!player->bypass_audio_effect)
2804 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2805 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2806 if (!_mmplayer_audio_effect_custom_apply(player))
2807 LOGI("apply audio effect(custom) setting success");
2811 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2812 && (player->set_mode.rich_audio)) {
2813 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2817 /* create audio sink */
2818 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2819 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2820 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2822 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2823 if (player->is_360_feature_enabled &&
2824 player->is_content_spherical &&
2826 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2827 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2828 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2830 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2832 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2834 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2835 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2836 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2837 gst_caps_unref(acaps);
2839 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2841 player->is_openal_plugin_used = TRUE;
2843 if (player->is_360_feature_enabled && player->is_content_spherical)
2844 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2845 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2848 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2849 (player->videodec_linked && player->ini.use_system_clock)) {
2850 LOGD("system clock will be used.");
2851 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2854 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2855 __mmplayer_gst_set_pulsesink_property(player);
2856 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2857 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2862 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2863 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2865 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2866 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2867 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2868 gst_object_unref(GST_OBJECT(sink_pad));
2870 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2873 return MM_ERROR_NONE;
2875 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2877 return MM_ERROR_PLAYER_INTERNAL;
2881 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2883 mmplayer_gst_element_t *audiobin = NULL;
2884 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2886 gchar *dst_format = NULL;
2888 int dst_samplerate = 0;
2889 int dst_channels = 0;
2890 GstCaps *caps = NULL;
2891 char *caps_str = NULL;
2894 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2895 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2897 audiobin = player->pipeline->audiobin;
2899 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2901 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2903 [case 1] extract interleave audio pcm without playback
2904 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2905 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2907 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2909 [case 2] deinterleave for each channel without playback
2910 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2911 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2913 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2914 - fakesink (sync or not)
2917 [case 3] [case 1(sync only)] + playback
2918 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2920 * src - ... - tee - queue1 - playback path
2921 - queue2 - [case1 pipeline with sync]
2923 [case 4] [case 2(sync only)] + playback
2924 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2926 * src - ... - tee - queue1 - playback path
2927 - queue2 - [case2 pipeline with sync]
2931 /* 1. create tee and playback path
2932 'tee' should be added at first to copy the decoded stream
2934 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2935 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2936 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2938 /* tee - path 1 : for playback path */
2939 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2940 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2942 /* tee - path 2 : for extract path */
2943 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2944 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2947 /* if there is tee, 'tee - path 2' is linked here */
2949 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2952 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2954 /* 2. decide the extract pcm format */
2955 mm_attrs_multiple_get(player->attrs, NULL,
2956 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2957 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2958 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2961 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2962 dst_format, dst_len, dst_samplerate, dst_channels);
2964 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2965 mm_attrs_multiple_get(player->attrs, NULL,
2966 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2967 "content_audio_samplerate", &dst_samplerate,
2968 "content_audio_channels", &dst_channels,
2971 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2972 dst_format, dst_len, dst_samplerate, dst_channels);
2974 /* If there is no enough information, set it to platform default value. */
2975 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2976 LOGD("set platform default format");
2977 dst_format = DEFAULT_PCM_OUT_FORMAT;
2979 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2980 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2983 /* 3. create capsfilter */
2984 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2985 caps = gst_caps_new_simple("audio/x-raw",
2986 "format", G_TYPE_STRING, dst_format,
2987 "rate", G_TYPE_INT, dst_samplerate,
2988 "channels", G_TYPE_INT, dst_channels,
2991 caps_str = gst_caps_to_string(caps);
2992 LOGD("new caps : %s", caps_str);
2994 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2997 gst_caps_unref(caps);
2998 MMPLAYER_FREEIF(caps_str);
3000 /* 4-1. create deinterleave to extract pcm for each channel */
3001 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
3002 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
3003 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3005 /* audiosink will be added after getting signal for each channel */
3006 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3007 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3008 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3009 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3010 player->no_more_pad = FALSE;
3012 /* 4-2. create fakesink to extract interlevaed pcm */
3013 LOGD("add audio fakesink for interleaved audio");
3014 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3015 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3016 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3017 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3019 _mmplayer_add_signal_connection(player,
3020 G_OBJECT(audiobin[extract_sink_id].gst),
3021 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3023 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3026 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3030 return MM_ERROR_NONE;
3032 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3034 return MM_ERROR_PLAYER_INTERNAL;
3038 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3040 int ret = MM_ERROR_NONE;
3041 mmplayer_gst_element_t *audiobin = NULL;
3042 GList *element_bucket = NULL;
3045 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3046 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3048 audiobin = player->pipeline->audiobin;
3050 if (player->build_audio_offload) { /* skip all the audio filters */
3051 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3053 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3054 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3055 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3057 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3061 /* FIXME: need to mention the supportable condition at API reference */
3062 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3063 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3065 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3067 if (ret != MM_ERROR_NONE)
3070 LOGD("success to make audio bin element");
3071 *bucket = element_bucket;
3074 return MM_ERROR_NONE;
3077 LOGE("failed to make audio bin element");
3078 g_list_free(element_bucket);
3082 return MM_ERROR_PLAYER_INTERNAL;
3086 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3088 mmplayer_gst_element_t *first_element = NULL;
3089 mmplayer_gst_element_t *audiobin = NULL;
3091 GstPad *ghostpad = NULL;
3092 GList *element_bucket = NULL;
3096 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3099 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3101 LOGE("failed to allocate memory for audiobin");
3102 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3106 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3107 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3108 if (!audiobin[MMPLAYER_A_BIN].gst) {
3109 LOGE("failed to create audiobin");
3114 player->pipeline->audiobin = audiobin;
3116 /* create audio filters and audiosink */
3117 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3120 /* adding created elements to bin */
3121 LOGD("adding created elements to bin");
3122 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3125 /* linking elements in the bucket by added order. */
3126 LOGD("Linking elements in the bucket by added order.");
3127 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3130 /* get first element's sinkpad for creating ghostpad */
3131 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3132 if (!first_element) {
3133 LOGE("failed to get first elem");
3137 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3139 LOGE("failed to get pad from first element of audiobin");
3143 ghostpad = gst_ghost_pad_new("sink", pad);
3145 LOGE("failed to create ghostpad");
3149 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3150 LOGE("failed to add ghostpad to audiobin");
3154 gst_object_unref(pad);
3156 g_list_free(element_bucket);
3159 return MM_ERROR_NONE;
3162 LOGD("ERROR : releasing audiobin");
3165 gst_object_unref(GST_OBJECT(pad));
3168 gst_object_unref(GST_OBJECT(ghostpad));
3171 g_list_free(element_bucket);
3173 /* release element which are not added to bin */
3174 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3175 /* NOTE : skip bin */
3176 if (audiobin[i].gst) {
3177 GstObject *parent = NULL;
3178 parent = gst_element_get_parent(audiobin[i].gst);
3181 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3182 audiobin[i].gst = NULL;
3184 gst_object_unref(GST_OBJECT(parent));
3188 /* release audiobin with it's children */
3189 if (audiobin[MMPLAYER_A_BIN].gst)
3190 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3192 MMPLAYER_FREEIF(audiobin);
3194 player->pipeline->audiobin = NULL;
3196 return MM_ERROR_PLAYER_INTERNAL;
3200 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3202 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3206 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3208 int ret = MM_ERROR_NONE;
3210 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3211 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3213 MMPLAYER_VIDEO_BO_LOCK(player);
3215 if (player->video_bo_list) {
3216 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3217 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3218 if (tmp && tmp->bo == bo) {
3220 LOGD("release bo %p", bo);
3221 tbm_bo_unref(tmp->bo);
3222 MMPLAYER_VIDEO_BO_UNLOCK(player);
3223 MMPLAYER_VIDEO_BO_SIGNAL(player);
3228 /* hw codec is running or the list was reset for DRC. */
3229 LOGW("there is no bo list.");
3231 MMPLAYER_VIDEO_BO_UNLOCK(player);
3233 LOGW("failed to find bo %p", bo);
3237 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3243 tbm_bo_unref(tmp->bo);
3248 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3251 MMPLAYER_RETURN_IF_FAIL(player);
3253 MMPLAYER_VIDEO_BO_LOCK(player);
3254 if (player->video_bo_list) {
3255 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3256 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3257 player->video_bo_list = NULL;
3259 player->video_bo_size = 0;
3260 MMPLAYER_VIDEO_BO_UNLOCK(player);
3267 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3270 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3271 gboolean ret = TRUE;
3273 /* check DRC, if it is, destroy the prev bo list to create again */
3274 if (player->video_bo_size != size) {
3275 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3276 __mmplayer_video_stream_destroy_bo_list(player);
3277 player->video_bo_size = size;
3280 MMPLAYER_VIDEO_BO_LOCK(player);
3282 if ((!player->video_bo_list) ||
3283 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3285 /* create bo list */
3287 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3289 if (player->video_bo_list) {
3290 /* if bo list did not created all, try it again. */
3291 idx = g_list_length(player->video_bo_list);
3292 LOGD("bo list exist(len: %d)", idx);
3295 for (; idx < player->ini.num_of_video_bo; idx++) {
3296 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3298 LOGE("Fail to alloc bo_info.");
3301 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3303 LOGE("Fail to tbm_bo_alloc.");
3304 MMPLAYER_FREEIF(bo_info);
3307 bo_info->used = FALSE;
3308 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3311 /* update video num buffers */
3312 LOGD("video_num_buffers : %d", idx);
3313 mm_player_set_attribute((MMHandleType)player, NULL,
3314 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3315 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3319 MMPLAYER_VIDEO_BO_UNLOCK(player);
3325 /* get bo from list*/
3326 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3327 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3328 if (tmp && (tmp->used == FALSE)) {
3329 LOGD("found bo %p to use", tmp->bo);
3331 MMPLAYER_VIDEO_BO_UNLOCK(player);
3332 return tbm_bo_ref(tmp->bo);
3336 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3337 MMPLAYER_VIDEO_BO_UNLOCK(player);
3341 if (player->ini.video_bo_timeout <= 0) {
3342 MMPLAYER_VIDEO_BO_WAIT(player);
3344 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3345 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3352 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3354 mmplayer_t *player = (mmplayer_t *)data;
3356 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3358 /* send prerolled pkt */
3359 player->video_stream_prerolled = false;
3361 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3363 /* not to send prerolled pkt again */
3364 player->video_stream_prerolled = true;
3368 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3370 mmplayer_t *player = (mmplayer_t *)data;
3371 mmplayer_video_decoded_data_info_t *stream = NULL;
3372 GstMemory *mem = NULL;
3375 MMPLAYER_RETURN_IF_FAIL(player);
3376 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3378 if (player->video_stream_prerolled) {
3379 player->video_stream_prerolled = false;
3380 LOGD("skip the prerolled pkt not to send it again");
3384 /* clear stream data structure */
3385 stream = __mmplayer_create_stream_from_pad(pad);
3387 LOGE("failed to alloc stream");
3391 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3393 /* set size and timestamp */
3394 mem = gst_buffer_peek_memory(buffer, 0);
3395 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3396 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3398 /* check zero-copy */
3399 if (player->set_mode.video_zc &&
3400 player->set_mode.video_export &&
3401 gst_is_tizen_memory(mem)) {
3402 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3403 stream->internal_buffer = gst_buffer_ref(buffer);
3404 } else { /* sw codec */
3405 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3408 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3412 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3413 LOGE("failed to send video decoded data.");
3420 LOGE("release video stream resource.");
3421 if (gst_is_tizen_memory(mem)) {
3423 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3425 tbm_bo_unref(stream->bo[i]);
3428 /* unref gst buffer */
3429 if (stream->internal_buffer)
3430 gst_buffer_unref(stream->internal_buffer);
3433 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3435 MMPLAYER_FREEIF(stream);
3440 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3442 mmplayer_gst_element_t *videobin = NULL;
3445 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3447 videobin = player->pipeline->videobin;
3449 /* Set spatial media metadata and/or user settings to the element.
3451 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3452 "projection-type", player->video360_metadata.projection_type, NULL);
3454 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3455 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3457 if (player->video360_metadata.full_pano_width_pixels &&
3458 player->video360_metadata.full_pano_height_pixels &&
3459 player->video360_metadata.cropped_area_image_width &&
3460 player->video360_metadata.cropped_area_image_height) {
3461 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3462 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3463 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3464 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3465 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3466 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3467 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3471 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3472 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3473 "horizontal-fov", player->video360_horizontal_fov,
3474 "vertical-fov", player->video360_vertical_fov, NULL);
3477 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3478 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3479 "zoom", 1.0f / player->video360_zoom, NULL);
3482 if (player->video360_yaw_radians <= M_PI &&
3483 player->video360_yaw_radians >= -M_PI &&
3484 player->video360_pitch_radians <= M_PI_2 &&
3485 player->video360_pitch_radians >= -M_PI_2) {
3486 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3487 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3488 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3489 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3490 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3491 "pose-yaw", player->video360_metadata.init_view_heading,
3492 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3495 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3496 "passthrough", !player->is_video360_enabled, NULL);
3503 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3505 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3506 GList *element_bucket = NULL;
3509 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3511 /* create video360 filter */
3512 if (player->is_360_feature_enabled && player->is_content_spherical) {
3513 LOGD("create video360 element");
3514 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3515 __mmplayer_gst_set_video360_property(player);
3519 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3520 LOGD("skip creating the videoconv and rotator");
3521 return MM_ERROR_NONE;
3524 /* in case of sw codec & overlay surface type, except 360 playback.
3525 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3526 LOGD("create video converter: %s", video_csc);
3527 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3530 *bucket = element_bucket;
3532 return MM_ERROR_NONE;
3534 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3535 g_list_free(element_bucket);
3539 return MM_ERROR_PLAYER_INTERNAL;
3543 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3545 gchar *factory_name = NULL;
3547 switch (surface_type) {
3548 case MM_DISPLAY_SURFACE_OVERLAY:
3549 if (strlen(player->ini.videosink_element_overlay) > 0)
3550 factory_name = player->ini.videosink_element_overlay;
3552 case MM_DISPLAY_SURFACE_REMOTE:
3553 case MM_DISPLAY_SURFACE_NULL:
3554 if (strlen(player->ini.videosink_element_fake) > 0)
3555 factory_name = player->ini.videosink_element_fake;
3558 LOGE("unidentified surface type");
3562 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3563 return factory_name;
3567 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3569 gchar *factory_name = NULL;
3570 mmplayer_gst_element_t *videobin = NULL;
3575 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3577 videobin = player->pipeline->videobin;
3578 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3580 attrs = MMPLAYER_GET_ATTRS(player);
3582 LOGE("cannot get content attribute");
3583 return MM_ERROR_PLAYER_INTERNAL;
3586 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3587 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3588 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3589 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3590 "use-tbm", use_tbm, NULL);
3593 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3594 return MM_ERROR_PLAYER_INTERNAL;
3596 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3599 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3600 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3603 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3605 LOGD("disable last-sample");
3606 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3609 if (player->set_mode.video_export) {
3611 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3612 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3613 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3615 _mmplayer_add_signal_connection(player,
3616 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3617 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3619 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3622 _mmplayer_add_signal_connection(player,
3623 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3624 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3626 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3630 if (videobin[MMPLAYER_V_SINK].gst) {
3631 GstPad *sink_pad = NULL;
3632 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3634 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3635 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3636 gst_object_unref(GST_OBJECT(sink_pad));
3638 LOGE("failed to get sink pad from videosink");
3642 return MM_ERROR_NONE;
3647 * - video overlay surface(arm/x86) : tizenwlsink
3650 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3653 GList *element_bucket = NULL;
3654 mmplayer_gst_element_t *first_element = NULL;
3655 mmplayer_gst_element_t *videobin = NULL;
3656 gchar *videosink_factory_name = NULL;
3659 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3662 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3664 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3666 player->pipeline->videobin = videobin;
3669 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3670 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3671 if (!videobin[MMPLAYER_V_BIN].gst) {
3672 LOGE("failed to create videobin");
3676 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3679 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3680 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3682 /* additional setting for sink plug-in */
3683 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3684 LOGE("failed to set video property");
3688 /* store it as it's sink element */
3689 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3691 /* adding created elements to bin */
3692 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3693 LOGE("failed to add elements");
3697 /* Linking elements in the bucket by added order */
3698 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3699 LOGE("failed to link elements");
3703 /* get first element's sinkpad for creating ghostpad */
3704 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3705 if (!first_element) {
3706 LOGE("failed to get first element from bucket");
3710 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3712 LOGE("failed to get pad from first element");
3716 /* create ghostpad */
3717 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3718 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3719 LOGE("failed to add ghostpad to videobin");
3722 gst_object_unref(pad);
3724 /* done. free allocated variables */
3725 g_list_free(element_bucket);
3729 return MM_ERROR_NONE;
3732 LOGE("ERROR : releasing videobin");
3733 g_list_free(element_bucket);
3736 gst_object_unref(GST_OBJECT(pad));
3738 /* release videobin with it's children */
3739 if (videobin[MMPLAYER_V_BIN].gst)
3740 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3742 MMPLAYER_FREEIF(videobin);
3743 player->pipeline->videobin = NULL;
3745 return MM_ERROR_PLAYER_INTERNAL;
3749 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3751 GList *element_bucket = NULL;
3752 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3754 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3755 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3756 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3757 "signal-handoffs", FALSE,
3760 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3761 _mmplayer_add_signal_connection(player,
3762 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3763 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3765 G_CALLBACK(__mmplayer_update_subtitle),
3768 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3769 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3771 if (!player->play_subtitle) {
3772 LOGD("add textbin sink as sink element of whole pipeline.");
3773 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3776 /* adding created elements to bin */
3777 LOGD("adding created elements to bin");
3778 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3779 LOGE("failed to add elements");
3780 g_list_free(element_bucket);
3784 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3785 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3786 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3788 /* linking elements in the bucket by added order. */
3789 LOGD("Linking elements in the bucket by added order.");
3790 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3791 LOGE("failed to link elements");
3792 g_list_free(element_bucket);
3796 /* done. free allocated variables */
3797 g_list_free(element_bucket);
3799 if (textbin[MMPLAYER_T_QUEUE].gst) {
3801 GstPad *ghostpad = NULL;
3803 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3805 LOGE("failed to get sink pad of text queue");
3809 ghostpad = gst_ghost_pad_new("text_sink", pad);
3810 gst_object_unref(pad);
3813 LOGE("failed to create ghostpad of textbin");
3817 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3818 LOGE("failed to add ghostpad to textbin");
3819 gst_object_unref(ghostpad);
3824 return MM_ERROR_NONE;
3828 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3829 LOGE("remove textbin sink from sink list");
3830 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3833 /* release element at __mmplayer_gst_create_text_sink_bin */
3834 return MM_ERROR_PLAYER_INTERNAL;
3838 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3840 mmplayer_gst_element_t *textbin = NULL;
3841 GList *element_bucket = NULL;
3842 int surface_type = 0;
3847 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3850 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3852 LOGE("failed to allocate memory for textbin");
3853 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3857 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3858 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3859 if (!textbin[MMPLAYER_T_BIN].gst) {
3860 LOGE("failed to create textbin");
3865 player->pipeline->textbin = textbin;
3868 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3869 LOGD("surface type for subtitle : %d", surface_type);
3870 switch (surface_type) {
3871 case MM_DISPLAY_SURFACE_OVERLAY:
3872 case MM_DISPLAY_SURFACE_NULL:
3873 case MM_DISPLAY_SURFACE_REMOTE:
3874 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3875 LOGE("failed to make plain text elements");
3886 return MM_ERROR_NONE;
3890 LOGD("ERROR : releasing textbin");
3892 g_list_free(element_bucket);
3894 /* release signal */
3895 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3897 /* release element which are not added to bin */
3898 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3899 /* NOTE : skip bin */
3900 if (textbin[i].gst) {
3901 GstObject *parent = NULL;
3902 parent = gst_element_get_parent(textbin[i].gst);
3905 gst_object_unref(GST_OBJECT(textbin[i].gst));
3906 textbin[i].gst = NULL;
3908 gst_object_unref(GST_OBJECT(parent));
3913 /* release textbin with it's children */
3914 if (textbin[MMPLAYER_T_BIN].gst)
3915 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3917 MMPLAYER_FREEIF(textbin);
3918 player->pipeline->textbin = NULL;
3921 return MM_ERROR_PLAYER_INTERNAL;
3925 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3927 mmplayer_gst_element_t *mainbin = NULL;
3928 mmplayer_gst_element_t *textbin = NULL;
3929 MMHandleType attrs = 0;
3930 GstElement *subsrc = NULL;
3931 GstElement *subparse = NULL;
3932 gchar *subtitle_uri = NULL;
3933 const gchar *charset = NULL;
3939 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3941 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3943 mainbin = player->pipeline->mainbin;
3945 attrs = MMPLAYER_GET_ATTRS(player);
3947 LOGE("cannot get content attribute");
3948 return MM_ERROR_PLAYER_INTERNAL;
3951 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3952 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3953 LOGE("subtitle uri is not proper filepath.");
3954 return MM_ERROR_PLAYER_INVALID_URI;
3957 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3958 LOGE("failed to get storage info of subtitle path");
3959 return MM_ERROR_PLAYER_INVALID_URI;
3962 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3964 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3965 player->subtitle_language_list = NULL;
3966 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3968 /* create the subtitle source */
3969 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3971 LOGE("failed to create filesrc element");
3974 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3976 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3977 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3979 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3980 LOGW("failed to add queue");
3981 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3982 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3983 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3988 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3990 LOGE("failed to create subparse element");
3994 charset = _mmplayer_get_charset(subtitle_uri);
3996 LOGD("detected charset is %s", charset);
3997 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
4000 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
4001 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
4003 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
4004 LOGW("failed to add subparse");
4005 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4006 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4007 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4011 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4012 LOGW("failed to link subsrc and subparse");
4016 player->play_subtitle = TRUE;
4017 player->adjust_subtitle_pos = 0;
4019 LOGD("play subtitle using subtitle file");
4021 if (player->pipeline->textbin == NULL) {
4022 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4023 LOGE("failed to create text sink bin. continuing without text");
4027 textbin = player->pipeline->textbin;
4029 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4030 LOGW("failed to add textbin");
4032 /* release signal */
4033 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4035 /* release textbin with it's children */
4036 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4037 MMPLAYER_FREEIF(player->pipeline->textbin);
4038 player->pipeline->textbin = textbin = NULL;
4042 LOGD("link text input selector and textbin ghost pad");
4044 player->textsink_linked = 1;
4045 player->external_text_idx = 0;
4046 LOGI("textsink is linked");
4048 textbin = player->pipeline->textbin;
4049 LOGD("text bin has been created. reuse it.");
4050 player->external_text_idx = 1;
4053 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4054 LOGW("failed to link subparse and textbin");
4058 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4060 LOGE("failed to get sink pad from textsink to probe data");
4064 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4065 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4067 gst_object_unref(pad);
4070 /* create dot. for debugging */
4071 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4074 return MM_ERROR_NONE;
4077 /* release text pipeline resource */
4078 player->textsink_linked = 0;
4080 /* release signal */
4081 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4083 if (player->pipeline->textbin) {
4084 LOGE("remove textbin");
4086 /* release textbin with it's children */
4087 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4088 MMPLAYER_FREEIF(player->pipeline->textbin);
4089 player->pipeline->textbin = NULL;
4093 /* release subtitle elem */
4094 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4095 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4097 return MM_ERROR_PLAYER_INTERNAL;
4101 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4103 mmplayer_t *player = (mmplayer_t *)data;
4104 MMMessageParamType msg = {0, };
4105 GstClockTime duration = 0;
4106 gpointer text = NULL;
4107 guint text_size = 0;
4108 gboolean ret = TRUE;
4109 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4113 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4114 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4116 if (player->is_subtitle_force_drop) {
4117 LOGW("subtitle is dropped forcedly.");
4121 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4122 text = mapinfo.data;
4123 text_size = mapinfo.size;
4125 if (player->set_mode.subtitle_off) {
4126 LOGD("subtitle is OFF.");
4130 if (!text || (text_size == 0)) {
4131 LOGD("There is no subtitle to be displayed.");
4135 msg.data = (void *)text;
4137 duration = GST_BUFFER_DURATION(buffer);
4139 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4140 if (player->duration > GST_BUFFER_PTS(buffer))
4141 duration = player->duration - GST_BUFFER_PTS(buffer);
4144 LOGI("subtitle duration is invalid, subtitle duration change "
4145 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4147 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4149 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4151 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4152 gst_buffer_unmap(buffer, &mapinfo);
4159 static GstPadProbeReturn
4160 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4162 mmplayer_t *player = (mmplayer_t *)u_data;
4163 GstClockTime cur_timestamp = 0;
4164 gint64 adjusted_timestamp = 0;
4165 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4167 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4169 if (player->set_mode.subtitle_off) {
4170 LOGD("subtitle is OFF.");
4174 if (player->adjust_subtitle_pos == 0) {
4175 LOGD("nothing to do");
4179 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4180 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4182 if (adjusted_timestamp < 0) {
4183 LOGD("adjusted_timestamp under zero");
4188 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4189 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4190 GST_TIME_ARGS(cur_timestamp),
4191 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4193 return GST_PAD_PROBE_OK;
4197 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4201 /* check player and subtitlebin are created */
4202 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4203 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4205 if (position == 0) {
4206 LOGD("nothing to do");
4208 return MM_ERROR_NONE;
4211 /* check current position */
4212 player->adjust_subtitle_pos = position;
4214 LOGD("save adjust_subtitle_pos in player");
4218 return MM_ERROR_NONE;
4222 * This function is to create audio or video pipeline for playing.
4224 * @param player [in] handle of player
4226 * @return This function returns zero on success.
4231 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4233 int ret = MM_ERROR_NONE;
4234 mmplayer_gst_element_t *mainbin = NULL;
4235 MMHandleType attrs = 0;
4238 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4240 /* get profile attribute */
4241 attrs = MMPLAYER_GET_ATTRS(player);
4243 LOGE("failed to get content attribute");
4247 /* create pipeline handles */
4248 if (player->pipeline) {
4249 LOGE("pipeline should be released before create new one");
4253 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4255 /* create mainbin */
4256 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4257 if (mainbin == NULL)
4260 /* create pipeline */
4261 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4262 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4263 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4264 LOGE("failed to create pipeline");
4269 player->pipeline->mainbin = mainbin;
4271 /* create the source and decoder elements */
4272 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4273 ret = _mmplayer_gst_build_es_pipeline(player);
4275 if (MMPLAYER_USE_DECODEBIN(player))
4276 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4278 ret = _mmplayer_gst_build_pipeline_with_src(player);
4281 if (ret != MM_ERROR_NONE) {
4282 LOGE("failed to create some elements");
4286 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4287 if (__mmplayer_check_subtitle(player)
4288 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4289 LOGE("failed to create text pipeline");
4292 ret = _mmplayer_gst_add_bus_watch(player);
4293 if (ret != MM_ERROR_NONE) {
4294 LOGE("failed to add bus watch");
4299 return MM_ERROR_NONE;
4302 _mmplayer_bus_watcher_remove(player);
4303 __mmplayer_gst_destroy_pipeline(player);
4304 return MM_ERROR_PLAYER_INTERNAL;
4308 __mmplayer_reset_gapless_state(mmplayer_t *player)
4311 MMPLAYER_RETURN_IF_FAIL(player
4313 && player->pipeline->audiobin
4314 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4316 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4323 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4326 int ret = MM_ERROR_NONE;
4330 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4332 /* cleanup stuffs */
4333 MMPLAYER_FREEIF(player->type);
4334 player->no_more_pad = FALSE;
4335 player->num_dynamic_pad = 0;
4337 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4338 player->subtitle_language_list = NULL;
4339 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4341 MMPLAYER_RECONFIGURE_LOCK(player);
4342 __mmplayer_reset_gapless_state(player);
4343 MMPLAYER_RECONFIGURE_UNLOCK(player);
4345 if (player->streamer) {
4346 _mm_player_streaming_initialize(player->streamer, FALSE);
4347 _mm_player_streaming_destroy(player->streamer);
4348 player->streamer = NULL;
4351 /* cleanup unlinked mime type */
4352 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4353 MMPLAYER_FREEIF(player->unlinked_video_mime);
4354 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4356 /* cleanup running stuffs */
4357 _mmplayer_cancel_eos_timer(player);
4359 /* cleanup gst stuffs */
4360 if (player->pipeline) {
4361 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4362 GstTagList *tag_list = player->pipeline->tag_list;
4364 /* first we need to disconnect all signal hander */
4365 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4368 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4369 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4370 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4371 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4372 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4373 gst_object_unref(bus);
4375 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4376 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4377 if (ret != MM_ERROR_NONE) {
4378 LOGE("fail to change state to NULL");
4379 return MM_ERROR_PLAYER_INTERNAL;
4382 LOGW("succeeded in changing state to NULL");
4384 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4387 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4388 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4390 MMPLAYER_FREEIF(audiobin);
4391 MMPLAYER_FREEIF(videobin);
4392 MMPLAYER_FREEIF(textbin);
4393 MMPLAYER_FREEIF(mainbin);
4397 gst_tag_list_unref(tag_list);
4399 MMPLAYER_FREEIF(player->pipeline);
4401 MMPLAYER_FREEIF(player->album_art);
4403 if (player->type_caps) {
4404 gst_caps_unref(player->type_caps);
4405 player->type_caps = NULL;
4408 if (player->v_stream_caps) {
4409 gst_caps_unref(player->v_stream_caps);
4410 player->v_stream_caps = NULL;
4413 if (player->a_stream_caps) {
4414 gst_caps_unref(player->a_stream_caps);
4415 player->a_stream_caps = NULL;
4418 if (player->s_stream_caps) {
4419 gst_caps_unref(player->s_stream_caps);
4420 player->s_stream_caps = NULL;
4422 _mmplayer_track_destroy(player);
4424 if (player->sink_elements)
4425 g_list_free(player->sink_elements);
4426 player->sink_elements = NULL;
4428 if (player->bufmgr) {
4429 tbm_bufmgr_deinit(player->bufmgr);
4430 player->bufmgr = NULL;
4433 LOGW("finished destroy pipeline");
4441 __mmplayer_gst_realize(mmplayer_t *player)
4444 int ret = MM_ERROR_NONE;
4448 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4450 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4452 ret = __mmplayer_gst_create_pipeline(player);
4454 LOGE("failed to create pipeline");
4458 /* set pipeline state to READY */
4459 /* NOTE : state change to READY must be performed sync. */
4460 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4461 ret = _mmplayer_gst_set_state(player,
4462 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4464 if (ret != MM_ERROR_NONE) {
4465 /* return error if failed to set state */
4466 LOGE("failed to set READY state");
4470 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4472 /* create dot before error-return. for debugging */
4473 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4481 __mmplayer_gst_unrealize(mmplayer_t *player)
4483 int ret = MM_ERROR_NONE;
4487 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4489 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4490 MMPLAYER_PRINT_STATE(player);
4492 /* release miscellaneous information */
4493 __mmplayer_release_misc(player);
4495 /* destroy pipeline */
4496 ret = __mmplayer_gst_destroy_pipeline(player);
4497 if (ret != MM_ERROR_NONE) {
4498 LOGE("failed to destroy pipeline");
4502 /* release miscellaneous information.
4503 these info needs to be released after pipeline is destroyed. */
4504 __mmplayer_release_misc_post(player);
4506 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4514 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4519 LOGW("set_message_callback is called with invalid player handle");
4520 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4523 player->msg_cb = callback;
4524 player->msg_cb_param = user_param;
4526 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4530 return MM_ERROR_NONE;
4534 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4536 int ret = MM_ERROR_NONE;
4541 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4542 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4543 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4545 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4547 if (strstr(uri, "es_buff://")) {
4548 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4549 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4550 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4551 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4553 tmp = g_ascii_strdown(uri, strlen(uri));
4554 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4555 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4557 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4559 } else if (strstr(uri, "mms://")) {
4560 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4561 } else if ((path = strstr(uri, "mem://"))) {
4562 ret = __mmplayer_set_mem_uri(data, path, param);
4564 ret = __mmplayer_set_file_uri(data, uri);
4567 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4568 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4569 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4570 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4572 /* dump parse result */
4573 SECURE_LOGW("incoming uri : %s", uri);
4574 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4575 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4583 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4586 mmplayer_t *player = NULL;
4587 MMMessageParamType msg = {0, };
4589 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4594 LOGE("user_data is null");
4598 player = (mmplayer_t *)user_data;
4600 if (!player->pipeline || !player->attrs) {
4601 LOGW("not initialized");
4605 LOGD("cmd lock player, cmd state : %d", player->cmd);
4606 MMPLAYER_CMD_LOCK(player);
4607 LOGD("cmd locked player");
4609 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4610 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4611 LOGW("player already destroyed");
4612 MMPLAYER_CMD_UNLOCK(player);
4616 player->interrupted_by_resource = TRUE;
4618 /* get last play position */
4619 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4620 msg.union_type = MM_MSG_UNION_TIME;
4621 msg.time.elapsed = pos;
4622 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4624 LOGW("failed to get play position.");
4627 LOGD("video resource conflict so, resource will be freed by unrealizing");
4628 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4629 LOGE("failed to unrealize");
4631 MMPLAYER_CMD_UNLOCK(player);
4633 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4634 player->hw_resource[res_idx] = NULL;
4638 return TRUE; /* release all the resources */
4642 __mmplayer_initialize_video_roi(mmplayer_t *player)
4644 player->video_roi.scale_x = 0.0;
4645 player->video_roi.scale_y = 0.0;
4646 player->video_roi.scale_width = 1.0;
4647 player->video_roi.scale_height = 1.0;
4651 _mmplayer_create_player(MMHandleType handle)
4653 int ret = MM_ERROR_PLAYER_INTERNAL;
4654 bool enabled = false;
4656 mmplayer_t *player = MM_PLAYER_CAST(handle);
4660 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4662 /* initialize player state */
4663 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4664 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4665 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4666 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4668 /* check current state */
4669 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4671 /* construct attributes */
4672 player->attrs = _mmplayer_construct_attribute(handle);
4674 if (!player->attrs) {
4675 LOGE("Failed to construct attributes");
4679 /* initialize gstreamer with configured parameter */
4680 if (!__mmplayer_init_gstreamer(player)) {
4681 LOGE("Initializing gstreamer failed");
4682 _mmplayer_deconstruct_attribute(handle);
4686 /* create lock. note that g_tread_init() has already called in gst_init() */
4687 g_mutex_init(&player->fsink_lock);
4689 /* create update tag lock */
4690 g_mutex_init(&player->update_tag_lock);
4692 /* create gapless play mutex */
4693 g_mutex_init(&player->gapless_play_thread_mutex);
4695 /* create gapless play cond */
4696 g_cond_init(&player->gapless_play_thread_cond);
4698 /* create gapless play thread */
4699 player->gapless_play_thread =
4700 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4701 if (!player->gapless_play_thread) {
4702 LOGE("failed to create gapless play thread");
4703 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4704 g_mutex_clear(&player->gapless_play_thread_mutex);
4705 g_cond_clear(&player->gapless_play_thread_cond);
4709 player->bus_msg_q = g_queue_new();
4710 if (!player->bus_msg_q) {
4711 LOGE("failed to create queue for bus_msg");
4712 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4716 ret = _mmplayer_initialize_video_capture(player);
4717 if (ret != MM_ERROR_NONE) {
4718 LOGE("failed to initialize video capture");
4722 /* initialize resource manager */
4723 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4724 __resource_release_cb, player, &player->resource_manager)
4725 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4726 LOGE("failed to create resource manager");
4727 ret = MM_ERROR_PLAYER_INTERNAL;
4731 /* create video bo lock and cond */
4732 g_mutex_init(&player->video_bo_mutex);
4733 g_cond_init(&player->video_bo_cond);
4735 /* create subtitle info lock and cond */
4736 g_mutex_init(&player->subtitle_info_mutex);
4737 g_cond_init(&player->subtitle_info_cond);
4739 player->streaming_type = STREAMING_SERVICE_NONE;
4741 /* give default value of audio effect setting */
4742 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4743 player->sound.rg_enable = false;
4744 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4746 player->play_subtitle = FALSE;
4747 player->has_closed_caption = FALSE;
4748 player->pending_resume = FALSE;
4749 if (player->ini.dump_element_keyword[0][0] == '\0')
4750 player->ini.set_dump_element_flag = FALSE;
4752 player->ini.set_dump_element_flag = TRUE;
4754 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4755 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4756 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4758 /* Set video360 settings to their defaults for just-created player.
4761 player->is_360_feature_enabled = FALSE;
4762 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4763 LOGI("spherical feature info: %d", enabled);
4765 player->is_360_feature_enabled = TRUE;
4767 LOGE("failed to get spherical feature info");
4770 player->is_content_spherical = FALSE;
4771 player->is_video360_enabled = TRUE;
4772 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4773 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4774 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4775 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4776 player->video360_zoom = 1.0f;
4777 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4778 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4780 __mmplayer_initialize_video_roi(player);
4782 /* set player state to null */
4783 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4784 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4788 return MM_ERROR_NONE;
4792 g_mutex_clear(&player->fsink_lock);
4793 /* free update tag lock */
4794 g_mutex_clear(&player->update_tag_lock);
4795 g_queue_free(player->bus_msg_q);
4796 player->bus_msg_q = NULL;
4797 /* free gapless play thread */
4798 if (player->gapless_play_thread) {
4799 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4800 player->gapless_play_thread_exit = TRUE;
4801 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4802 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4804 g_thread_join(player->gapless_play_thread);
4805 player->gapless_play_thread = NULL;
4807 g_mutex_clear(&player->gapless_play_thread_mutex);
4808 g_cond_clear(&player->gapless_play_thread_cond);
4811 /* release attributes */
4812 _mmplayer_deconstruct_attribute(handle);
4820 __mmplayer_init_gstreamer(mmplayer_t *player)
4822 static gboolean initialized = FALSE;
4823 static const int max_argc = 50;
4825 gchar **argv = NULL;
4826 gchar **argv2 = NULL;
4832 LOGD("gstreamer already initialized.");
4837 argc = malloc(sizeof(int));
4838 argv = malloc(sizeof(gchar *) * max_argc);
4839 argv2 = malloc(sizeof(gchar *) * max_argc);
4841 if (!argc || !argv || !argv2)
4844 memset(argv, 0, sizeof(gchar *) * max_argc);
4845 memset(argv2, 0, sizeof(gchar *) * max_argc);
4849 argv[0] = g_strdup("mmplayer");
4852 for (i = 0; i < 5; i++) {
4853 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4854 if (strlen(player->ini.gst_param[i]) > 0) {
4855 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4860 /* we would not do fork for scanning plugins */
4861 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4864 /* check disable registry scan */
4865 if (player->ini.skip_rescan) {
4866 argv[*argc] = g_strdup("--gst-disable-registry-update");
4870 /* check disable segtrap */
4871 if (player->ini.disable_segtrap) {
4872 argv[*argc] = g_strdup("--gst-disable-segtrap");
4876 LOGD("initializing gstreamer with following parameter");
4877 LOGD("argc : %d", *argc);
4880 for (i = 0; i < arg_count; i++) {
4882 LOGD("argv[%d] : %s", i, argv2[i]);
4885 /* initializing gstreamer */
4886 if (!gst_init_check(argc, &argv, &err)) {
4887 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4894 for (i = 0; i < arg_count; i++) {
4896 LOGD("release - argv[%d] : %s", i, argv2[i]);
4898 MMPLAYER_FREEIF(argv2[i]);
4901 MMPLAYER_FREEIF(argv);
4902 MMPLAYER_FREEIF(argv2);
4903 MMPLAYER_FREEIF(argc);
4913 for (i = 0; i < arg_count; i++) {
4914 LOGD("free[%d] : %s", i, argv2[i]);
4915 MMPLAYER_FREEIF(argv2[i]);
4918 MMPLAYER_FREEIF(argv);
4919 MMPLAYER_FREEIF(argv2);
4920 MMPLAYER_FREEIF(argc);
4926 __mmplayer_check_async_state_transition(mmplayer_t *player)
4928 GstState element_state = GST_STATE_VOID_PENDING;
4929 GstState element_pending_state = GST_STATE_VOID_PENDING;
4930 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4931 GstElement *element = NULL;
4932 gboolean async = FALSE;
4934 /* check player handle */
4935 MMPLAYER_RETURN_IF_FAIL(player &&
4937 player->pipeline->mainbin &&
4938 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4941 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4943 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4944 LOGD("don't need to check the pipeline state");
4948 MMPLAYER_PRINT_STATE(player);
4950 /* wait for state transition */
4951 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4952 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4954 if (ret == GST_STATE_CHANGE_FAILURE) {
4955 LOGE(" [%s] state : %s pending : %s",
4956 GST_ELEMENT_NAME(element),
4957 gst_element_state_get_name(element_state),
4958 gst_element_state_get_name(element_pending_state));
4960 /* dump state of all element */
4961 _mmplayer_dump_pipeline_state(player);
4966 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4971 _mmplayer_destroy(MMHandleType handle)
4973 mmplayer_t *player = MM_PLAYER_CAST(handle);
4977 /* check player handle */
4978 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4980 /* destroy can called at anytime */
4981 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4983 /* check async state transition */
4984 __mmplayer_check_async_state_transition(player);
4986 /* release gapless play thread */
4987 if (player->gapless_play_thread) {
4988 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4989 player->gapless_play_thread_exit = TRUE;
4990 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4991 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4993 LOGD("waiting for gapless play thread exit");
4994 g_thread_join(player->gapless_play_thread);
4995 g_mutex_clear(&player->gapless_play_thread_mutex);
4996 g_cond_clear(&player->gapless_play_thread_cond);
4997 LOGD("gapless play thread released");
5000 _mmplayer_release_video_capture(player);
5002 /* release miscellaneous information */
5003 __mmplayer_release_misc(player);
5005 /* release pipeline */
5006 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5007 LOGE("failed to destroy pipeline");
5008 return MM_ERROR_PLAYER_INTERNAL;
5011 __mmplayer_destroy_hw_resource(player);
5013 g_queue_free(player->bus_msg_q);
5015 /* release subtitle info lock and cond */
5016 g_mutex_clear(&player->subtitle_info_mutex);
5017 g_cond_clear(&player->subtitle_info_cond);
5019 __mmplayer_release_dump_list(player->dump_list);
5021 /* release miscellaneous information.
5022 these info needs to be released after pipeline is destroyed. */
5023 __mmplayer_release_misc_post(player);
5025 /* release attributes */
5026 _mmplayer_deconstruct_attribute(handle);
5028 if (player->uri_info.uri_list) {
5029 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5030 player->uri_info.uri_list = NULL;
5034 g_mutex_clear(&player->fsink_lock);
5037 g_mutex_clear(&player->update_tag_lock);
5039 /* release video bo lock and cond */
5040 g_mutex_clear(&player->video_bo_mutex);
5041 g_cond_clear(&player->video_bo_cond);
5045 return MM_ERROR_NONE;
5049 _mmplayer_realize(MMHandleType hplayer)
5051 mmplayer_t *player = (mmplayer_t *)hplayer;
5052 int ret = MM_ERROR_NONE;
5055 MMHandleType attrs = 0;
5059 /* check player handle */
5060 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5062 /* check current state */
5063 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5065 attrs = MMPLAYER_GET_ATTRS(player);
5067 LOGE("fail to get attributes.");
5068 return MM_ERROR_PLAYER_INTERNAL;
5070 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5071 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5073 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5074 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5076 if (ret != MM_ERROR_NONE) {
5077 LOGE("failed to parse profile");
5082 if (uri && (strstr(uri, "es_buff://"))) {
5083 if (strstr(uri, "es_buff://push_mode"))
5084 player->es_player_push_mode = TRUE;
5086 player->es_player_push_mode = FALSE;
5089 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5090 LOGW("mms protocol is not supported format.");
5091 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5094 if (MMPLAYER_IS_STREAMING(player))
5095 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5097 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5099 player->smooth_streaming = FALSE;
5100 player->videodec_linked = 0;
5101 player->audiodec_linked = 0;
5102 player->textsink_linked = 0;
5103 player->is_external_subtitle_present = FALSE;
5104 player->is_external_subtitle_added_now = FALSE;
5105 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5106 player->video360_metadata.is_spherical = -1;
5107 player->is_openal_plugin_used = FALSE;
5108 player->subtitle_language_list = NULL;
5109 player->is_subtitle_force_drop = FALSE;
5111 _mmplayer_track_initialize(player);
5112 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5114 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5115 gint prebuffer_ms = 0, rebuffer_ms = 0;
5117 player->streamer = _mm_player_streaming_create();
5118 _mm_player_streaming_initialize(player->streamer, TRUE);
5120 mm_attrs_multiple_get(player->attrs, NULL,
5121 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5122 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5124 if (prebuffer_ms > 0) {
5125 prebuffer_ms = MAX(prebuffer_ms, 1000);
5126 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5129 if (rebuffer_ms > 0) {
5130 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5131 rebuffer_ms = MAX(rebuffer_ms, 1000);
5132 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5135 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5136 player->streamer->buffering_req.rebuffer_time);
5139 /* realize pipeline */
5140 ret = __mmplayer_gst_realize(player);
5141 if (ret != MM_ERROR_NONE)
5142 LOGE("fail to realize the player.");
5144 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5152 _mmplayer_unrealize(MMHandleType hplayer)
5154 mmplayer_t *player = (mmplayer_t *)hplayer;
5155 int ret = MM_ERROR_NONE;
5156 int rm_ret = MM_ERROR_NONE;
5157 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5161 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5163 MMPLAYER_CMD_UNLOCK(player);
5164 _mmplayer_bus_watcher_remove(player);
5165 /* destroy the gst bus msg thread which is created during realize.
5166 this funct have to be called before getting cmd lock. */
5167 _mmplayer_bus_msg_thread_destroy(player);
5168 MMPLAYER_CMD_LOCK(player);
5170 /* check current state */
5171 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5173 /* check async state transition */
5174 __mmplayer_check_async_state_transition(player);
5176 /* unrealize pipeline */
5177 ret = __mmplayer_gst_unrealize(player);
5179 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5180 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5181 if (rm_ret != MM_ERROR_NONE)
5182 LOGE("failed to release [%d] resources", res_idx);
5185 player->interrupted_by_resource = FALSE;
5192 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5194 mmplayer_t *player = (mmplayer_t *)hplayer;
5196 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5198 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5202 _mmplayer_get_state(MMHandleType hplayer, int *state)
5204 mmplayer_t *player = (mmplayer_t *)hplayer;
5206 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5208 *state = MMPLAYER_CURRENT_STATE(player);
5210 return MM_ERROR_NONE;
5214 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5216 GstElement *vol_element = NULL;
5217 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5220 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5221 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5223 /* check pipeline handle */
5224 if (!player->pipeline || !player->pipeline->audiobin) {
5225 LOGD("'%s' will be applied when audiobin is created", prop_name);
5227 /* NOTE : stored value will be used in create_audiobin
5228 * returning MM_ERROR_NONE here makes application to able to
5229 * set audio volume or mute at anytime.
5231 return MM_ERROR_NONE;
5234 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5235 volume_elem_id = MMPLAYER_A_SINK;
5237 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5239 LOGE("failed to get vol element %d", volume_elem_id);
5240 return MM_ERROR_PLAYER_INTERNAL;
5243 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5245 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5246 LOGE("there is no '%s' property", prop_name);
5247 return MM_ERROR_PLAYER_INTERNAL;
5250 if (!strcmp(prop_name, "volume")) {
5251 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5252 } else if (!strcmp(prop_name, "mute")) {
5253 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5255 LOGE("invalid property %s", prop_name);
5256 return MM_ERROR_PLAYER_INTERNAL;
5259 return MM_ERROR_NONE;
5263 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5265 int ret = MM_ERROR_NONE;
5266 mmplayer_t *player = (mmplayer_t *)hplayer;
5269 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5271 LOGD("volume = %f", volume);
5273 /* invalid factor range or not */
5274 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5275 LOGE("Invalid volume value");
5276 return MM_ERROR_INVALID_ARGUMENT;
5279 player->sound.volume = volume;
5281 ret = __mmplayer_gst_set_volume_property(player, "volume");
5288 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5290 mmplayer_t *player = (mmplayer_t *)hplayer;
5294 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5295 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5297 *volume = player->sound.volume;
5299 LOGD("current vol = %f", *volume);
5302 return MM_ERROR_NONE;
5306 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5308 int ret = MM_ERROR_NONE;
5309 mmplayer_t *player = (mmplayer_t *)hplayer;
5312 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5314 LOGD("mute = %d", mute);
5316 player->sound.mute = mute;
5318 ret = __mmplayer_gst_set_volume_property(player, "mute");
5325 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5327 mmplayer_t *player = (mmplayer_t *)hplayer;
5331 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5332 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5334 *mute = player->sound.mute;
5336 LOGD("current mute = %d", *mute);
5340 return MM_ERROR_NONE;
5344 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5346 mmplayer_t *player = (mmplayer_t *)hplayer;
5350 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5352 player->audio_stream_changed_cb = callback;
5353 player->audio_stream_changed_cb_user_param = user_param;
5354 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5358 return MM_ERROR_NONE;
5362 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5364 mmplayer_t *player = (mmplayer_t *)hplayer;
5368 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5370 player->audio_decoded_cb = callback;
5371 player->audio_decoded_cb_user_param = user_param;
5372 player->audio_extract_opt = opt;
5373 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5377 return MM_ERROR_NONE;
5381 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5383 mmplayer_t *player = (mmplayer_t *)hplayer;
5387 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5389 if (callback && !player->bufmgr)
5390 player->bufmgr = tbm_bufmgr_init(-1);
5392 player->set_mode.video_export = (callback) ? true : false;
5393 player->video_decoded_cb = callback;
5394 player->video_decoded_cb_user_param = user_param;
5396 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5400 return MM_ERROR_NONE;
5404 _mmplayer_start(MMHandleType hplayer)
5406 mmplayer_t *player = (mmplayer_t *)hplayer;
5407 gint ret = MM_ERROR_NONE;
5411 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5413 /* check current state */
5414 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5416 /* start pipeline */
5417 ret = _mmplayer_gst_start(player);
5418 if (ret != MM_ERROR_NONE)
5419 LOGE("failed to start player.");
5421 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5422 LOGD("force playing start even during buffering");
5423 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5431 /* NOTE: post "not supported codec message" to application
5432 * when one codec is not found during AUTOPLUGGING in MSL.
5433 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5434 * And, if any codec is not found, don't send message here.
5435 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5438 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5440 MMMessageParamType msg_param;
5441 memset(&msg_param, 0, sizeof(MMMessageParamType));
5442 gboolean post_msg_direct = FALSE;
5446 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5448 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5449 player->not_supported_codec, player->can_support_codec);
5451 if (player->not_found_demuxer) {
5452 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5453 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5455 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5456 MMPLAYER_FREEIF(msg_param.data);
5458 return MM_ERROR_NONE;
5461 if (player->not_supported_codec) {
5462 if (player->can_support_codec) {
5463 // There is one codec to play
5464 post_msg_direct = TRUE;
5466 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5467 post_msg_direct = TRUE;
5470 if (post_msg_direct) {
5471 MMMessageParamType msg_param;
5472 memset(&msg_param, 0, sizeof(MMMessageParamType));
5474 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5475 LOGW("not found AUDIO codec, posting error code to application.");
5477 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5478 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5479 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5480 LOGW("not found VIDEO codec, posting error code to application.");
5482 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5483 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5486 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5488 MMPLAYER_FREEIF(msg_param.data);
5490 return MM_ERROR_NONE;
5492 // no any supported codec case
5493 LOGW("not found any codec, posting error code to application.");
5495 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5496 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5497 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5499 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5500 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5503 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5505 MMPLAYER_FREEIF(msg_param.data);
5511 return MM_ERROR_NONE;
5514 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5516 GstState element_state = GST_STATE_VOID_PENDING;
5517 GstState element_pending_state = GST_STATE_VOID_PENDING;
5518 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5519 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5521 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5523 MMPLAYER_RECONFIGURE_LOCK(player);
5524 if (!player->gapless.reconfigure) {
5525 MMPLAYER_RECONFIGURE_UNLOCK(player);
5529 LOGI("reconfigure is under process");
5530 MMPLAYER_RECONFIGURE_WAIT(player);
5531 MMPLAYER_RECONFIGURE_UNLOCK(player);
5532 LOGI("reconfigure is completed.");
5534 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5535 &element_state, &element_pending_state, timeout * GST_SECOND);
5536 if (result == GST_STATE_CHANGE_FAILURE)
5537 LOGW("failed to get pipeline state in %d sec", timeout);
5542 /* NOTE : it should be able to call 'stop' anytime*/
5544 _mmplayer_stop(MMHandleType hplayer)
5546 mmplayer_t *player = (mmplayer_t *)hplayer;
5547 int ret = MM_ERROR_NONE;
5551 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5553 /* check current state */
5554 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5556 /* need to wait till the rebuilding pipeline is completed */
5557 __mmplayer_check_pipeline_reconfigure_state(player);
5558 MMPLAYER_RECONFIGURE_LOCK(player);
5559 __mmplayer_reset_gapless_state(player);
5560 MMPLAYER_RECONFIGURE_UNLOCK(player);
5562 /* NOTE : application should not wait for EOS after calling STOP */
5563 _mmplayer_cancel_eos_timer(player);
5566 player->seek_state = MMPLAYER_SEEK_NONE;
5569 ret = _mmplayer_gst_stop(player);
5571 if (ret != MM_ERROR_NONE)
5572 LOGE("failed to stop player.");
5580 _mmplayer_pause(MMHandleType hplayer)
5582 mmplayer_t *player = (mmplayer_t *)hplayer;
5583 gint64 pos_nsec = 0;
5584 gboolean async = FALSE;
5585 gint ret = MM_ERROR_NONE;
5589 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5591 /* check current state */
5592 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5594 /* check pipeline reconfigure state */
5595 __mmplayer_check_pipeline_reconfigure_state(player);
5597 switch (MMPLAYER_CURRENT_STATE(player)) {
5598 case MM_PLAYER_STATE_READY:
5600 /* check prepare async or not.
5601 * In the case of streaming playback, it's recommended to avoid blocking wait.
5603 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5604 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5606 /* Changing back sync of rtspsrc to async */
5607 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5608 LOGD("async prepare working mode for rtsp");
5614 case MM_PLAYER_STATE_PLAYING:
5616 /* NOTE : store current point to overcome some bad operation
5617 *(returning zero when getting current position in paused state) of some
5620 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5621 LOGW("getting current position failed in paused");
5623 player->last_position = pos_nsec;
5625 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5626 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5627 This causes problem is position calculation during normal pause resume scenarios also.
5628 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5629 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5630 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5631 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5637 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5638 LOGD("doing async pause in case of ms buff src");
5642 /* pause pipeline */
5643 ret = _mmplayer_gst_pause(player, async);
5644 if (ret != MM_ERROR_NONE) {
5645 LOGE("failed to pause player. ret : 0x%x", ret);
5646 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5650 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5651 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5652 LOGE("failed to update display_rotation");
5656 return MM_ERROR_NONE;
5659 /* in case of streaming, pause could take long time.*/
5661 _mmplayer_abort_pause(MMHandleType hplayer)
5663 mmplayer_t *player = (mmplayer_t *)hplayer;
5664 int ret = MM_ERROR_NONE;
5668 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5670 player->pipeline->mainbin,
5671 MM_ERROR_PLAYER_NOT_INITIALIZED);
5673 LOGD("set the pipeline state to READY");
5675 /* set state to READY */
5676 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5677 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5678 if (ret != MM_ERROR_NONE) {
5679 LOGE("fail to change state to READY");
5680 return MM_ERROR_PLAYER_INTERNAL;
5683 LOGD("succeeded in changing state to READY");
5688 _mmplayer_resume(MMHandleType hplayer)
5690 mmplayer_t *player = (mmplayer_t *)hplayer;
5691 int ret = MM_ERROR_NONE;
5692 gboolean async = FALSE;
5696 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5698 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5699 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5700 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5704 /* Changing back sync mode rtspsrc to async */
5705 LOGD("async resume for rtsp case");
5709 /* check current state */
5710 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5712 ret = _mmplayer_gst_resume(player, async);
5713 if (ret != MM_ERROR_NONE)
5714 LOGE("failed to resume player.");
5716 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5717 LOGD("force resume even during buffering");
5718 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5727 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5729 mmplayer_t *player = (mmplayer_t *)hplayer;
5730 gint64 pos_nsec = 0;
5731 int ret = MM_ERROR_NONE;
5733 signed long long start = 0, stop = 0;
5734 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5737 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5738 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5740 /* The sound of video is not supported under 0.0 and over 2.0. */
5741 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5742 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5745 _mmplayer_set_mute(hplayer, mute);
5747 if (player->playback_rate == rate)
5748 return MM_ERROR_NONE;
5750 /* If the position is reached at start potion during fast backward, EOS is posted.
5751 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5753 player->playback_rate = rate;
5755 current_state = MMPLAYER_CURRENT_STATE(player);
5757 if (current_state != MM_PLAYER_STATE_PAUSED)
5758 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5760 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5762 if ((current_state == MM_PLAYER_STATE_PAUSED)
5763 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5764 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5765 pos_nsec = player->last_position;
5770 stop = GST_CLOCK_TIME_NONE;
5772 start = GST_CLOCK_TIME_NONE;
5776 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5777 player->playback_rate,
5779 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5780 GST_SEEK_TYPE_SET, start,
5781 GST_SEEK_TYPE_SET, stop)) {
5782 LOGE("failed to set speed playback");
5783 return MM_ERROR_PLAYER_SEEK;
5786 LOGD("succeeded to set speed playback as %0.1f", rate);
5790 return MM_ERROR_NONE;;
5794 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5796 mmplayer_t *player = (mmplayer_t *)hplayer;
5797 int ret = MM_ERROR_NONE;
5801 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5803 /* check pipeline reconfigure state */
5804 __mmplayer_check_pipeline_reconfigure_state(player);
5806 ret = _mmplayer_gst_set_position(player, position, FALSE);
5814 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5816 mmplayer_t *player = (mmplayer_t *)hplayer;
5817 int ret = MM_ERROR_NONE;
5819 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5820 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5822 if (g_strrstr(player->type, "video/mpegts"))
5823 __mmplayer_update_duration_value(player);
5825 *duration = player->duration;
5830 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5832 mmplayer_t *player = (mmplayer_t *)hplayer;
5833 int ret = MM_ERROR_NONE;
5835 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5837 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5843 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5845 mmplayer_t *player = (mmplayer_t *)hplayer;
5846 int ret = MM_ERROR_NONE;
5850 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5852 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5860 __mmplayer_is_midi_type(gchar *str_caps)
5862 if ((g_strrstr(str_caps, "audio/midi")) ||
5863 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5864 (g_strrstr(str_caps, "application/x-smaf")) ||
5865 (g_strrstr(str_caps, "audio/x-imelody")) ||
5866 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5867 (g_strrstr(str_caps, "audio/xmf")) ||
5868 (g_strrstr(str_caps, "audio/mxmf"))) {
5877 __mmplayer_is_only_mp3_type(gchar *str_caps)
5879 if (g_strrstr(str_caps, "application/x-id3") ||
5880 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5886 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5888 GstStructure *caps_structure = NULL;
5889 gint samplerate = 0;
5893 MMPLAYER_RETURN_IF_FAIL(player && caps);
5895 caps_structure = gst_caps_get_structure(caps, 0);
5897 /* set stream information */
5898 gst_structure_get_int(caps_structure, "rate", &samplerate);
5899 gst_structure_get_int(caps_structure, "channels", &channels);
5901 mm_player_set_attribute((MMHandleType)player, NULL,
5902 "content_audio_samplerate", samplerate,
5903 "content_audio_channels", channels, NULL);
5905 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5909 __mmplayer_update_content_type_info(mmplayer_t *player)
5912 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5914 if (__mmplayer_is_midi_type(player->type)) {
5915 player->bypass_audio_effect = TRUE;
5919 if (!player->streamer) {
5920 LOGD("no need to check streaming type");
5924 if (g_strrstr(player->type, "application/x-hls")) {
5925 /* If it can't know exact type when it parses uri because of redirection case,
5926 * it will be fixed by typefinder or when doing autoplugging.
5928 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5929 player->streamer->is_adaptive_streaming = TRUE;
5930 } else if (g_strrstr(player->type, "application/dash+xml")) {
5931 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5932 player->streamer->is_adaptive_streaming = TRUE;
5935 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5936 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5937 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5939 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5940 if (player->streamer->is_adaptive_streaming)
5941 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5943 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5947 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5952 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5953 GstCaps *caps, gpointer data)
5955 mmplayer_t *player = (mmplayer_t *)data;
5959 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5961 /* store type string */
5962 if (player->type_caps) {
5963 gst_caps_unref(player->type_caps);
5964 player->type_caps = NULL;
5967 player->type_caps = gst_caps_copy(caps);
5968 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5970 MMPLAYER_FREEIF(player->type);
5971 player->type = gst_caps_to_string(caps);
5973 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5974 player, player->type, probability, gst_caps_get_size(caps));
5976 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5977 (g_strrstr(player->type, "audio/x-raw-int"))) {
5978 LOGE("not support media format");
5980 if (player->msg_posted == FALSE) {
5981 MMMessageParamType msg_param;
5982 memset(&msg_param, 0, sizeof(MMMessageParamType));
5984 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5985 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5987 /* don't post more if one was sent already */
5988 player->msg_posted = TRUE;
5993 __mmplayer_update_content_type_info(player);
5995 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5998 pad = gst_element_get_static_pad(tf, "src");
6000 LOGE("fail to get typefind src pad.");
6004 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6005 gboolean async = FALSE;
6006 LOGE("failed to autoplug %s", player->type);
6008 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6010 if (async && player->msg_posted == FALSE)
6011 __mmplayer_handle_missed_plugin(player);
6013 gst_object_unref(GST_OBJECT(pad));
6020 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6022 GstElement *decodebin = NULL;
6026 /* create decodebin */
6027 decodebin = gst_element_factory_make("decodebin", NULL);
6030 LOGE("fail to create decodebin");
6034 /* raw pad handling signal */
6035 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6036 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6038 /* no-more-pad pad handling signal */
6039 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6040 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6042 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6043 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6045 /* This signal is emitted when a pad for which there is no further possible
6046 decoding is added to the decodebin.*/
6047 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6048 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6050 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6051 before looking for any elements that can handle that stream.*/
6052 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6053 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6055 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6056 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6057 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6059 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6060 before looking for any elements that can handle that stream.*/
6061 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6062 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6064 /* This signal is emitted once decodebin has finished decoding all the data.*/
6065 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6066 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6068 /* This signal is emitted when a element is added to the bin.*/
6069 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6070 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6077 __mmplayer_gst_make_queue2(mmplayer_t *player)
6079 GstElement *queue2 = NULL;
6080 gint64 dur_bytes = 0L;
6081 mmplayer_gst_element_t *mainbin = NULL;
6082 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6085 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6087 mainbin = player->pipeline->mainbin;
6089 queue2 = gst_element_factory_make("queue2", "queue2");
6091 LOGE("failed to create buffering queue element");
6095 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6096 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6098 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6100 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6101 * skip the pull mode(file or ring buffering) setting. */
6102 if (dur_bytes > 0) {
6103 if (!g_strrstr(player->type, "video/mpegts")) {
6104 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6105 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6111 _mm_player_streaming_set_queue2(player->streamer,
6115 (guint64)dur_bytes); /* no meaning at the moment */
6121 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6123 mmplayer_gst_element_t *mainbin = NULL;
6124 GstElement *decodebin = NULL;
6125 GstElement *queue2 = NULL;
6126 GstPad *sinkpad = NULL;
6127 GstPad *qsrcpad = NULL;
6130 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6132 mainbin = player->pipeline->mainbin;
6134 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6136 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6137 LOGW("need to check: muxed buffer is not null");
6140 queue2 = __mmplayer_gst_make_queue2(player);
6142 LOGE("failed to make queue2");
6146 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6147 LOGE("failed to add buffering queue");
6151 sinkpad = gst_element_get_static_pad(queue2, "sink");
6152 qsrcpad = gst_element_get_static_pad(queue2, "src");
6154 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6155 LOGE("failed to link [%s:%s]-[%s:%s]",
6156 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6160 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6161 LOGE("failed to sync queue2 state with parent");
6165 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6166 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6170 gst_object_unref(GST_OBJECT(sinkpad));
6174 /* create decodebin */
6175 decodebin = _mmplayer_gst_make_decodebin(player);
6177 LOGE("failed to make decodebin");
6181 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6182 LOGE("failed to add decodebin");
6186 /* to force caps on the decodebin element and avoid reparsing stuff by
6187 * typefind. It also avoids a deadlock in the way typefind activates pads in
6188 * the state change */
6189 g_object_set(decodebin, "sink-caps", caps, NULL);
6191 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6193 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6194 LOGE("failed to link [%s:%s]-[%s:%s]",
6195 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6199 gst_object_unref(GST_OBJECT(sinkpad));
6201 gst_object_unref(GST_OBJECT(qsrcpad));
6204 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6205 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6207 /* set decodebin property about buffer in streaming playback. *
6208 * in case of HLS/DASH, it does not need to have big buffer *
6209 * because it is kind of adaptive streaming. */
6210 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6211 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6212 gint high_percent = 0;
6214 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6215 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6217 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6219 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6221 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6222 "high-percent", high_percent,
6223 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6224 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6225 "max-size-buffers", 0, NULL); // disable or automatic
6228 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6229 LOGE("failed to sync decodebin state with parent");
6240 gst_object_unref(GST_OBJECT(sinkpad));
6243 gst_object_unref(GST_OBJECT(qsrcpad));
6246 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6247 * You need to explicitly set elements to the NULL state before
6248 * dropping the final reference, to allow them to clean up.
6250 gst_element_set_state(queue2, GST_STATE_NULL);
6252 /* And, it still has a parent "player".
6253 * You need to let the parent manage the object instead of unreffing the object directly.
6255 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6256 gst_object_unref(queue2);
6261 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6262 * You need to explicitly set elements to the NULL state before
6263 * dropping the final reference, to allow them to clean up.
6265 gst_element_set_state(decodebin, GST_STATE_NULL);
6267 /* And, it still has a parent "player".
6268 * You need to let the parent manage the object instead of unreffing the object directly.
6271 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6272 gst_object_unref(decodebin);
6280 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6284 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6285 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6287 LOGD("class : %s, mime : %s", factory_class, mime);
6289 /* add missing plugin */
6290 /* NOTE : msl should check missing plugin for image mime type.
6291 * Some motion jpeg clips can have playable audio track.
6292 * So, msl have to play audio after displaying popup written video format not supported.
6294 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6295 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6296 LOGD("not found demuxer");
6297 player->not_found_demuxer = TRUE;
6298 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6304 if (!g_strrstr(factory_class, "Demuxer")) {
6305 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6306 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6307 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6309 /* check that clip have multi tracks or not */
6310 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6311 LOGD("video plugin is already linked");
6313 LOGW("add VIDEO to missing plugin");
6314 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6315 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6317 } else if (g_str_has_prefix(mime, "audio")) {
6318 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6319 LOGD("audio plugin is already linked");
6321 LOGW("add AUDIO to missing plugin");
6322 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6323 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6331 return MM_ERROR_NONE;
6335 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6337 mmplayer_t *player = (mmplayer_t *)data;
6341 MMPLAYER_RETURN_IF_FAIL(player);
6343 /* remove fakesink. */
6344 if (!_mmplayer_gst_remove_fakesink(player,
6345 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6346 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6347 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6348 * source element are not same. To overcome this situation, this function will called
6349 * several places and several times. Therefore, this is not an error case.
6354 LOGD("[handle: %p] pipeline has completely constructed", player);
6356 if ((player->msg_posted == FALSE) &&
6357 (player->cmd >= MMPLAYER_COMMAND_START))
6358 __mmplayer_handle_missed_plugin(player);
6360 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6364 __mmplayer_check_profile(void)
6367 static int profile_tv = -1;
6369 if (__builtin_expect(profile_tv != -1, 1))
6372 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6373 switch (*profileName) {
6388 __mmplayer_get_next_uri(mmplayer_t *player)
6390 mmplayer_parse_profile_t profile;
6392 guint num_of_list = 0;
6395 num_of_list = g_list_length(player->uri_info.uri_list);
6396 uri_idx = player->uri_info.uri_idx;
6398 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6399 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6400 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6402 LOGW("next uri does not exist");
6406 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6407 LOGE("failed to parse profile");
6411 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6412 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6413 LOGW("uri type is not supported(%d)", profile.uri_type);
6417 LOGD("success to find next uri %d", uri_idx);
6421 if (!uri || uri_idx == num_of_list) {
6422 LOGE("failed to find next uri");
6426 player->uri_info.uri_idx = uri_idx;
6427 if (mm_player_set_attribute((MMHandleType)player, NULL,
6428 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6429 LOGE("failed to set attribute");
6433 SECURE_LOGD("next playback uri: %s", uri);
6438 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6440 #define REPEAT_COUNT_INFINITE -1
6441 #define REPEAT_COUNT_MIN 2
6442 #define ORIGINAL_URI_ONLY 1
6444 MMHandleType attrs = 0;
6448 guint num_of_uri = 0;
6449 int profile_tv = -1;
6453 LOGD("checking for gapless play option");
6455 if (player->build_audio_offload) {
6456 LOGE("offload path is not supportable.");
6460 if (player->pipeline->textbin) {
6461 LOGE("subtitle path is enabled. gapless play is not supported.");
6465 attrs = MMPLAYER_GET_ATTRS(player);
6467 LOGE("fail to get attributes.");
6471 mm_attrs_multiple_get(player->attrs, NULL,
6472 "content_video_found", &video,
6473 "profile_play_count", &count,
6474 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6476 /* gapless playback is not supported in case of video at TV profile. */
6477 profile_tv = __mmplayer_check_profile();
6478 if (profile_tv && video) {
6479 LOGW("not support video gapless playback");
6483 /* check repeat count in case of audio */
6485 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6486 LOGW("gapless is disabled");
6490 num_of_uri = g_list_length(player->uri_info.uri_list);
6492 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6494 if (num_of_uri == ORIGINAL_URI_ONLY) {
6495 /* audio looping path */
6496 if (count >= REPEAT_COUNT_MIN) {
6497 /* decrease play count */
6498 /* we succeeded to rewind. update play count and then wait for next EOS */
6500 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6501 } else if (count != REPEAT_COUNT_INFINITE) {
6502 LOGD("there is no next uri and no repeat");
6505 LOGD("looping cnt %d", count);
6507 /* gapless playback path */
6508 if (!__mmplayer_get_next_uri(player)) {
6509 LOGE("failed to get next uri");
6516 LOGE("unable to play gapless path. EOS will be posted soon");
6521 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6523 GstPad *sinkpad = g_value_get_object (item);
6524 GstElement *element = GST_ELEMENT(user_data);
6525 if (!sinkpad || !element) {
6526 LOGE("invalid parameter");
6530 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6531 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6535 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6537 mmplayer_gst_element_t *sinkbin = NULL;
6538 main_element_id_e concatId = MMPLAYER_M_NUM;
6539 main_element_id_e sinkId = MMPLAYER_M_NUM;
6540 gboolean send_notice = FALSE;
6541 GstElement *element;
6545 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6547 LOGD("type %d", type);
6550 case MM_PLAYER_TRACK_TYPE_AUDIO:
6551 concatId = MMPLAYER_M_A_CONCAT;
6552 sinkId = MMPLAYER_A_BIN;
6553 sinkbin = player->pipeline->audiobin;
6555 case MM_PLAYER_TRACK_TYPE_VIDEO:
6556 concatId = MMPLAYER_M_V_CONCAT;
6557 sinkId = MMPLAYER_V_BIN;
6558 sinkbin = player->pipeline->videobin;
6561 case MM_PLAYER_TRACK_TYPE_TEXT:
6562 concatId = MMPLAYER_M_T_CONCAT;
6563 sinkId = MMPLAYER_T_BIN;
6564 sinkbin = player->pipeline->textbin;
6567 LOGE("requested type is not supportable");
6572 element = player->pipeline->mainbin[concatId].gst;
6576 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6577 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6578 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6579 if (srcpad && sinkpad) {
6580 /* after getting drained signal there is no data flows, so no need to do pad_block */
6581 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6582 gst_pad_unlink(srcpad, sinkpad);
6584 /* send custom event to sink pad to handle it at video sink */
6586 LOGD("send custom event to sinkpad");
6587 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6588 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6589 gst_pad_send_event(sinkpad, event);
6592 gst_object_unref(srcpad);
6593 gst_object_unref(sinkpad);
6596 LOGD("release concat request pad");
6597 /* release and unref requests pad from the selector */
6598 iter = gst_element_iterate_sink_pads(element);
6599 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6600 gst_iterator_resync(iter);
6601 gst_iterator_free(iter);
6607 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6609 mmplayer_track_t *selector = &player->track[type];
6610 mmplayer_gst_element_t *sinkbin = NULL;
6611 main_element_id_e selectorId = MMPLAYER_M_NUM;
6612 main_element_id_e sinkId = MMPLAYER_M_NUM;
6613 GstPad *srcpad = NULL;
6614 GstPad *sinkpad = NULL;
6615 gboolean send_notice = FALSE;
6618 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6620 LOGD("type %d", type);
6623 case MM_PLAYER_TRACK_TYPE_AUDIO:
6624 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6625 sinkId = MMPLAYER_A_BIN;
6626 sinkbin = player->pipeline->audiobin;
6628 case MM_PLAYER_TRACK_TYPE_VIDEO:
6629 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6630 sinkId = MMPLAYER_V_BIN;
6631 sinkbin = player->pipeline->videobin;
6634 case MM_PLAYER_TRACK_TYPE_TEXT:
6635 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6636 sinkId = MMPLAYER_T_BIN;
6637 sinkbin = player->pipeline->textbin;
6640 LOGE("requested type is not supportable");
6645 if (player->pipeline->mainbin[selectorId].gst) {
6648 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6650 if (selector->event_probe_id != 0)
6651 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6652 selector->event_probe_id = 0;
6654 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6655 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6657 if (srcpad && sinkpad) {
6658 /* after getting drained signal there is no data flows, so no need to do pad_block */
6659 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6660 gst_pad_unlink(srcpad, sinkpad);
6662 /* send custom event to sink pad to handle it at video sink */
6664 LOGD("send custom event to sinkpad");
6665 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6666 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6667 gst_pad_send_event(sinkpad, event);
6671 gst_object_unref(sinkpad);
6674 gst_object_unref(srcpad);
6677 LOGD("selector release");
6679 /* release and unref requests pad from the selector */
6680 for (n = 0; n < selector->streams->len; n++) {
6681 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6682 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6685 g_ptr_array_set_size(selector->streams, 0);
6687 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6688 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6690 player->pipeline->mainbin[selectorId].gst = NULL;
6698 __mmplayer_deactivate_old_path(mmplayer_t *player)
6701 MMPLAYER_RETURN_IF_FAIL(player);
6703 if (MMPLAYER_USE_DECODEBIN(player)) {
6704 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6705 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6706 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6707 LOGE("deactivate selector error");
6711 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6712 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6713 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6714 LOGE("deactivate concat error");
6719 _mmplayer_track_destroy(player);
6720 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6722 if (player->streamer) {
6723 _mm_player_streaming_initialize(player->streamer, FALSE);
6724 _mm_player_streaming_destroy(player->streamer);
6725 player->streamer = NULL;
6728 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6734 if (!player->msg_posted) {
6735 MMMessageParamType msg = {0,};
6738 msg.code = MM_ERROR_PLAYER_INTERNAL;
6739 LOGE("gapless_uri_play> deactivate error");
6741 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6742 player->msg_posted = TRUE;
6748 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6750 int result = MM_ERROR_NONE;
6751 mmplayer_t *player = (mmplayer_t *)hplayer;
6754 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6755 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6757 if (mm_player_set_attribute(hplayer, NULL,
6758 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6759 LOGE("failed to set attribute");
6760 result = MM_ERROR_PLAYER_INTERNAL;
6762 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6763 LOGE("failed to add the original uri in the uri list.");
6771 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6773 mmplayer_t *player = (mmplayer_t *)hplayer;
6774 guint num_of_list = 0;
6778 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6779 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6781 if (player->pipeline && player->pipeline->textbin) {
6782 LOGE("subtitle path is enabled.");
6783 return MM_ERROR_PLAYER_INVALID_STATE;
6786 num_of_list = g_list_length(player->uri_info.uri_list);
6788 if (is_first_path) {
6789 if (num_of_list == 0) {
6790 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6791 SECURE_LOGD("add original path : %s", uri);
6793 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6794 player->uri_info.uri_list = g_list_prepend(
6795 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6796 SECURE_LOGD("change original path : %s", uri);
6799 MMHandleType attrs = 0;
6800 attrs = MMPLAYER_GET_ATTRS(player);
6802 if (num_of_list == 0) {
6803 char *original_uri = NULL;
6806 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6808 if (!original_uri) {
6809 LOGE("there is no original uri.");
6810 return MM_ERROR_PLAYER_INVALID_STATE;
6813 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6814 player->uri_info.uri_idx = 0;
6816 SECURE_LOGD("add original path at first : %s", original_uri);
6820 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6821 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6825 return MM_ERROR_NONE;
6829 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6831 mmplayer_t *player = (mmplayer_t *)hplayer;
6832 char *next_uri = NULL;
6833 guint num_of_list = 0;
6836 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6838 num_of_list = g_list_length(player->uri_info.uri_list);
6840 if (num_of_list > 0) {
6841 gint uri_idx = player->uri_info.uri_idx;
6843 if (uri_idx < num_of_list - 1)
6848 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6849 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6851 *uri = g_strdup(next_uri);
6855 return MM_ERROR_NONE;
6859 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6860 GstCaps *caps, gpointer data)
6862 mmplayer_t *player = (mmplayer_t *)data;
6863 const gchar *klass = NULL;
6864 const gchar *mime = NULL;
6865 gchar *caps_str = NULL;
6867 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6868 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6869 caps_str = gst_caps_to_string(caps);
6871 LOGW("unknown type of caps : %s from %s",
6872 caps_str, GST_ELEMENT_NAME(elem));
6874 MMPLAYER_FREEIF(caps_str);
6876 /* There is no available codec. */
6877 __mmplayer_check_not_supported_codec(player, klass, mime);
6881 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6882 GstCaps *caps, gpointer data)
6884 mmplayer_t *player = (mmplayer_t *)data;
6885 const char *mime = NULL;
6886 gboolean ret = TRUE;
6888 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6889 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6891 if (g_str_has_prefix(mime, "audio")) {
6892 GstStructure *caps_structure = NULL;
6893 gint samplerate = 0;
6895 gchar *caps_str = NULL;
6897 caps_structure = gst_caps_get_structure(caps, 0);
6898 gst_structure_get_int(caps_structure, "rate", &samplerate);
6899 gst_structure_get_int(caps_structure, "channels", &channels);
6901 if ((channels > 0 && samplerate == 0)) {
6902 LOGD("exclude audio...");
6906 caps_str = gst_caps_to_string(caps);
6907 /* set it directly because not sent by TAG */
6908 if (g_strrstr(caps_str, "mobile-xmf"))
6909 mm_player_set_attribute((MMHandleType)player, NULL,
6910 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6912 MMPLAYER_FREEIF(caps_str);
6913 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6914 LOGD("already video linked");
6917 LOGD("found new stream");
6924 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6926 gboolean ret = FALSE;
6927 GDBusConnection *conn = NULL;
6929 GVariant *result = NULL;
6930 const gchar *dbus_device_type = NULL;
6931 const gchar *dbus_ret = NULL;
6934 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6936 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6941 result = g_dbus_connection_call_sync(conn,
6942 "org.pulseaudio.Server",
6943 "/org/pulseaudio/StreamManager",
6944 "org.pulseaudio.StreamManager",
6945 "GetCurrentMediaRoutingPath",
6946 g_variant_new("(s)", "out"),
6947 G_VARIANT_TYPE("(ss)"),
6948 G_DBUS_CALL_FLAGS_NONE,
6952 if (!result || err) {
6953 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6958 /* device type is listed in stream-map.json at mmfw-sysconf */
6959 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6961 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6962 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6965 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6966 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6967 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6968 LOGD("audio offload is supportable");
6974 LOGD("audio offload is not supportable");
6977 g_variant_unref(result);
6979 g_object_unref(conn);
6984 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6986 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6987 gint64 position = 0;
6989 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6990 player->pipeline && player->pipeline->mainbin);
6992 MMPLAYER_CMD_LOCK(player);
6993 current_state = MMPLAYER_CURRENT_STATE(player);
6995 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6996 LOGW("getting current position failed in paused");
6998 _mmplayer_unrealize((MMHandleType)player);
6999 _mmplayer_realize((MMHandleType)player);
7001 _mmplayer_set_position((MMHandleType)player, position);
7003 /* async not to be blocked in streaming case */
7004 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7006 _mmplayer_pause((MMHandleType)player);
7008 if (current_state == MM_PLAYER_STATE_PLAYING)
7009 _mmplayer_start((MMHandleType)player);
7010 MMPLAYER_CMD_UNLOCK(player);
7012 LOGD("rebuilding audio pipeline is completed.");
7015 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7017 mmplayer_t *player = (mmplayer_t *)user_data;
7018 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7019 gboolean is_supportable = FALSE;
7021 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7022 LOGW("failed to get device type");
7024 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7026 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7027 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7028 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7029 LOGD("ignore this dev connected info");
7033 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7034 if (player->build_audio_offload == is_supportable) {
7035 LOGD("keep current pipeline without re-building");
7039 /* rebuild pipeline */
7040 LOGD("re-build pipeline - offload: %d", is_supportable);
7041 player->build_audio_offload = FALSE;
7042 __mmplayer_rebuild_audio_pipeline(player);
7048 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7050 unsigned int id = 0;
7052 if (player->audio_device_cb_id != 0) {
7053 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7057 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7058 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7059 LOGD("added device connected cb (%u)", id);
7060 player->audio_device_cb_id = id;
7062 LOGW("failed to add device connected cb");
7069 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7071 mmplayer_t *player = (mmplayer_t *)hplayer;
7074 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7075 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7077 *activated = player->build_audio_offload;
7079 LOGD("offload activated : %d", (int)*activated);
7082 return MM_ERROR_NONE;
7086 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7089 this function need to be updated according to the supported media format
7090 @see player->ini.audio_offload_media_format */
7092 if (__mmplayer_is_only_mp3_type(player->type)) {
7093 LOGD("offload supportable media format type");
7101 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7103 gboolean ret = FALSE;
7104 GstElementFactory *factory = NULL;
7107 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7109 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7110 if (!__mmplayer_is_offload_supported_type(player))
7113 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7114 LOGD("there is no audio offload sink");
7118 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7119 LOGW("there is no audio device type to support offload");
7123 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7125 LOGW("there is no installed audio offload sink element");
7128 gst_object_unref(factory);
7130 if (_mmplayer_acquire_hw_resource(player,
7131 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7132 LOGE("failed to acquire audio offload decoder resource");
7136 if (!__mmplayer_add_audio_device_connected_cb(player))
7139 if (!__mmplayer_is_audio_offload_device_type(player))
7142 LOGD("audio offload can be built");
7147 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7153 static GstAutoplugSelectResult
7154 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7156 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7157 int audio_offload = 0;
7159 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7160 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7162 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7163 LOGD("expose audio path to build offload output path");
7164 player->build_audio_offload = TRUE;
7165 /* update codec info */
7166 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7167 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7168 player->audiodec_linked = 1;
7170 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7174 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7175 And need to consider the multi-track audio content.
7176 There is no HW audio decoder in public. */
7178 /* set stream information */
7179 if (!player->audiodec_linked)
7180 _mmplayer_set_audio_attrs(player, caps);
7182 /* update codec info */
7183 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7184 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7185 player->audiodec_linked = 1;
7187 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7189 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7190 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7192 /* mark video decoder for acquire */
7193 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7194 LOGW("video decoder resource is already acquired, skip it.");
7195 ret = GST_AUTOPLUG_SELECT_SKIP;
7199 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7200 LOGE("failed to acquire video decoder resource");
7201 ret = GST_AUTOPLUG_SELECT_SKIP;
7204 player->interrupted_by_resource = FALSE;
7207 /* update codec info */
7208 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7209 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7210 player->videodec_linked = 1;
7218 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7219 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7221 #define DEFAULT_IDX 0xFFFF
7222 #define MIN_FACTORY_NUM 2
7223 mmplayer_t *player = (mmplayer_t *)data;
7224 GValueArray *new_factories = NULL;
7225 GValue val = { 0, };
7226 GstElementFactory *factory = NULL;
7227 const gchar *klass = NULL;
7228 gchar *factory_name = NULL;
7229 guint hw_dec_idx = DEFAULT_IDX;
7230 guint first_sw_dec_idx = DEFAULT_IDX;
7231 guint last_sw_dec_idx = DEFAULT_IDX;
7232 guint new_pos = DEFAULT_IDX;
7233 guint rm_pos = DEFAULT_IDX;
7234 int audio_codec_type;
7235 int video_codec_type;
7236 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7238 if (factories->n_values < MIN_FACTORY_NUM)
7241 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7242 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7245 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7247 for (int i = 0 ; i < factories->n_values ; i++) {
7248 gchar *hw_dec_info = NULL;
7249 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7251 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7253 LOGW("failed to get factory object");
7256 klass = gst_element_factory_get_klass(factory);
7257 factory_name = GST_OBJECT_NAME(factory);
7260 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7262 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7263 if (!player->need_audio_dec_sorting) {
7264 LOGD("sorting is not required");
7267 codec_type = audio_codec_type;
7268 hw_dec_info = player->ini.audiocodec_element_hw;
7269 sw_dec_info = player->ini.audiocodec_element_sw;
7270 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7271 if (!player->need_video_dec_sorting) {
7272 LOGD("sorting is not required");
7275 codec_type = video_codec_type;
7276 hw_dec_info = player->ini.videocodec_element_hw;
7277 sw_dec_info = player->ini.videocodec_element_sw;
7282 if (g_strrstr(factory_name, hw_dec_info)) {
7285 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7286 if (strstr(factory_name, sw_dec_info[j])) {
7287 last_sw_dec_idx = i;
7288 if (first_sw_dec_idx == DEFAULT_IDX) {
7289 first_sw_dec_idx = i;
7294 if (first_sw_dec_idx == DEFAULT_IDX)
7295 LOGW("unknown codec %s", factory_name);
7299 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7302 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7303 if (hw_dec_idx < first_sw_dec_idx)
7305 new_pos = first_sw_dec_idx;
7306 rm_pos = hw_dec_idx + 1;
7307 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7308 if (last_sw_dec_idx < hw_dec_idx)
7310 new_pos = last_sw_dec_idx + 1;
7311 rm_pos = hw_dec_idx;
7316 /* change position - insert H/W decoder according to the new position */
7317 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7319 LOGW("failed to get factory object");
7322 new_factories = g_value_array_copy(factories);
7323 g_value_init (&val, G_TYPE_OBJECT);
7324 g_value_set_object (&val, factory);
7325 g_value_array_insert(new_factories, new_pos, &val);
7326 g_value_unset (&val);
7327 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7329 for (int i = 0 ; i < new_factories->n_values ; i++) {
7330 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7332 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7333 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7335 LOGE("[Re-arranged] failed to get factory object");
7338 return new_factories;
7342 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7343 GstCaps *caps, GstElementFactory *factory, gpointer data)
7345 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7346 mmplayer_t *player = (mmplayer_t *)data;
7348 gchar *factory_name = NULL;
7349 gchar *caps_str = NULL;
7350 const gchar *klass = NULL;
7353 factory_name = GST_OBJECT_NAME(factory);
7354 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7355 caps_str = gst_caps_to_string(caps);
7357 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7359 /* store type string */
7360 if (player->type == NULL) {
7361 player->type = gst_caps_to_string(caps);
7362 __mmplayer_update_content_type_info(player);
7365 /* filtering exclude keyword */
7366 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7367 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7368 LOGW("skipping [%s] by exclude keyword [%s]",
7369 factory_name, player->ini.exclude_element_keyword[idx]);
7371 result = GST_AUTOPLUG_SELECT_SKIP;
7376 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7377 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7378 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7379 factory_name, player->ini.unsupported_codec_keyword[idx]);
7380 result = GST_AUTOPLUG_SELECT_SKIP;
7385 /* exclude webm format */
7386 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7387 * because webm format is not supportable.
7388 * If webm is disabled in "autoplug-continue", there is no state change
7389 * failure or error because the decodebin will expose the pad directly.
7390 * It make MSL invoke _prepare_async_callback.
7391 * So, we need to disable webm format in "autoplug-select" */
7392 if (caps_str && strstr(caps_str, "webm")) {
7393 LOGW("webm is not supported");
7394 result = GST_AUTOPLUG_SELECT_SKIP;
7398 /* check factory class for filtering */
7399 /* NOTE : msl don't need to use image plugins.
7400 * So, those plugins should be skipped for error handling.
7402 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7403 LOGD("skipping [%s] by not required", factory_name);
7404 result = GST_AUTOPLUG_SELECT_SKIP;
7408 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7409 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7410 // TO CHECK : subtitle if needed, add subparse exception.
7411 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7412 result = GST_AUTOPLUG_SELECT_SKIP;
7416 if (g_strrstr(factory_name, "mpegpsdemux")) {
7417 LOGD("skipping PS container - not support");
7418 result = GST_AUTOPLUG_SELECT_SKIP;
7422 if (g_strrstr(factory_name, "mssdemux"))
7423 player->smooth_streaming = TRUE;
7425 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7426 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7429 GstStructure *str = NULL;
7430 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7432 /* don't make video because of not required */
7433 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7434 (!player->set_mode.video_export)) {
7435 LOGD("no need video decoding, expose pad");
7436 result = GST_AUTOPLUG_SELECT_EXPOSE;
7440 /* get w/h for omx state-tune */
7441 /* FIXME: deprecated? */
7442 str = gst_caps_get_structure(caps, 0);
7443 gst_structure_get_int(str, "width", &width);
7446 if (player->v_stream_caps) {
7447 gst_caps_unref(player->v_stream_caps);
7448 player->v_stream_caps = NULL;
7451 player->v_stream_caps = gst_caps_copy(caps);
7452 LOGD("take caps for video state tune");
7453 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7457 if (g_strrstr(klass, "Codec/Decoder")) {
7458 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7459 if (result != GST_AUTOPLUG_SELECT_TRY) {
7460 LOGW("skip add decoder");
7466 MMPLAYER_FREEIF(caps_str);
7472 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *pad,
7475 int ret = MM_ERROR_NONE;
7476 mmplayer_t *player = (mmplayer_t *)data;
7477 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
7478 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
7479 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
7482 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && mainbin);
7484 LOGD("decoded pad %s:%s removed", GST_DEBUG_PAD_NAME(pad));
7486 if (MMPLAYER_USE_DECODEBIN(player))
7489 if (!videobin || !g_str_has_prefix (GST_PAD_NAME (pad), "video"))
7492 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_V_CONCAT].gst, GST_STATE_NULL, FALSE, timeout);
7493 if (ret != MM_ERROR_NONE) {
7494 LOGE("fail to change state to NULL");
7498 ret = _mmplayer_gst_set_state(player, videobin[MMPLAYER_V_BIN].gst, GST_STATE_NULL, FALSE, timeout);
7499 if (ret != MM_ERROR_NONE) {
7500 LOGE("fail to change state to NULL");
7504 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), mainbin[MMPLAYER_M_V_CONCAT].gst)) {
7505 LOGE("failed to remove video concat");
7508 if (!gst_bin_remove(GST_BIN_CAST(mainbin[MMPLAYER_M_PIPE].gst), videobin[MMPLAYER_V_BIN].gst)) {
7509 LOGE("failed to remove videobin");
7512 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_V_CONCAT].gst));
7513 mainbin[MMPLAYER_M_V_CONCAT].gst = NULL;
7514 mainbin[MMPLAYER_M_V_CONCAT].id = 0;
7516 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
7517 MMPLAYER_FREEIF(player->pipeline->videobin);
7519 ret = __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY);
7520 if (ret != MM_ERROR_NONE)
7521 LOGE("failed to release overlay resources");
7523 player->videodec_linked = 0;
7525 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pad-removed");
7530 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7532 mmplayer_t *player = (mmplayer_t *)data;
7535 MMPLAYER_RETURN_IF_FAIL(player);
7537 LOGD("got about to finish signal");
7539 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7540 LOGW("Fail to get cmd lock");
7544 if (!__mmplayer_verify_gapless_play_path(player)) {
7545 LOGD("decoding is finished.");
7546 MMPLAYER_CMD_UNLOCK(player);
7550 _mmplayer_set_reconfigure_state(player, TRUE);
7551 MMPLAYER_CMD_UNLOCK(player);
7553 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL);
7554 __mmplayer_deactivate_old_path(player);
7560 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7562 mmplayer_t *player = (mmplayer_t *)data;
7563 GstIterator *iter = NULL;
7564 GValue item = { 0, };
7566 gboolean done = FALSE;
7567 gboolean is_all_drained = TRUE;
7570 MMPLAYER_RETURN_IF_FAIL(player);
7572 LOGD("got drained signal");
7574 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7575 LOGW("Fail to get cmd lock");
7579 if (!__mmplayer_verify_gapless_play_path(player)) {
7580 LOGD("decoding is finished.");
7581 MMPLAYER_CMD_UNLOCK(player);
7585 _mmplayer_set_reconfigure_state(player, TRUE);
7586 MMPLAYER_CMD_UNLOCK(player);
7588 /* check decodebin src pads whether they received EOS or not */
7589 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7592 switch (gst_iterator_next(iter, &item)) {
7593 case GST_ITERATOR_OK:
7594 pad = g_value_get_object(&item);
7595 if (pad && !GST_PAD_IS_EOS(pad)) {
7596 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7597 is_all_drained = FALSE;
7600 g_value_reset(&item);
7602 case GST_ITERATOR_RESYNC:
7603 gst_iterator_resync(iter);
7605 case GST_ITERATOR_ERROR:
7606 case GST_ITERATOR_DONE:
7611 g_value_unset(&item);
7612 gst_iterator_free(iter);
7614 if (!is_all_drained) {
7615 LOGD("Wait util the all pads get EOS.");
7620 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7621 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7623 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7624 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7625 __mmplayer_deactivate_old_path(player);
7631 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7633 mmplayer_t *player = (mmplayer_t *)data;
7634 const gchar *klass = NULL;
7635 gchar *factory_name = NULL;
7637 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7638 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7640 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7642 if (__mmplayer_add_dump_buffer_probe(player, element))
7643 LOGD("add buffer probe");
7645 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7646 gchar *selected = NULL;
7647 selected = g_strdup(GST_ELEMENT_NAME(element));
7648 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7650 /* update codec info */
7651 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7652 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7653 player->audiodec_linked = 1;
7654 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7655 /* update codec info */
7656 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7657 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7658 player->videodec_linked = 1;
7661 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7662 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7663 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7665 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7666 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7668 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7669 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7670 "max-video-width", player->adaptive_info.limit.width,
7671 "max-video-height", player->adaptive_info.limit.height, NULL);
7673 } else if (g_strrstr(klass, "Demuxer")) {
7675 LOGD("plugged element is demuxer. take it");
7677 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7678 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7681 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7682 int surface_type = 0;
7684 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7687 // to support trust-zone only
7688 if (g_strrstr(factory_name, "asfdemux")) {
7689 LOGD("set file-location %s", player->profile.uri);
7690 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7691 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7692 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7693 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7694 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7695 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7696 (__mmplayer_is_only_mp3_type(player->type))) {
7697 LOGD("[mpegaudioparse] set streaming pull mode.");
7698 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7700 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7701 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7704 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7705 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7706 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7708 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7709 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7711 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7712 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7713 (MMPLAYER_IS_DASH_STREAMING(player))) {
7714 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7715 _mm_player_streaming_set_multiqueue(player->streamer, element);
7716 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7725 __mmplayer_release_misc(mmplayer_t *player)
7728 bool cur_mode = player->set_mode.rich_audio;
7731 MMPLAYER_RETURN_IF_FAIL(player);
7733 player->sent_bos = FALSE;
7734 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7736 player->seek_state = MMPLAYER_SEEK_NONE;
7738 player->total_bitrate = 0;
7739 player->total_maximum_bitrate = 0;
7741 player->not_found_demuxer = 0;
7743 player->last_position = 0;
7744 player->duration = 0;
7745 player->http_content_size = 0;
7746 player->not_supported_codec = MISSING_PLUGIN_NONE;
7747 player->can_support_codec = FOUND_PLUGIN_NONE;
7748 player->pending_seek.is_pending = false;
7749 player->pending_seek.pos = 0;
7750 player->msg_posted = FALSE;
7751 player->has_many_types = FALSE;
7752 player->is_subtitle_force_drop = FALSE;
7753 player->play_subtitle = FALSE;
7754 player->adjust_subtitle_pos = 0;
7755 player->has_closed_caption = FALSE;
7756 player->set_mode.video_export = false;
7757 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7758 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7760 player->set_mode.rich_audio = cur_mode;
7762 if (player->audio_device_cb_id > 0 &&
7763 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7764 LOGW("failed to remove audio device_connected_callback");
7765 player->audio_device_cb_id = 0;
7767 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7768 player->bitrate[i] = 0;
7769 player->maximum_bitrate[i] = 0;
7772 /* free memory related to audio effect */
7773 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7775 if (player->adaptive_info.var_list) {
7776 g_list_free_full(player->adaptive_info.var_list, g_free);
7777 player->adaptive_info.var_list = NULL;
7780 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7781 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7782 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7784 /* Reset video360 settings to their defaults in case if the pipeline is to be
7787 player->video360_metadata.is_spherical = -1;
7788 player->is_openal_plugin_used = FALSE;
7790 player->is_content_spherical = FALSE;
7791 player->is_video360_enabled = TRUE;
7792 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7793 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7794 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7795 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7796 player->video360_zoom = 1.0f;
7797 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7798 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7800 player->sound.rg_enable = false;
7802 __mmplayer_initialize_video_roi(player);
7807 __mmplayer_release_misc_post(mmplayer_t *player)
7809 gchar *original_uri = NULL;
7812 /* player->pipeline is already released before. */
7813 MMPLAYER_RETURN_IF_FAIL(player);
7815 player->video_decoded_cb = NULL;
7816 player->video_decoded_cb_user_param = NULL;
7817 player->video_stream_prerolled = false;
7819 player->audio_decoded_cb = NULL;
7820 player->audio_decoded_cb_user_param = NULL;
7821 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7823 player->audio_stream_changed_cb = NULL;
7824 player->audio_stream_changed_cb_user_param = NULL;
7826 mm_player_set_attribute((MMHandleType)player, NULL,
7827 "content_video_found", 0, MM_PLAYER_AUDIO_ONLY, 0, NULL);
7829 /* clean found audio decoders */
7830 if (player->audio_decoders) {
7831 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7832 player->audio_decoders = NULL;
7835 /* clean the uri list except original uri */
7836 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7838 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7839 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7840 g_list_free_full(tmp, (GDestroyNotify)g_free);
7843 LOGW("failed to get original uri info");
7845 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7846 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7847 MMPLAYER_FREEIF(original_uri);
7850 /* clear the audio stream buffer list */
7851 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7853 /* clear the video stream bo list */
7854 __mmplayer_video_stream_destroy_bo_list(player);
7855 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7857 if (player->profile.input_mem.buf) {
7858 free(player->profile.input_mem.buf);
7859 player->profile.input_mem.buf = NULL;
7861 player->profile.input_mem.len = 0;
7862 player->profile.input_mem.offset = 0;
7864 player->uri_info.uri_idx = 0;
7869 __mmplayer_check_subtitle(mmplayer_t *player)
7871 MMHandleType attrs = 0;
7872 char *subtitle_uri = NULL;
7876 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7878 /* get subtitle attribute */
7879 attrs = MMPLAYER_GET_ATTRS(player);
7883 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7884 if (!subtitle_uri || !strlen(subtitle_uri))
7887 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7888 player->is_external_subtitle_present = TRUE;
7896 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7898 MMPLAYER_RETURN_IF_FAIL(player);
7900 if (player->eos_timer) {
7901 LOGD("cancel eos timer");
7902 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7903 player->eos_timer = 0;
7910 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7914 MMPLAYER_RETURN_IF_FAIL(player);
7915 MMPLAYER_RETURN_IF_FAIL(sink);
7918 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7920 player->sink_elements = g_list_append(player->sink_elements, sink);
7926 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7930 MMPLAYER_RETURN_IF_FAIL(player);
7931 MMPLAYER_RETURN_IF_FAIL(sink);
7933 player->sink_elements = g_list_remove(player->sink_elements, sink);
7939 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7940 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7942 mmplayer_signal_item_t *item = NULL;
7945 MMPLAYER_RETURN_IF_FAIL(player);
7947 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7948 LOGE("invalid signal type [%d]", type);
7952 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7954 LOGE("cannot connect signal [%s]", signal);
7959 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7960 player->signals[type] = g_list_append(player->signals[type], item);
7966 /* NOTE : be careful with calling this api. please refer to below glib comment
7967 * glib comment : Note that there is a bug in GObject that makes this function much
7968 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7969 * will no longer be called, but, the signal handler is not currently disconnected.
7970 * If the instance is itself being freed at the same time than this doesn't matter,
7971 * since the signal will automatically be removed, but if instance persists,
7972 * then the signal handler will leak. You should not remove the signal yourself
7973 * because in a future versions of GObject, the handler will automatically be
7976 * It's possible to work around this problem in a way that will continue to work
7977 * with future versions of GObject by checking that the signal handler is still
7978 * connected before disconnected it:
7980 * if (g_signal_handler_is_connected(instance, id))
7981 * g_signal_handler_disconnect(instance, id);
7984 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7986 GList *sig_list = NULL;
7987 mmplayer_signal_item_t *item = NULL;
7991 MMPLAYER_RETURN_IF_FAIL(player);
7993 LOGD("release signals type : %d", type);
7995 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7996 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7997 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7998 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7999 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8000 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
8004 sig_list = player->signals[type];
8006 for (; sig_list; sig_list = sig_list->next) {
8007 item = sig_list->data;
8009 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
8010 if (g_signal_handler_is_connected(item->obj, item->sig))
8011 g_signal_handler_disconnect(item->obj, item->sig);
8014 MMPLAYER_FREEIF(item);
8017 g_list_free(player->signals[type]);
8018 player->signals[type] = NULL;
8026 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8028 mmplayer_t *player = 0;
8029 int prev_display_surface_type = 0;
8033 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8035 player = MM_PLAYER_CAST(handle);
8037 /* check video sinkbin is created */
8038 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8039 LOGW("Videosink is already created");
8040 return MM_ERROR_NONE;
8043 LOGD("videosink element is not yet ready");
8045 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8046 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8048 return MM_ERROR_INVALID_ARGUMENT;
8051 /* load previous attributes */
8052 if (player->attrs) {
8053 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8054 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8055 if (prev_display_surface_type == surface_type) {
8056 LOGD("incoming display surface type is same as previous one, do nothing..");
8058 return MM_ERROR_NONE;
8061 LOGE("failed to load attributes");
8063 return MM_ERROR_PLAYER_INTERNAL;
8066 /* videobin is not created yet, so we just set attributes related to display surface */
8067 LOGD("store display attribute for given surface type(%d)", surface_type);
8068 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8069 "display_overlay", wl_surface_id, NULL);
8072 return MM_ERROR_NONE;
8075 /* Note : if silent is true, then subtitle would not be displayed. :*/
8077 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8079 mmplayer_t *player = (mmplayer_t *)hplayer;
8083 /* check player handle */
8084 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8086 player->set_mode.subtitle_off = silent;
8088 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8092 return MM_ERROR_NONE;
8096 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8098 mmplayer_gst_element_t *mainbin = NULL;
8099 mmplayer_gst_element_t *textbin = NULL;
8100 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8101 GstState current_state = GST_STATE_VOID_PENDING;
8102 GstState element_state = GST_STATE_VOID_PENDING;
8103 GstState element_pending_state = GST_STATE_VOID_PENDING;
8105 GstEvent *event = NULL;
8106 int result = MM_ERROR_NONE;
8108 GstClock *curr_clock = NULL;
8109 GstClockTime base_time, start_time, curr_time;
8114 /* check player handle */
8115 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8117 player->pipeline->mainbin &&
8118 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8120 mainbin = player->pipeline->mainbin;
8121 textbin = player->pipeline->textbin;
8123 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8125 // sync clock with current pipeline
8126 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8127 curr_time = gst_clock_get_time(curr_clock);
8129 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8130 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8132 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8133 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8135 if (current_state > GST_STATE_READY) {
8136 // sync state with current pipeline
8137 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8138 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8139 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8141 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8142 if (GST_STATE_CHANGE_FAILURE == ret) {
8143 LOGE("fail to state change.");
8144 result = MM_ERROR_PLAYER_INTERNAL;
8148 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8149 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8152 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8153 gst_object_unref(curr_clock);
8156 // seek to current position
8157 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8158 result = MM_ERROR_PLAYER_INVALID_STATE;
8159 LOGE("gst_element_query_position failed, invalid state");
8163 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8164 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);
8166 _mmplayer_gst_send_event_to_sink(player, event);
8168 result = MM_ERROR_PLAYER_INTERNAL;
8169 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8173 /* sync state with current pipeline */
8174 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8175 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8176 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8178 return MM_ERROR_NONE;
8181 /* release text pipeline resource */
8182 player->textsink_linked = 0;
8184 /* release signal */
8185 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8187 /* release textbin with it's children */
8188 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8189 MMPLAYER_FREEIF(player->pipeline->textbin);
8190 player->pipeline->textbin = NULL;
8192 /* release subtitle elem */
8193 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8194 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8200 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8202 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8203 GstState current_state = GST_STATE_VOID_PENDING;
8205 MMHandleType attrs = 0;
8206 mmplayer_gst_element_t *mainbin = NULL;
8207 mmplayer_gst_element_t *textbin = NULL;
8209 gchar *subtitle_uri = NULL;
8210 int result = MM_ERROR_NONE;
8211 const gchar *charset = NULL;
8215 /* check player handle */
8216 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8218 player->pipeline->mainbin &&
8219 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8220 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8222 mainbin = player->pipeline->mainbin;
8223 textbin = player->pipeline->textbin;
8225 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8226 if (current_state < GST_STATE_READY) {
8227 result = MM_ERROR_PLAYER_INVALID_STATE;
8228 LOGE("Pipeline is not in proper state");
8232 attrs = MMPLAYER_GET_ATTRS(player);
8234 LOGE("cannot get content attribute");
8235 result = MM_ERROR_PLAYER_INTERNAL;
8239 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8240 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8241 LOGE("subtitle uri is not proper filepath");
8242 result = MM_ERROR_PLAYER_INVALID_URI;
8246 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8247 LOGE("failed to get storage info of subtitle path");
8248 result = MM_ERROR_PLAYER_INVALID_URI;
8252 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8253 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8255 if (!strcmp(filepath, subtitle_uri)) {
8256 LOGD("subtitle path is not changed");
8259 if (mm_player_set_attribute((MMHandleType)player, NULL,
8260 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8261 LOGE("failed to set attribute");
8266 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8267 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8268 player->subtitle_language_list = NULL;
8269 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8271 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8272 if (ret != GST_STATE_CHANGE_SUCCESS) {
8273 LOGE("failed to change state of textbin to READY");
8274 result = MM_ERROR_PLAYER_INTERNAL;
8278 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8279 if (ret != GST_STATE_CHANGE_SUCCESS) {
8280 LOGE("failed to change state of subparse to READY");
8281 result = MM_ERROR_PLAYER_INTERNAL;
8285 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8286 if (ret != GST_STATE_CHANGE_SUCCESS) {
8287 LOGE("failed to change state of filesrc to READY");
8288 result = MM_ERROR_PLAYER_INTERNAL;
8292 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8294 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8296 charset = _mmplayer_get_charset(filepath);
8298 LOGD("detected charset is %s", charset);
8299 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8302 result = _mmplayer_sync_subtitle_pipeline(player);
8309 /* API to switch between external subtitles */
8311 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8313 int result = MM_ERROR_NONE;
8314 mmplayer_t *player = (mmplayer_t *)hplayer;
8319 /* check player handle */
8320 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8322 /* filepath can be null in idle state */
8324 /* check file path */
8325 if ((path = strstr(filepath, "file://")))
8326 result = _mmplayer_exist_file_path(path + 7);
8328 result = _mmplayer_exist_file_path(filepath);
8330 if (result != MM_ERROR_NONE) {
8331 LOGE("invalid subtitle path 0x%X", result);
8332 return result; /* file not found or permission denied */
8336 if (!player->pipeline) {
8338 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8339 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8340 LOGE("failed to set attribute");
8341 return MM_ERROR_PLAYER_INTERNAL;
8344 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8345 /* check filepath */
8346 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8348 if (!__mmplayer_check_subtitle(player)) {
8349 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8350 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8351 LOGE("failed to set attribute");
8352 return MM_ERROR_PLAYER_INTERNAL;
8355 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8356 LOGE("fail to create text pipeline");
8357 return MM_ERROR_PLAYER_INTERNAL;
8360 result = _mmplayer_sync_subtitle_pipeline(player);
8362 result = __mmplayer_change_external_subtitle_language(player, filepath);
8365 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8366 player->is_external_subtitle_added_now = TRUE;
8368 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8369 if (!player->subtitle_language_list) {
8370 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8371 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8372 LOGW("subtitle language list is not updated yet");
8374 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8382 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8384 guint active_idx = 0;
8385 GstStream *stream = NULL;
8386 GList *streams = NULL;
8387 GstCaps *caps = NULL;
8390 LOGD("Switching Streams... type: %d, index: %d", type, index);
8392 player->track[type].active_track_index = index;
8394 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8395 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8396 LOGD("track type:%d, total: %d, active: %d", i,
8397 player->track[i].total_track_num, player->track[i].active_track_index);
8398 if (player->track[i].total_track_num > 0 &&
8399 player->track[i].active_track_index > INVALID_TRACK_INDEX) {
8400 active_idx = player->track[i].active_track_index;
8401 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8402 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8403 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8405 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8406 caps = gst_stream_get_caps(stream);
8408 _mmplayer_set_audio_attrs(player, caps);
8409 gst_caps_unref(caps);
8416 LOGD("send select stream event");
8417 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
8418 gst_event_new_select_streams(streams));
8419 g_list_free(streams);
8423 return MM_ERROR_NONE;
8427 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8429 int result = MM_ERROR_NONE;
8430 gchar *change_pad_name = NULL;
8431 GstPad *sinkpad = NULL;
8432 mmplayer_gst_element_t *mainbin = NULL;
8433 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8434 GstCaps *caps = NULL;
8435 gint total_track_num = 0;
8439 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8440 MM_ERROR_PLAYER_NOT_INITIALIZED);
8442 LOGD("Change Track(%d) to %d", type, index);
8444 mainbin = player->pipeline->mainbin;
8446 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8447 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8448 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8449 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8451 /* Changing Video Track is not supported. */
8452 LOGE("Track Type Error");
8456 if (mainbin[elem_idx].gst == NULL) {
8457 result = MM_ERROR_PLAYER_NO_OP;
8458 LOGD("Req track doesn't exist");
8462 total_track_num = player->track[type].total_track_num;
8463 if (total_track_num <= 0) {
8464 result = MM_ERROR_PLAYER_NO_OP;
8465 LOGD("Language list is not available");
8469 if ((index < 0) || (index >= total_track_num)) {
8470 result = MM_ERROR_INVALID_ARGUMENT;
8471 LOGD("Not a proper index : %d", index);
8475 /*To get the new pad from the selector*/
8476 change_pad_name = g_strdup_printf("sink_%u", index);
8477 if (change_pad_name == NULL) {
8478 result = MM_ERROR_PLAYER_INTERNAL;
8479 LOGD("Pad does not exists");
8483 LOGD("new active pad name: %s", change_pad_name);
8485 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8486 if (sinkpad == NULL) {
8487 LOGD("sinkpad is NULL");
8488 result = MM_ERROR_PLAYER_INTERNAL;
8492 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8493 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8495 caps = gst_pad_get_current_caps(sinkpad);
8496 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8499 gst_object_unref(sinkpad);
8501 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8502 _mmplayer_set_audio_attrs(player, caps);
8505 gst_caps_unref(caps);
8508 MMPLAYER_FREEIF(change_pad_name);
8513 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8515 int result = MM_ERROR_NONE;
8516 mmplayer_t *player = NULL;
8517 mmplayer_gst_element_t *mainbin = NULL;
8519 gint current_active_index = 0;
8521 GstState current_state = GST_STATE_VOID_PENDING;
8526 player = (mmplayer_t *)hplayer;
8527 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8529 if (!player->pipeline) {
8530 LOGE("Track %d pre setting -> %d", type, index);
8532 player->track[type].active_track_index = index;
8536 mainbin = player->pipeline->mainbin;
8538 current_active_index = player->track[type].active_track_index;
8540 /*If index is same as running index no need to change the pad*/
8541 if (current_active_index == index)
8544 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8545 result = MM_ERROR_PLAYER_INVALID_STATE;
8549 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8550 if (current_state < GST_STATE_PAUSED) {
8551 result = MM_ERROR_PLAYER_INVALID_STATE;
8552 LOGW("Pipeline not in proper state");
8556 if (MMPLAYER_USE_DECODEBIN(player))
8557 result = __mmplayer_change_selector_pad(player, type, index);
8559 result = __mmplayer_switch_stream(player, type, index);
8561 if (result != MM_ERROR_NONE) {
8562 LOGE("failed to change track");
8566 player->track[type].active_track_index = index;
8568 if (MMPLAYER_USE_DECODEBIN(player)) {
8569 GstEvent *event = NULL;
8570 if (current_state == GST_STATE_PLAYING) {
8571 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8572 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8573 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8575 _mmplayer_gst_send_event_to_sink(player, event);
8577 result = MM_ERROR_PLAYER_INTERNAL;
8588 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8590 mmplayer_t *player = (mmplayer_t *)hplayer;
8594 /* check player handle */
8595 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8597 *silent = player->set_mode.subtitle_off;
8599 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8603 return MM_ERROR_NONE;
8607 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8609 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8610 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8612 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8613 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8617 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8618 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8619 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8620 mmplayer_dump_t *dump_s;
8621 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8622 if (dump_s == NULL) {
8623 LOGE("malloc fail");
8627 dump_s->dump_element_file = NULL;
8628 dump_s->dump_pad = NULL;
8629 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8631 if (dump_s->dump_pad) {
8632 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8633 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]);
8634 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8635 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);
8636 /* add list for removed buffer probe and close FILE */
8637 player->dump_list = g_list_append(player->dump_list, dump_s);
8638 LOGD("%s sink pad added buffer probe for dump", factory_name);
8641 MMPLAYER_FREEIF(dump_s);
8642 LOGE("failed to get %s sink pad added", factory_name);
8649 static GstPadProbeReturn
8650 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8652 FILE *dump_data = (FILE *)u_data;
8654 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8655 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8657 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8659 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8661 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8663 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8665 gst_buffer_unmap(buffer, &probe_info);
8667 return GST_PAD_PROBE_OK;
8671 __mmplayer_release_dump_list(GList *dump_list)
8673 GList *d_list = dump_list;
8678 for (; d_list; d_list = g_list_next(d_list)) {
8679 mmplayer_dump_t *dump_s = d_list->data;
8680 if (dump_s->dump_pad) {
8681 if (dump_s->probe_handle_id)
8682 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8683 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8685 if (dump_s->dump_element_file) {
8686 fclose(dump_s->dump_element_file);
8687 dump_s->dump_element_file = NULL;
8689 MMPLAYER_FREEIF(dump_s);
8691 g_list_free(dump_list);
8696 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8698 mmplayer_t *player = (mmplayer_t *)hplayer;
8702 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8703 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8705 *exist = (bool)player->has_closed_caption;
8709 return MM_ERROR_NONE;
8713 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8718 LOGD("unref internal gst buffer %p", buffer);
8720 gst_buffer_unref((GstBuffer *)buffer);
8727 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8729 mmplayer_t *player = (mmplayer_t *)hplayer;
8733 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8734 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8736 if (MMPLAYER_IS_STREAMING(player))
8737 *timeout = (int)player->ini.live_state_change_timeout;
8739 *timeout = (int)player->ini.localplayback_state_change_timeout;
8741 LOGD("timeout = %d", *timeout);
8744 return MM_ERROR_NONE;
8748 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8752 MMPLAYER_RETURN_IF_FAIL(player);
8754 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8756 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8757 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8758 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8759 player->storage_info[i].id = -1;
8760 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8762 if (path_type != MMPLAYER_PATH_MAX)
8771 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8773 int ret = MM_ERROR_NONE;
8774 mmplayer_t *player = (mmplayer_t *)hplayer;
8775 MMMessageParamType msg_param = {0, };
8778 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8780 LOGW("state changed storage %d:%d", id, state);
8782 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8783 return MM_ERROR_NONE;
8785 /* FIXME: text path should be handled separately. */
8786 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8787 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8788 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8789 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8790 LOGW("external storage is removed");
8792 if (player->msg_posted == FALSE) {
8793 memset(&msg_param, 0, sizeof(MMMessageParamType));
8794 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8795 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8796 player->msg_posted = TRUE;
8799 /* unrealize the player */
8800 ret = _mmplayer_unrealize(hplayer);
8801 if (ret != MM_ERROR_NONE)
8802 LOGE("failed to unrealize");
8810 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8812 int ret = MM_ERROR_NONE;
8813 mmplayer_t *player = (mmplayer_t *)hplayer;
8814 int idx = 0, total = 0;
8815 gchar *result = NULL, *tmp = NULL;
8818 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8819 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8821 total = *num = g_list_length(player->adaptive_info.var_list);
8823 LOGW("There is no stream variant info.");
8827 result = g_strdup("");
8828 for (idx = 0 ; idx < total ; idx++) {
8829 stream_variant_t *v_data = NULL;
8830 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8833 gchar data[64] = {0};
8834 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8836 tmp = g_strconcat(result, data, NULL);
8840 LOGW("There is no variant data in %d", idx);
8845 *var_info = (char *)result;
8847 LOGD("variant info %d:%s", *num, *var_info);
8853 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8855 int ret = MM_ERROR_NONE;
8856 mmplayer_t *player = (mmplayer_t *)hplayer;
8859 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8861 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8863 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8864 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8865 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8867 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8868 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8869 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8870 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8872 /* FIXME: seek to current position for applying new variant limitation */
8881 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8883 int ret = MM_ERROR_NONE;
8884 mmplayer_t *player = (mmplayer_t *)hplayer;
8887 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8888 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8890 *bandwidth = player->adaptive_info.limit.bandwidth;
8891 *width = player->adaptive_info.limit.width;
8892 *height = player->adaptive_info.limit.height;
8894 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8901 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8903 int ret = MM_ERROR_NONE;
8904 mmplayer_t *player = (mmplayer_t *)hplayer;
8907 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8908 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8909 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8911 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8913 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8914 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8915 else /* live case */
8916 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8918 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8925 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8927 #define IDX_FIRST_SW_CODEC 0
8928 mmplayer_t *player = (mmplayer_t *)hplayer;
8929 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8930 const char *attr_name = NULL;
8931 const char *default_type = NULL;
8932 const char *element_hw = NULL;
8933 const char *element_sw = NULL;
8936 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8938 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8940 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8941 switch (stream_type) {
8942 case MM_PLAYER_STREAM_TYPE_AUDIO:
8943 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8944 default_type = player->ini.audiocodec_default_type;
8945 element_hw = player->ini.audiocodec_element_hw;
8946 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8948 case MM_PLAYER_STREAM_TYPE_VIDEO:
8949 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8950 default_type = player->ini.videocodec_default_type;
8951 element_hw = player->ini.videocodec_element_hw;
8952 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8955 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8956 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8960 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8962 if (!strcmp(default_type, "sw"))
8963 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8965 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8967 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8968 codec_type = default_codec_type;
8970 /* to support codec selection, codec info have to be added in ini file.
8971 in case of hw codec is selected, filter elements should be applied
8972 depending on the hw capabilities. */
8973 if (codec_type != default_codec_type) {
8974 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
8975 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
8976 LOGE("There is no codec for type %d", codec_type);
8977 return MM_ERROR_PLAYER_NO_OP;
8980 LOGD("sorting is required");
8981 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
8982 player->need_audio_dec_sorting = TRUE;
8984 player->need_video_dec_sorting = TRUE;
8987 LOGD("update %s codec_type to %d", attr_name, codec_type);
8988 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8991 return MM_ERROR_NONE;
8995 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8997 mmplayer_t *player = (mmplayer_t *)hplayer;
8998 GstElement *rg_vol_element = NULL;
9002 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9004 player->sound.rg_enable = enabled;
9006 /* just hold rgvolume enable value if pipeline is not ready */
9007 if (!player->pipeline || !player->pipeline->audiobin) {
9008 LOGD("pipeline is not ready. holding rgvolume enable value");
9009 return MM_ERROR_NONE;
9012 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9014 if (!rg_vol_element) {
9015 LOGD("rgvolume element is not created");
9016 return MM_ERROR_PLAYER_INTERNAL;
9020 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
9022 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
9026 return MM_ERROR_NONE;
9030 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
9032 mmplayer_t *player = (mmplayer_t *)hplayer;
9033 GstElement *rg_vol_element = NULL;
9034 gboolean enable = FALSE;
9038 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9039 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9041 /* just hold enable_rg value if pipeline is not ready */
9042 if (!player->pipeline || !player->pipeline->audiobin) {
9043 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9044 *enabled = player->sound.rg_enable;
9045 return MM_ERROR_NONE;
9048 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9050 if (!rg_vol_element) {
9051 LOGD("rgvolume element is not created");
9052 return MM_ERROR_PLAYER_INTERNAL;
9055 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9056 *enabled = (bool)enable;
9060 return MM_ERROR_NONE;
9064 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9066 mmplayer_t *player = (mmplayer_t *)hplayer;
9067 MMHandleType attrs = 0;
9069 int ret = MM_ERROR_NONE;
9073 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9075 attrs = MMPLAYER_GET_ATTRS(player);
9076 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9078 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9080 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9081 return MM_ERROR_PLAYER_INTERNAL;
9084 player->video_roi.scale_x = scale_x;
9085 player->video_roi.scale_y = scale_y;
9086 player->video_roi.scale_width = scale_width;
9087 player->video_roi.scale_height = scale_height;
9089 /* check video sinkbin is created */
9090 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9091 return MM_ERROR_NONE;
9093 if (!gst_video_overlay_set_video_roi_area(
9094 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9095 scale_x, scale_y, scale_width, scale_height))
9096 ret = MM_ERROR_PLAYER_INTERNAL;
9098 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9099 scale_x, scale_y, scale_width, scale_height);
9107 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9109 mmplayer_t *player = (mmplayer_t *)hplayer;
9110 int ret = MM_ERROR_NONE;
9114 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9115 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9117 *scale_x = player->video_roi.scale_x;
9118 *scale_y = player->video_roi.scale_y;
9119 *scale_width = player->video_roi.scale_width;
9120 *scale_height = player->video_roi.scale_height;
9122 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9123 *scale_x, *scale_y, *scale_width, *scale_height);
9129 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9131 mmplayer_t *player = (mmplayer_t *)hplayer;
9135 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9137 player->client_pid = pid;
9139 LOGD("client pid[%d] %p", pid, player);
9143 return MM_ERROR_NONE;
9147 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9149 mmplayer_t *player = (mmplayer_t *)hplayer;
9150 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9151 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9155 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9156 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9159 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9161 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9163 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9164 return MM_ERROR_NONE;
9166 /* in case of audio codec default type is HW */
9168 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9169 if (player->ini.support_audio_effect)
9170 return MM_ERROR_NONE;
9171 elem_id = MMPLAYER_A_FILTER;
9173 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9174 if (player->ini.support_replaygain_control)
9175 return MM_ERROR_NONE;
9176 elem_id = MMPLAYER_A_RGVOL;
9178 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9179 if (player->ini.support_pitch_control)
9180 return MM_ERROR_NONE;
9181 elem_id = MMPLAYER_A_PITCH;
9183 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9184 if (player->ini.support_audio_effect)
9185 return MM_ERROR_NONE;
9187 /* default case handling is not required */
9190 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9191 LOGW("audio control option [%d] is not available", opt);
9194 /* setting pcm exporting option is allowed before READY state */
9195 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9196 return MM_ERROR_PLAYER_INVALID_STATE;
9198 /* check whether the audio filter exist or not after READY state,
9199 because the sw codec could be added during auto-plugging in some cases */
9200 if (!player->pipeline ||
9201 !player->pipeline->audiobin ||
9202 !player->pipeline->audiobin[elem_id].gst) {
9203 LOGW("there is no audio elem [%d]", elem_id);
9208 LOGD("audio control opt %d, available %d", opt, *available);
9212 return MM_ERROR_NONE;
9216 __mmplayer_update_duration_value(mmplayer_t *player)
9218 gboolean ret = FALSE;
9219 gint64 dur_nsec = 0;
9220 LOGD("try to update duration");
9222 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9223 player->duration = dur_nsec;
9224 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9228 if (player->duration < 0) {
9229 LOGW("duration is Non-Initialized !!!");
9230 player->duration = 0;
9233 /* update streaming service type */
9234 player->streaming_type = _mmplayer_get_stream_service_type(player);
9236 /* check duration is OK */
9237 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9238 /* FIXIT : find another way to get duration here. */
9239 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9245 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9247 /* update audio params
9248 NOTE : We need original audio params and it can be only obtained from src pad of audio
9249 decoder. Below code only valid when we are not using 'resampler' just before
9250 'audioconverter'. */
9251 GstCaps *caps_a = NULL;
9253 gint samplerate = 0, channels = 0;
9254 GstStructure *p = NULL;
9255 GstElement *aconv = NULL;
9257 LOGD("try to update audio attrs");
9259 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9261 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9262 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9263 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9264 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9266 LOGE("there is no audio converter");
9270 pad = gst_element_get_static_pad(aconv, "sink");
9273 LOGW("failed to get pad from audio converter");
9277 caps_a = gst_pad_get_current_caps(pad);
9279 LOGW("not ready to get audio caps");
9280 gst_object_unref(pad);
9284 p = gst_caps_get_structure(caps_a, 0);
9286 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9288 gst_structure_get_int(p, "rate", &samplerate);
9289 gst_structure_get_int(p, "channels", &channels);
9291 mm_player_set_attribute((MMHandleType)player, NULL,
9292 "content_audio_samplerate", samplerate,
9293 "content_audio_channels", channels, NULL);
9295 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9297 gst_caps_unref(caps_a);
9298 gst_object_unref(pad);
9304 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9306 LOGD("try to update video attrs");
9308 GstCaps *caps_v = NULL;
9312 GstStructure *p = NULL;
9314 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9315 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9317 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9319 LOGD("no videosink sink pad");
9323 caps_v = gst_pad_get_current_caps(pad);
9324 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9325 if (!caps_v && player->v_stream_caps) {
9326 caps_v = player->v_stream_caps;
9327 gst_caps_ref(caps_v);
9331 LOGD("no negotiated caps from videosink");
9332 gst_object_unref(pad);
9336 p = gst_caps_get_structure(caps_v, 0);
9337 gst_structure_get_int(p, "width", &width);
9338 gst_structure_get_int(p, "height", &height);
9340 mm_player_set_attribute((MMHandleType)player, NULL,
9341 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9343 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9345 SECURE_LOGD("width : %d height : %d", width, height);
9347 gst_caps_unref(caps_v);
9348 gst_object_unref(pad);
9351 mm_player_set_attribute((MMHandleType)player, NULL,
9352 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9353 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9360 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9362 gboolean ret = FALSE;
9363 guint64 data_size = 0;
9367 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9368 if (!player->duration)
9371 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9372 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9373 if (stat(path, &sb) == 0)
9374 data_size = (guint64)sb.st_size;
9376 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9377 data_size = player->http_content_size;
9380 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9383 guint64 bitrate = 0;
9384 guint64 msec_dur = 0;
9386 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9388 bitrate = data_size * 8 * 1000 / msec_dur;
9389 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9390 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9391 mm_player_set_attribute((MMHandleType)player, NULL,
9392 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9395 LOGD("player duration is less than 0");
9399 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9400 if (player->total_bitrate) {
9401 mm_player_set_attribute((MMHandleType)player, NULL,
9402 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9411 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9413 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9414 data->uri_type = uri_type;
9418 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9420 int ret = MM_ERROR_PLAYER_INVALID_URI;
9422 char *buffer = NULL;
9423 char *seperator = strchr(path, ',');
9424 char ext[100] = {0,}, size[100] = {0,};
9427 if ((buffer = strstr(path, "ext="))) {
9428 buffer += strlen("ext=");
9430 if (strlen(buffer)) {
9431 strncpy(ext, buffer, 99);
9433 if ((seperator = strchr(ext, ','))
9434 || (seperator = strchr(ext, ' '))
9435 || (seperator = strchr(ext, '\0'))) {
9436 seperator[0] = '\0';
9441 if ((buffer = strstr(path, "size="))) {
9442 buffer += strlen("size=");
9444 if (strlen(buffer) > 0) {
9445 strncpy(size, buffer, 99);
9447 if ((seperator = strchr(size, ','))
9448 || (seperator = strchr(size, ' '))
9449 || (seperator = strchr(size, '\0'))) {
9450 seperator[0] = '\0';
9453 mem_size = atoi(size);
9458 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9460 if (mem_size && param) {
9461 if (data->input_mem.buf)
9462 free(data->input_mem.buf);
9463 data->input_mem.buf = malloc(mem_size);
9465 if (data->input_mem.buf) {
9466 memcpy(data->input_mem.buf, param, mem_size);
9467 data->input_mem.len = mem_size;
9468 ret = MM_ERROR_NONE;
9470 LOGE("failed to alloc mem %d", mem_size);
9471 ret = MM_ERROR_PLAYER_INTERNAL;
9474 data->input_mem.offset = 0;
9475 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9482 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9484 gchar *location = NULL;
9487 int ret = MM_ERROR_NONE;
9489 if ((path = strstr(uri, "file://"))) {
9490 location = g_filename_from_uri(uri, NULL, &err);
9491 if (!location || (err != NULL)) {
9492 LOGE("Invalid URI '%s' for filesrc: %s", path,
9493 (err != NULL) ? err->message : "unknown error");
9497 MMPLAYER_FREEIF(location);
9499 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9500 return MM_ERROR_PLAYER_INVALID_URI;
9502 LOGD("path from uri: %s", location);
9505 path = (location != NULL) ? (location) : ((char *)uri);
9508 ret = _mmplayer_exist_file_path(path);
9510 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9511 if (ret == MM_ERROR_NONE) {
9512 if (_mmplayer_is_sdp_file(path)) {
9513 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9514 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9515 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9517 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9518 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9520 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9521 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9523 LOGE("invalid uri, could not play..");
9524 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9527 MMPLAYER_FREEIF(location);
9532 static mmplayer_video_decoded_data_info_t *
9533 __mmplayer_create_stream_from_pad(GstPad *pad)
9535 GstCaps *caps = NULL;
9536 GstStructure *structure = NULL;
9537 unsigned int fourcc = 0;
9538 const gchar *string_format = NULL;
9539 mmplayer_video_decoded_data_info_t *stream = NULL;
9541 MMPixelFormatType format;
9544 caps = gst_pad_get_current_caps(pad);
9546 LOGE("Caps is NULL.");
9551 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9553 structure = gst_caps_get_structure(caps, 0);
9554 gst_structure_get_int(structure, "width", &width);
9555 gst_structure_get_int(structure, "height", &height);
9556 string_format = gst_structure_get_string(structure, "format");
9559 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9560 format = _mmplayer_get_pixtype(fourcc);
9561 gst_video_info_from_caps(&info, caps);
9562 gst_caps_unref(caps);
9565 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9566 LOGE("Wrong condition!!");
9570 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9572 LOGE("failed to alloc mem for video data");
9576 stream->width = width;
9577 stream->height = height;
9578 stream->format = format;
9579 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9585 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9587 unsigned int pitch = 0;
9588 unsigned int size = 0;
9590 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9593 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9594 bo = gst_tizen_memory_get_bos(mem, index);
9596 stream->bo[index] = tbm_bo_ref(bo);
9598 LOGE("failed to get bo for index %d", index);
9601 for (index = 0; index < stream->plane_num; index++) {
9602 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9603 stream->stride[index] = pitch;
9605 stream->elevation[index] = size / pitch;
9607 stream->elevation[index] = stream->height;
9612 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9614 if (stream->format == MM_PIXEL_FORMAT_I420) {
9615 int ret = TBM_SURFACE_ERROR_NONE;
9616 tbm_surface_h surface;
9617 tbm_surface_info_s info;
9619 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9621 ret = tbm_surface_get_info(surface, &info);
9622 if (ret != TBM_SURFACE_ERROR_NONE) {
9623 tbm_surface_destroy(surface);
9627 tbm_surface_destroy(surface);
9628 stream->stride[0] = info.planes[0].stride;
9629 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9630 stream->stride[1] = info.planes[1].stride;
9631 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9632 stream->stride[2] = info.planes[2].stride;
9633 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9634 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9635 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9636 stream->stride[0] = stream->width * 4;
9637 stream->elevation[0] = stream->height;
9638 stream->bo_size = stream->stride[0] * stream->height;
9640 LOGE("Not support format %d", stream->format);
9648 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9650 tbm_bo_handle thandle;
9652 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9653 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9654 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9658 unsigned char *src = NULL;
9659 unsigned char *dest = NULL;
9660 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9662 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9664 LOGE("fail to gst_memory_map");
9668 if (!mapinfo.data) {
9669 LOGE("data pointer is wrong");
9673 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9674 if (!stream->bo[0]) {
9675 LOGE("Fail to tbm_bo_alloc!!");
9679 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9681 LOGE("thandle pointer is wrong");
9685 if (stream->format == MM_PIXEL_FORMAT_I420) {
9686 src_stride[0] = GST_ROUND_UP_4(stream->width);
9687 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9688 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9689 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9692 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9693 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9695 for (i = 0; i < 3; i++) {
9696 src = mapinfo.data + src_offset[i];
9697 dest = thandle.ptr + dest_offset[i];
9702 for (j = 0; j < stream->height >> k; j++) {
9703 memcpy(dest, src, stream->width>>k);
9704 src += src_stride[i];
9705 dest += stream->stride[i];
9708 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9709 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9711 LOGE("Not support format %d", stream->format);
9715 tbm_bo_unmap(stream->bo[0]);
9716 gst_memory_unmap(mem, &mapinfo);
9722 tbm_bo_unmap(stream->bo[0]);
9725 gst_memory_unmap(mem, &mapinfo);
9731 __mmplayer_set_pause_state(mmplayer_t *player)
9733 if (player->sent_bos)
9736 /* rtsp case, get content attrs by GstMessage */
9737 if (MMPLAYER_IS_RTSP_STREAMING(player))
9740 /* it's first time to update all content attrs. */
9741 _mmplayer_update_content_attrs(player, ATTR_ALL);
9745 __mmplayer_set_playing_state(mmplayer_t *player)
9747 gchar *audio_codec = NULL;
9749 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9750 /* initialize because auto resume is done well. */
9751 player->resumed_by_rewind = FALSE;
9752 player->playback_rate = 1.0;
9755 if (player->sent_bos)
9758 /* try to get content metadata */
9760 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9761 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9762 * legacy mmfw-player api
9764 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9766 if ((player->cmd == MMPLAYER_COMMAND_START)
9767 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9768 __mmplayer_handle_missed_plugin(player);
9771 /* check audio codec field is set or not
9772 * we can get it from typefinder or codec's caps.
9774 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9776 /* The codec format can't be sent for audio only case like amr, mid etc.
9777 * Because, parser don't make related TAG.
9778 * So, if it's not set yet, fill it with found data.
9781 if (g_strrstr(player->type, "audio/midi"))
9782 audio_codec = "MIDI";
9783 else if (g_strrstr(player->type, "audio/x-amr"))
9784 audio_codec = "AMR";
9785 else if (g_strrstr(player->type, "audio/mpeg")
9786 && !g_strrstr(player->type, "mpegversion=(int)1"))
9787 audio_codec = "AAC";
9789 audio_codec = "unknown";
9791 if (mm_player_set_attribute((MMHandleType)player, NULL,
9792 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9793 LOGE("failed to set attribute");
9795 LOGD("set audio codec type with caps");