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 fucntion 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 /*===========================================================================================
201 | FUNCTION DEFINITIONS |
203 ========================================================================================== */
205 /* This function should be called after the pipeline goes PAUSED or higher
208 _mmplayer_update_content_attrs(mmplayer_t *player, enum content_attr_flag flag)
210 static gboolean has_duration = FALSE;
211 static gboolean has_video_attrs = FALSE;
212 static gboolean has_audio_attrs = FALSE;
213 static gboolean has_bitrate = FALSE;
214 gboolean missing_only = FALSE;
215 gboolean all = FALSE;
216 MMHandleType attrs = 0;
220 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
222 /* check player state here */
223 if (MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PAUSED &&
224 MMPLAYER_CURRENT_STATE(player) != MM_PLAYER_STATE_PLAYING) {
225 /* give warning now only */
226 LOGW("be careful. content attributes may not available in this state ");
229 /* get content attribute first */
230 attrs = MMPLAYER_GET_ATTRS(player);
232 LOGE("cannot get content attribute");
236 /* get update flag */
238 if (flag & ATTR_MISSING_ONLY) {
240 LOGD("updating missed attr only");
243 if (flag & ATTR_ALL) {
245 has_duration = FALSE;
246 has_video_attrs = FALSE;
247 has_audio_attrs = FALSE;
250 LOGD("updating all attrs");
253 if (missing_only && all) {
254 LOGW("cannot use ATTR_MISSING_ONLY and ATTR_ALL. ignoring ATTR_MISSING_ONLY flag!");
255 missing_only = FALSE;
258 if ((flag & ATTR_DURATION) || (!has_duration && missing_only) || all)
259 has_duration = __mmplayer_update_duration_value(player);
261 if ((flag & ATTR_AUDIO) || (!has_audio_attrs && missing_only) || all)
262 has_audio_attrs = __mmplayer_update_audio_attrs(player, attrs);
264 if ((flag & ATTR_VIDEO) || (!has_video_attrs && missing_only) || all)
265 has_video_attrs = __mmplayer_update_video_attrs(player, attrs);
267 if ((flag & ATTR_BITRATE) || (!has_bitrate && missing_only) || all)
268 has_bitrate = __mmplayer_update_bitrate_attrs(player, attrs);
276 _mmplayer_get_stream_service_type(mmplayer_t *player)
278 MMStreamingType streaming_type = STREAMING_SERVICE_NONE;
282 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
284 player->pipeline->mainbin &&
285 player->pipeline->mainbin[MMPLAYER_M_SRC].gst,
286 STREAMING_SERVICE_NONE);
288 /* streaming service type if streaming */
289 if (!MMPLAYER_IS_STREAMING(player))
290 return STREAMING_SERVICE_NONE;
292 streaming_type = (player->duration == 0) ?
293 STREAMING_SERVICE_LIVE : STREAMING_SERVICE_VOD;
295 switch (streaming_type) {
296 case STREAMING_SERVICE_LIVE:
297 LOGD("it's live streaming");
299 case STREAMING_SERVICE_VOD:
300 LOGD("it's vod streaming");
303 LOGE("should not get here");
309 return streaming_type;
312 /* this function sets the player state and also report
313 * it to applicaton by calling callback function
316 _mmplayer_set_state(mmplayer_t *player, int state)
318 MMMessageParamType msg = {0, };
320 MMPLAYER_RETURN_IF_FAIL(player);
322 if (MMPLAYER_CURRENT_STATE(player) == state) {
323 LOGW("already same state(%s)", MMPLAYER_STATE_GET_NAME(state));
324 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
328 /* update player states */
329 MMPLAYER_PREV_STATE(player) = MMPLAYER_CURRENT_STATE(player);
330 MMPLAYER_CURRENT_STATE(player) = state;
332 if (MMPLAYER_CURRENT_STATE(player) == MMPLAYER_PENDING_STATE(player))
333 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
336 MMPLAYER_PRINT_STATE(player);
338 switch (MMPLAYER_CURRENT_STATE(player)) {
339 case MM_PLAYER_STATE_NULL:
340 case MM_PLAYER_STATE_READY:
342 case MM_PLAYER_STATE_PAUSED:
343 __mmplayer_set_pause_state(player);
345 case MM_PLAYER_STATE_PLAYING:
346 __mmplayer_set_playing_state(player);
348 case MM_PLAYER_STATE_NONE:
350 LOGW("invalid target state, there is nothing to do.");
355 /* post message to application */
356 if (MMPLAYER_TARGET_STATE(player) == state) {
357 /* fill the message with state of player */
358 msg.union_type = MM_MSG_UNION_STATE;
359 msg.state.previous = MMPLAYER_PREV_STATE(player);
360 msg.state.current = MMPLAYER_CURRENT_STATE(player);
362 LOGD("player reach the target state (%s)", MMPLAYER_STATE_GET_NAME(MMPLAYER_TARGET_STATE(player)));
364 /* state changed by resource callback */
365 if (player->interrupted_by_resource)
366 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_INTERRUPTED, &msg);
367 else /* state changed by usecase */
368 MMPLAYER_POST_MSG(player, MM_MESSAGE_STATE_CHANGED, &msg);
371 LOGD("intermediate state, do nothing.");
372 MMPLAYER_PRINT_STATE(player);
376 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PLAYING
377 && !player->sent_bos) {
378 MMPLAYER_POST_MSG(player, MM_MESSAGE_BEGIN_OF_STREAM, NULL);
379 player->sent_bos = TRUE;
386 _mmplayer_check_state(mmplayer_t *player, mmplayer_command_state_e command)
388 mmplayer_state_e current_state = MM_PLAYER_STATE_NUM;
389 mmplayer_state_e pending_state = MM_PLAYER_STATE_NUM;
391 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
393 LOGD("incomming command : %d ", command);
395 current_state = MMPLAYER_CURRENT_STATE(player);
396 pending_state = MMPLAYER_PENDING_STATE(player);
398 MMPLAYER_PRINT_STATE(player);
401 case MMPLAYER_COMMAND_CREATE:
403 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
405 if (current_state == MM_PLAYER_STATE_NULL ||
406 current_state == MM_PLAYER_STATE_READY ||
407 current_state == MM_PLAYER_STATE_PAUSED ||
408 current_state == MM_PLAYER_STATE_PLAYING)
413 case MMPLAYER_COMMAND_DESTROY:
415 /* destroy can called anytime */
417 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
421 case MMPLAYER_COMMAND_REALIZE:
423 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
425 if (pending_state != MM_PLAYER_STATE_NONE) {
428 /* need ready state to realize */
429 if (current_state == MM_PLAYER_STATE_READY)
432 if (current_state != MM_PLAYER_STATE_NULL)
438 case MMPLAYER_COMMAND_UNREALIZE:
440 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NULL;
442 if (current_state == MM_PLAYER_STATE_NULL)
447 case MMPLAYER_COMMAND_START:
449 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
451 if (pending_state == MM_PLAYER_STATE_NONE) {
452 if (current_state == MM_PLAYER_STATE_PLAYING)
454 else if (current_state != MM_PLAYER_STATE_READY &&
455 current_state != MM_PLAYER_STATE_PAUSED)
457 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
459 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
460 LOGD("player is going to paused state, just change the pending state as playing");
467 case MMPLAYER_COMMAND_STOP:
469 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_READY;
471 if (current_state == MM_PLAYER_STATE_READY)
474 /* need playing/paused state to stop */
475 if (current_state != MM_PLAYER_STATE_PLAYING &&
476 current_state != MM_PLAYER_STATE_PAUSED)
481 case MMPLAYER_COMMAND_PAUSE:
483 if (MMPLAYER_IS_LIVE_STREAMING(player))
486 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
487 goto NOT_COMPLETED_SEEK;
489 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PAUSED;
491 if (pending_state == MM_PLAYER_STATE_NONE) {
492 if (current_state == MM_PLAYER_STATE_PAUSED)
494 else if (current_state != MM_PLAYER_STATE_PLAYING && current_state != MM_PLAYER_STATE_READY) // support loading state of broswer
496 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
498 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
499 if (current_state == MM_PLAYER_STATE_PAUSED)
500 LOGD("player is PAUSED going to PLAYING, just change the pending state as PAUSED");
507 case MMPLAYER_COMMAND_RESUME:
509 if (player->seek_state == MMPLAYER_SEEK_IN_PROGRESS)
510 goto NOT_COMPLETED_SEEK;
512 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_PLAYING;
514 if (pending_state == MM_PLAYER_STATE_NONE) {
515 if (current_state == MM_PLAYER_STATE_PLAYING)
517 else if (current_state != MM_PLAYER_STATE_PAUSED)
519 } else if (pending_state == MM_PLAYER_STATE_PLAYING) {
521 } else if (pending_state == MM_PLAYER_STATE_PAUSED) {
522 LOGD("player is going to paused state, just change the pending state as playing");
532 player->cmd = command;
534 return MM_ERROR_NONE;
537 LOGW("since player is in wrong state(%s). it's not able to apply the command(%d)",
538 MMPLAYER_STATE_GET_NAME(current_state), command);
539 return MM_ERROR_PLAYER_INVALID_STATE;
542 LOGW("not completed seek");
543 return MM_ERROR_PLAYER_DOING_SEEK;
546 LOGW("player is in the desired state(%s). doing noting", MMPLAYER_STATE_GET_NAME(current_state));
547 return MM_ERROR_PLAYER_NO_OP;
550 LOGW("player is already going to %s, doing nothing", MMPLAYER_STATE_GET_NAME(pending_state));
551 return MM_ERROR_PLAYER_NO_OP;
554 int _mmplayer_acquire_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
556 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
557 mm_resource_manager_res_type_e rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_MAX;
560 case MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER:
561 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER;
563 case MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY:
564 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY;
566 case MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD:
567 rm_res_type = MM_RESOURCE_MANAGER_RES_TYPE_AUDIO_OFFLOAD;
570 LOGE("invalid mmplayer resource type %d", type);
571 return MM_ERROR_PLAYER_INTERNAL;
574 if (player->hw_resource[type] != NULL) {
575 LOGD("[%d type] resource was already acquired", type);
576 return MM_ERROR_NONE;
579 LOGD("mark for acquire [%d type] resource", type);
580 rm_ret = mm_resource_manager_mark_for_acquire(player->resource_manager,
581 rm_res_type, MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &player->hw_resource[type]);
582 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
583 LOGE("failed to mark resource for acquire, ret(0x%x)", rm_ret);
584 return MM_ERROR_PLAYER_INTERNAL;
587 rm_ret = mm_resource_manager_commit(player->resource_manager);
588 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
589 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
590 return MM_ERROR_PLAYER_INTERNAL;
594 return MM_ERROR_NONE;
597 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
599 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
603 if (player->hw_resource[type] == NULL) {
604 LOGD("there is no acquired [%d type] resource", type);
605 return MM_ERROR_NONE;
608 LOGD("mark for release [%d type] resource", type);
609 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
610 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
611 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
612 return MM_ERROR_PLAYER_INTERNAL;
615 player->hw_resource[type] = NULL;
617 rm_ret = mm_resource_manager_commit(player->resource_manager);
618 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
619 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
620 return MM_ERROR_PLAYER_INTERNAL;
624 return MM_ERROR_NONE;
628 __mmplayer_initialize_gapless_play(mmplayer_t *player)
634 player->smooth_streaming = FALSE;
635 player->videodec_linked = 0;
636 player->audiodec_linked = 0;
637 player->textsink_linked = 0;
638 player->is_external_subtitle_present = FALSE;
639 player->is_external_subtitle_added_now = FALSE;
640 player->not_supported_codec = MISSING_PLUGIN_NONE;
641 player->can_support_codec = FOUND_PLUGIN_NONE;
642 player->pending_seek.is_pending = false;
643 player->pending_seek.pos = 0;
644 player->msg_posted = FALSE;
645 player->has_many_types = FALSE;
646 player->no_more_pad = FALSE;
647 player->not_found_demuxer = 0;
648 player->seek_state = MMPLAYER_SEEK_NONE;
649 player->is_subtitle_force_drop = FALSE;
650 player->play_subtitle = FALSE;
651 player->adjust_subtitle_pos = 0;
653 player->total_bitrate = 0;
654 player->total_maximum_bitrate = 0;
656 _mmplayer_track_initialize(player);
657 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
659 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
660 player->bitrate[i] = 0;
661 player->maximum_bitrate[i] = 0;
664 if (player->v_stream_caps) {
665 gst_caps_unref(player->v_stream_caps);
666 player->v_stream_caps = NULL;
669 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
671 /* clean found audio decoders */
672 if (player->audio_decoders) {
673 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
674 player->audio_decoders = NULL;
677 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
682 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
684 LOGI("set pipeline reconfigure state %d", state);
685 MMPLAYER_RECONFIGURE_LOCK(player);
686 player->gapless.reconfigure = state;
687 if (!state) /* wake up the waiting job */
688 MMPLAYER_RECONFIGURE_SIGNAL(player);
689 MMPLAYER_RECONFIGURE_UNLOCK(player);
693 __mmplayer_gapless_play_thread(gpointer data)
695 mmplayer_t *player = (mmplayer_t *)data;
696 mmplayer_gst_element_t *mainbin = NULL;
698 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
700 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
701 while (!player->gapless_play_thread_exit) {
702 LOGD("gapless play thread started. waiting for signal.");
703 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
705 LOGD("reconfigure pipeline for gapless play.");
707 if (player->gapless_play_thread_exit) {
708 _mmplayer_set_reconfigure_state(player, FALSE);
709 LOGD("exiting gapless play thread");
713 mainbin = player->pipeline->mainbin;
715 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
716 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
717 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
718 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
719 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
721 /* Initialize Player values */
722 __mmplayer_initialize_gapless_play(player);
724 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
726 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
732 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
734 GSource *source = NULL;
738 source = g_main_context_find_source_by_id(context, source_id);
739 if (source != NULL) {
740 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
741 g_source_destroy(source);
748 _mmplayer_watcher_removed_notify(gpointer data)
750 mmplayer_t *player = (mmplayer_t *)data;
751 MMPLAYER_RETURN_IF_FAIL(player);
753 MMPLAYER_BUS_WATCHER_LOCK(player);
754 player->bus_watcher = 0;
755 MMPLAYER_BUS_WATCHER_SIGNAL(player);
756 MMPLAYER_BUS_WATCHER_UNLOCK(player);
760 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
762 mmplayer_t *player = (mmplayer_t *)hplayer;
765 MMPLAYER_RETURN_IF_FAIL(player);
767 /* disconnecting bus watch */
768 if (player->bus_watcher > 0) {
769 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
770 MMPLAYER_BUS_WATCHER_LOCK(player);
771 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
772 while (player->bus_watcher > 0)
773 MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time);
774 MMPLAYER_BUS_WATCHER_UNLOCK(player);
776 g_mutex_clear(&player->bus_watcher_mutex);
777 g_cond_clear(&player->bus_watcher_cond);
784 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
786 mmplayer_t *player = (mmplayer_t *)hplayer;
787 GstMessage *msg = NULL;
788 GQueue *queue = NULL;
791 MMPLAYER_RETURN_IF_FAIL(player);
793 /* destroy the gst bus msg thread */
794 if (player->bus_msg_thread) {
795 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
796 player->bus_msg_thread_exit = TRUE;
797 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
798 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
800 LOGD("gst bus msg thread exit.");
801 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
802 player->bus_msg_thread = NULL;
804 g_mutex_clear(&player->bus_msg_thread_mutex);
805 g_cond_clear(&player->bus_msg_thread_cond);
808 g_mutex_lock(&player->bus_msg_q_lock);
809 queue = player->bus_msg_q;
810 while (!g_queue_is_empty(queue)) {
811 msg = (GstMessage *)g_queue_pop_head(queue);
816 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
817 gst_message_unref(msg);
819 g_mutex_unlock(&player->bus_msg_q_lock);
825 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
827 GstElement *parent = NULL;
829 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
830 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
833 MMPLAYER_FSINK_LOCK(player);
835 /* get parent of fakesink */
836 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
838 LOGD("fakesink already removed");
842 gst_element_set_locked_state(fakesink->gst, TRUE);
844 /* setting the state to NULL never returns async
845 * so no need to wait for completion of state transiton
847 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
848 LOGE("fakesink state change failure!");
849 /* FIXIT : should I return here? or try to proceed to next? */
852 /* remove fakesink from it's parent */
853 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
854 LOGE("failed to remove fakesink");
856 gst_object_unref(parent);
861 gst_object_unref(parent);
863 LOGD("state-holder removed");
865 gst_element_set_locked_state(fakesink->gst, FALSE);
867 MMPLAYER_FSINK_UNLOCK(player);
872 gst_element_set_locked_state(fakesink->gst, FALSE);
874 MMPLAYER_FSINK_UNLOCK(player);
878 static GstPadProbeReturn
879 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
881 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
882 return GST_PAD_PROBE_OK;
886 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
888 gint64 stop_running_time = 0;
889 gint64 position_running_time = 0;
893 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
894 if ((player->gapless.update_segment[idx] == TRUE) ||
895 !(player->track[idx].event_probe_id)) {
897 LOGW("[%d] skip", idx);
902 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
904 gst_segment_to_running_time(&player->gapless.segment[idx],
905 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
906 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
908 gst_segment_to_running_time(&player->gapless.segment[idx],
909 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
911 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
913 gst_segment_to_running_time(&player->gapless.segment[idx],
914 GST_FORMAT_TIME, player->duration);
917 position_running_time =
918 gst_segment_to_running_time(&player->gapless.segment[idx],
919 GST_FORMAT_TIME, player->gapless.segment[idx].position);
921 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
922 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
924 GST_TIME_ARGS(stop_running_time),
925 GST_TIME_ARGS(position_running_time),
926 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
927 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
929 position_running_time = MAX(position_running_time, stop_running_time);
930 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
931 GST_FORMAT_TIME, player->gapless.segment[idx].start);
932 position_running_time = MAX(0, position_running_time);
933 position = MAX(position, position_running_time);
937 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
938 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
939 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
941 player->gapless.start_time[stream_type] += position;
947 static GstPadProbeReturn
948 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
950 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
951 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
952 mmplayer_t *player = (mmplayer_t *)data;
953 GstCaps *caps = NULL;
954 GstStructure *str = NULL;
955 const gchar *name = NULL;
956 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
957 gboolean caps_ret = TRUE;
959 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
960 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
961 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
962 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
963 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
966 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
970 if (strstr(name, "audio")) {
971 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
972 } else if (strstr(name, "video")) {
973 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
975 /* text track is not supportable */
976 LOGE("invalid name %s", name);
980 switch (GST_EVENT_TYPE(event)) {
983 /* in case of gapless, drop eos event not to send it to sink */
984 if (player->gapless.reconfigure && !player->msg_posted) {
985 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
986 ret = GST_PAD_PROBE_DROP;
990 case GST_EVENT_STREAM_START:
992 __mmplayer_gst_selector_update_start_time(player, stream_type);
995 case GST_EVENT_FLUSH_STOP:
997 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
998 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
999 player->gapless.start_time[stream_type] = 0;
1002 case GST_EVENT_SEGMENT:
1007 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1008 gst_event_copy_segment(event, &segment);
1010 if (segment.format != GST_FORMAT_TIME)
1013 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1014 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1015 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1016 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1017 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1018 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1020 /* keep the all the segment ev to cover the seeking */
1021 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1022 player->gapless.update_segment[stream_type] = TRUE;
1024 if (!player->gapless.running)
1027 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1029 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1031 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1032 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1033 gst_event_unref(event);
1034 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1040 gdouble proportion = 0.0;
1041 GstClockTimeDiff diff = 0;
1042 GstClockTime timestamp = 0;
1043 gint64 running_time_diff = -1;
1044 GstQOSType type = 0;
1045 GstEvent *tmpev = NULL;
1047 running_time_diff = player->gapless.segment[stream_type].base;
1049 if (running_time_diff <= 0) /* don't need to adjust */
1052 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1053 gst_event_unref(event);
1055 if (timestamp < running_time_diff) {
1056 LOGW("QOS event from previous group");
1057 ret = GST_PAD_PROBE_DROP;
1062 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1063 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1064 stream_type, GST_TIME_ARGS(timestamp),
1065 GST_TIME_ARGS(running_time_diff),
1066 GST_TIME_ARGS(timestamp - running_time_diff));
1069 timestamp -= running_time_diff;
1071 /* That case is invalid for QoS events */
1072 if (diff < 0 && -diff > timestamp) {
1073 LOGW("QOS event from previous group");
1074 ret = GST_PAD_PROBE_DROP;
1078 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1079 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1089 gst_caps_unref(caps);
1093 /* create fakesink for audio or video path witout audiobin or videobin */
1095 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1097 GstElement *pipeline = NULL;
1098 GstElement *fakesink = NULL;
1099 GstPad *sinkpad = NULL;
1102 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1104 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1107 fakesink = gst_element_factory_make("fakesink", NULL);
1108 if (fakesink == NULL) {
1109 LOGE("failed to create fakesink");
1113 /* store it as it's sink element */
1114 __mmplayer_add_sink(player, fakesink, FALSE);
1116 gst_bin_add(GST_BIN(pipeline), fakesink);
1119 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1121 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1123 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1124 LOGE("failed to link fakesink");
1125 gst_object_unref(GST_OBJECT(fakesink));
1129 if (strstr(name, "video")) {
1130 if (player->v_stream_caps) {
1131 gst_caps_unref(player->v_stream_caps);
1132 player->v_stream_caps = NULL;
1134 if (player->ini.set_dump_element_flag)
1135 __mmplayer_add_dump_buffer_probe(player, fakesink);
1138 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1139 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1143 gst_object_unref(GST_OBJECT(sinkpad));
1150 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1152 GstElement *pipeline = NULL;
1153 GstElement *concat = NULL;
1156 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1158 concat = gst_element_factory_make("concat", NULL);
1160 LOGE("failed to create concat");
1164 LOGD("Create concat [%d] element", elem_idx);
1166 player->pipeline->mainbin[elem_idx].id = elem_idx;
1167 player->pipeline->mainbin[elem_idx].gst = concat;
1169 gst_element_set_state(concat, GST_STATE_PAUSED);
1171 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1172 gst_bin_add(GST_BIN(pipeline), concat);
1179 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1181 GstElement *pipeline = NULL;
1182 GstElement *selector = NULL;
1183 GstPad *srcpad = NULL;
1186 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1188 selector = gst_element_factory_make("input-selector", NULL);
1190 LOGE("failed to create input-selector");
1193 g_object_set(selector, "sync-streams", TRUE, NULL);
1195 player->pipeline->mainbin[elem_idx].id = elem_idx;
1196 player->pipeline->mainbin[elem_idx].gst = selector;
1198 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1200 srcpad = gst_element_get_static_pad(selector, "src");
1202 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1203 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1204 __mmplayer_gst_selector_blocked, NULL, NULL);
1205 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1206 __mmplayer_gst_selector_event_probe, player, NULL);
1208 gst_element_set_state(selector, GST_STATE_PAUSED);
1210 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1211 gst_bin_add(GST_BIN(pipeline), selector);
1213 gst_object_unref(GST_OBJECT(srcpad));
1220 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1222 mmplayer_t *player = (mmplayer_t *)data;
1223 GstElement *combiner = NULL;
1224 GstCaps *caps = NULL;
1225 GstStructure *str = NULL;
1226 const gchar *name = NULL;
1227 GstPad *sinkpad = NULL;
1228 gboolean first_track = FALSE;
1229 gboolean caps_ret = TRUE;
1231 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1232 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1235 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1236 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1238 LOGD("pad-added signal handling");
1240 /* get mimetype from caps */
1241 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1245 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1247 LOGD("detected mimetype : %s", name);
1250 if (strstr(name, "video")) {
1252 gchar *caps_str = NULL;
1254 caps_str = gst_caps_to_string(caps);
1255 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1256 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1257 player->set_mode.video_zc = true;
1259 MMPLAYER_FREEIF(caps_str);
1261 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1262 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1264 LOGD("surface type : %d", stype);
1266 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1267 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1271 /* in case of exporting video frame, it requires the 360 video filter.
1272 * it will be handled in _no_more_pads(). */
1273 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1274 __mmplayer_gst_make_fakesink(player, pad, name);
1278 if (MMPLAYER_USE_DECODEBIN(player)) {
1279 LOGD("video selector is required");
1280 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1282 LOGD("video concat is required");
1283 elem_idx = MMPLAYER_M_V_CONCAT;
1285 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1286 } else if (strstr(name, "audio")) {
1287 gint samplerate = 0;
1290 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1291 if (player->build_audio_offload)
1292 player->no_more_pad = TRUE; /* remove state holder */
1293 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1297 gst_structure_get_int(str, "rate", &samplerate);
1298 gst_structure_get_int(str, "channels", &channels);
1300 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1301 __mmplayer_gst_make_fakesink(player, pad, name);
1304 if (MMPLAYER_USE_DECODEBIN(player)) {
1305 LOGD("audio selector is required");
1306 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1308 LOGD("audio concat is required");
1309 elem_idx = MMPLAYER_M_A_CONCAT;
1311 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1313 } else if (strstr(name, "text")) {
1314 if (MMPLAYER_USE_DECODEBIN(player)) {
1315 LOGD("text selector is required");
1316 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1318 LOGD("text concat is required");
1319 elem_idx = MMPLAYER_M_T_CONCAT;
1321 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1323 LOGE("invalid caps info");
1327 /* check selector and create it */
1328 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1329 if (MMPLAYER_USE_DECODEBIN(player))
1330 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1332 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1338 LOGD("Combiner element is already created.");
1342 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1344 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1346 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1347 LOGE("failed to link combiner");
1348 gst_object_unref(GST_OBJECT(combiner));
1353 if (MMPLAYER_USE_DECODEBIN(player)) {
1354 LOGD("this track will be activated");
1355 g_object_set(combiner, "active-pad", sinkpad, NULL);
1359 if (MMPLAYER_USE_DECODEBIN(player)) {
1360 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1362 /* apply the text track information */
1363 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1364 mm_player_set_attribute((MMHandleType)player, NULL,
1365 "content_text_track_num", player->track[stream_type].total_track_num,
1366 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1367 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1374 gst_caps_unref(caps);
1377 gst_object_unref(GST_OBJECT(sinkpad));
1385 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1387 GstPad *srcpad = NULL;
1390 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1392 LOGD("type %d", type);
1395 LOGD("there is no %d track", type);
1399 srcpad = gst_element_get_static_pad(combiner, "src");
1401 LOGE("failed to get srcpad from combiner");
1405 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1407 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1409 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1410 if (player->track[type].block_id) {
1411 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1412 player->track[type].block_id = 0;
1416 gst_object_unref(GST_OBJECT(srcpad));
1425 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1427 gint active_index = 0;
1430 MMPLAYER_RETURN_IF_FAIL(player);
1432 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1434 /* change track to active pad */
1435 active_index = player->track[type].active_track_index;
1436 if ((active_index != DEFAULT_TRACK) &&
1437 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1438 LOGW("failed to change %d type track to %d", type, active_index);
1439 player->track[type].active_track_index = DEFAULT_TRACK;
1443 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1444 mm_player_set_attribute((MMHandleType)player, NULL,
1445 "content_text_track_num", player->track[type].total_track_num,
1446 "current_text_track_index", player->track[type].active_track_index, NULL);
1453 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1456 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1458 if (!audio_selector) {
1459 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1461 /* in case the source is changed, output can be changed. */
1462 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1463 LOGD("remove previous audiobin if it exist");
1465 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1466 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1468 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1469 MMPLAYER_FREEIF(player->pipeline->audiobin);
1472 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1473 _mmplayer_pipeline_complete(NULL, player);
1478 /* apply the audio track information */
1479 if (MMPLAYER_USE_DECODEBIN(player))
1480 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1482 /* create audio sink path */
1483 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1484 LOGE("failed to create audio sink path");
1493 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1496 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1498 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1499 LOGD("text path is not supproted");
1503 /* apply the text track information */
1504 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1506 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1507 player->has_closed_caption = TRUE;
1509 /* create text decode path */
1510 player->no_more_pad = TRUE;
1512 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1513 LOGE("failed to create text sink path");
1522 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1524 gint64 dur_bytes = 0L;
1527 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1528 player->pipeline->mainbin && player->streamer, FALSE);
1530 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1531 LOGE("fail to get duration.");
1533 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1534 * use file information was already set on Q2 when it was created. */
1535 _mm_player_streaming_set_queue2(player->streamer,
1536 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1537 TRUE, /* use_buffering */
1538 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1539 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1546 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1548 mmplayer_t *player = NULL;
1549 GstElement *video_selector = NULL;
1550 GstElement *audio_selector = NULL;
1551 GstElement *text_selector = NULL;
1554 player = (mmplayer_t *)data;
1556 LOGD("no-more-pad signal handling");
1558 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1559 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1560 LOGW("player is shutting down");
1564 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1565 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1566 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1567 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1568 LOGE("failed to set queue2 buffering");
1573 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1574 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1575 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1577 if (!video_selector && !audio_selector && !text_selector) {
1578 LOGW("there is no selector");
1579 player->no_more_pad = TRUE;
1583 /* create video path followed by video-select */
1584 if (video_selector && !audio_selector && !text_selector)
1585 player->no_more_pad = TRUE;
1587 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1590 /* create audio path followed by audio-select */
1591 if (audio_selector && !text_selector)
1592 player->no_more_pad = TRUE;
1594 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1597 /* create text path followed by text-select */
1598 __mmplayer_create_text_sink_path(player, text_selector);
1601 _mmplayer_set_reconfigure_state(player, FALSE);
1606 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1608 gboolean ret = FALSE;
1609 GstElement *pipeline = NULL;
1610 GstPad *sinkpad = NULL;
1613 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1614 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1616 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1618 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1620 LOGE("failed to get pad from sinkbin");
1626 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1627 LOGE("failed to link sinkbin for reusing");
1628 goto EXIT; /* exit either pass or fail */
1632 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1633 LOGE("failed to set state(READY) to sinkbin");
1638 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1639 LOGE("failed to add sinkbin to pipeline");
1644 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1645 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1650 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1651 LOGE("failed to set state(PAUSED) to sinkbin");
1660 gst_object_unref(GST_OBJECT(sinkpad));
1668 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1670 mmplayer_t *player = NULL;
1671 GstCaps *caps = NULL;
1672 gchar *caps_str = NULL;
1673 GstStructure *str = NULL;
1674 const gchar *name = NULL;
1675 GstElement *sinkbin = NULL;
1676 gboolean reusing = FALSE;
1677 gboolean caps_ret = TRUE;
1678 gchar *sink_pad_name = "sink";
1681 player = (mmplayer_t *)data;
1684 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1685 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1686 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1688 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1692 caps = gst_caps_ref(ref_caps);
1695 caps_str = gst_caps_to_string(caps);
1697 LOGD("detected mimetype : %s", name);
1699 if (strstr(name, "audio")) {
1700 if (player->pipeline->audiobin == NULL) {
1701 const gchar *audio_format = gst_structure_get_string(str, "format");
1703 LOGD("original audio format %s", audio_format);
1704 mm_player_set_attribute((MMHandleType)player, NULL,
1705 "content_audio_format", audio_format, strlen(audio_format), NULL);
1708 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1709 LOGE("failed to create audiobin. continuing without audio");
1713 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1714 LOGD("creating audiobin success");
1717 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1718 LOGD("reusing audiobin");
1719 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1721 } else if (strstr(name, "video")) {
1722 /* 1. zero copy is updated at _decode_pad_added()
1723 * 2. NULL surface type is handled in _decode_pad_added() */
1724 LOGD("zero copy %d", player->set_mode.video_zc);
1725 if (player->pipeline->videobin == NULL) {
1726 int surface_type = 0;
1727 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1728 LOGD("display_surface_type (%d)", surface_type);
1730 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1731 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1732 LOGE("failed to acquire video overlay resource");
1736 player->interrupted_by_resource = FALSE;
1738 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1739 LOGE("failed to create videobin. continuing without video");
1743 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1744 LOGD("creating videosink bin success");
1747 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1748 LOGD("re-using videobin");
1749 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1751 } else if (strstr(name, "text")) {
1752 if (player->pipeline->textbin == NULL) {
1753 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1754 LOGE("failed to create text sink bin. continuing without text");
1758 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1759 player->textsink_linked = 1;
1760 LOGD("creating textsink bin success");
1762 if (!player->textsink_linked) {
1763 LOGD("re-using textbin");
1765 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1766 player->textsink_linked = 1;
1768 /* linked textbin exist which means that the external subtitle path exist already */
1769 LOGW("ignoring internal subtutle since external subtitle is available");
1772 sink_pad_name = "text_sink";
1774 LOGW("unknown mime type %s, ignoring it", name);
1778 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1781 LOGD("[handle: %p] success to create and link sink bin", player);
1783 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1784 * streaming task. if the task blocked, then buffer will not flow to the next element
1785 *(autoplugging element). so this is special hack for streaming. please try to remove it
1787 /* dec stream count. we can remove fakesink if it's zero */
1788 if (player->num_dynamic_pad)
1789 player->num_dynamic_pad--;
1791 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1793 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1794 _mmplayer_pipeline_complete(NULL, player);
1798 MMPLAYER_FREEIF(caps_str);
1801 gst_caps_unref(caps);
1807 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1809 int required_angle = 0; /* Angle required for straight view */
1810 int rotation_angle = 0;
1812 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1813 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1815 /* Counter clockwise */
1816 switch (orientation) {
1821 required_angle = 270;
1824 required_angle = 180;
1827 required_angle = 90;
1831 rotation_angle = display_angle + required_angle;
1832 if (rotation_angle >= 360)
1833 rotation_angle -= 360;
1835 /* chech if supported or not */
1836 if (rotation_angle % 90) {
1837 LOGD("not supported rotation angle = %d", rotation_angle);
1841 switch (rotation_angle) {
1843 *value = MM_DISPLAY_ROTATION_NONE;
1846 *value = MM_DISPLAY_ROTATION_90;
1849 *value = MM_DISPLAY_ROTATION_180;
1852 *value = MM_DISPLAY_ROTATION_270;
1856 LOGD("setting rotation property value : %d", *value);
1862 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1864 int display_rotation = 0;
1865 gchar *org_orient = NULL;
1866 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1869 LOGE("cannot get content attribute");
1870 return MM_ERROR_PLAYER_INTERNAL;
1873 if (display_angle) {
1874 /* update user roation */
1875 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1877 /* Counter clockwise */
1878 switch (display_rotation) {
1879 case MM_DISPLAY_ROTATION_NONE:
1882 case MM_DISPLAY_ROTATION_90:
1883 *display_angle = 90;
1885 case MM_DISPLAY_ROTATION_180:
1886 *display_angle = 180;
1888 case MM_DISPLAY_ROTATION_270:
1889 *display_angle = 270;
1892 LOGW("wrong angle type : %d", display_rotation);
1895 LOGD("check user angle: %d", *display_angle);
1899 /* Counter clockwise */
1900 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1903 if (!strcmp(org_orient, "rotate-90"))
1905 else if (!strcmp(org_orient, "rotate-180"))
1907 else if (!strcmp(org_orient, "rotate-270"))
1910 LOGD("original rotation is %s", org_orient);
1912 LOGD("content_video_orientation get fail");
1915 LOGD("check orientation: %d", *orientation);
1918 return MM_ERROR_NONE;
1921 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1923 int rotation_value = 0;
1924 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1925 int display_angle = 0;
1928 /* check video sinkbin is created */
1929 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1932 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1934 /* get rotation value to set */
1935 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1936 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1937 LOGD("set video param : rotate %d", rotation_value);
1940 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1942 MMHandleType attrs = 0;
1946 /* check video sinkbin is created */
1947 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1950 attrs = MMPLAYER_GET_ATTRS(player);
1951 MMPLAYER_RETURN_IF_FAIL(attrs);
1953 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1954 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1955 LOGD("set video param : visible %d", visible);
1958 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1960 MMHandleType attrs = 0;
1961 int display_method = 0;
1964 /* check video sinkbin is created */
1965 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1968 attrs = MMPLAYER_GET_ATTRS(player);
1969 MMPLAYER_RETURN_IF_FAIL(attrs);
1971 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
1972 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
1973 LOGD("set video param : method %d", display_method);
1976 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
1978 MMHandleType attrs = 0;
1982 /* check video sinkbin is created */
1983 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1986 attrs = MMPLAYER_GET_ATTRS(player);
1987 MMPLAYER_RETURN_IF_FAIL(attrs);
1989 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
1990 MMPLAYER_RETURN_IF_FAIL(handle);
1992 gst_video_overlay_set_video_roi_area(
1993 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
1994 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1995 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
1996 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
1999 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2001 MMHandleType attrs = 0;
2006 int win_roi_width = 0;
2007 int win_roi_height = 0;
2010 /* check video sinkbin is created */
2011 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2014 attrs = MMPLAYER_GET_ATTRS(player);
2015 MMPLAYER_RETURN_IF_FAIL(attrs);
2017 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2018 MMPLAYER_RETURN_IF_FAIL(handle);
2020 /* It should be set after setting window */
2021 mm_attrs_multiple_get(attrs, NULL,
2022 "display_win_roi_x", &win_roi_x,
2023 "display_win_roi_y", &win_roi_y,
2024 "display_win_roi_width", &win_roi_width,
2025 "display_win_roi_height", &win_roi_height, NULL);
2027 /* After setting window handle, set display roi area */
2028 gst_video_overlay_set_display_roi_area(
2029 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2030 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2031 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2032 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2035 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2037 MMHandleType attrs = 0;
2040 /* check video sinkbin is created */
2041 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2044 attrs = MMPLAYER_GET_ATTRS(player);
2045 MMPLAYER_RETURN_IF_FAIL(attrs);
2047 /* common case if using overlay surface */
2048 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2049 MMPLAYER_RETURN_IF_FAIL(handle);
2051 /* default is using wl_surface_id */
2052 LOGD("set video param : wl_surface_id %d", handle);
2053 gst_video_overlay_set_wl_window_wl_surface_id(
2054 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2059 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2061 gboolean update_all_param = FALSE;
2065 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2066 LOGW("videosink is not ready yet");
2067 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2070 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2071 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2072 return MM_ERROR_PLAYER_INTERNAL;
2075 LOGD("param_name : %s", param_name);
2076 if (!g_strcmp0(param_name, "update_all_param"))
2077 update_all_param = TRUE;
2079 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2080 __mmplayer_video_param_set_display_overlay(player);
2081 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2082 __mmplayer_video_param_set_display_method(player);
2083 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2084 __mmplayer_video_param_set_display_visible(player);
2085 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2086 __mmplayer_video_param_set_display_rotation(player);
2087 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2088 __mmplayer_video_param_set_roi_area(player);
2089 if (update_all_param)
2090 __mmplayer_video_param_set_video_roi_area(player);
2094 return MM_ERROR_NONE;
2098 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2100 gboolean disable_overlay = FALSE;
2101 mmplayer_t *player = (mmplayer_t *)hplayer;
2104 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2105 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2106 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2107 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2109 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2110 LOGW("Display control is not supported");
2111 return MM_ERROR_PLAYER_INTERNAL;
2114 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2116 if (audio_only == (bool)disable_overlay) {
2117 LOGE("It's the same with current setting: (%d)", audio_only);
2118 return MM_ERROR_NONE;
2122 LOGE("disable overlay");
2123 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2125 /* release overlay resource */
2126 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2127 LOGE("failed to release overlay resource");
2131 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2132 LOGE("failed to acquire video overlay resource");
2135 player->interrupted_by_resource = FALSE;
2137 LOGD("enable overlay");
2138 __mmplayer_video_param_set_display_overlay(player);
2139 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2144 return MM_ERROR_NONE;
2148 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2150 mmplayer_t *player = (mmplayer_t *)hplayer;
2151 gboolean disable_overlay = FALSE;
2155 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2156 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2157 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2158 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2159 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2161 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2162 LOGW("Display control is not supported");
2163 return MM_ERROR_PLAYER_INTERNAL;
2166 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2168 *paudio_only = (bool)disable_overlay;
2170 LOGD("audio_only : %d", *paudio_only);
2174 return MM_ERROR_NONE;
2178 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2180 GList *bucket = element_bucket;
2181 mmplayer_gst_element_t *element = NULL;
2182 mmplayer_gst_element_t *prv_element = NULL;
2183 GstElement *tee_element = NULL;
2184 gint successful_link_count = 0;
2188 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2190 prv_element = (mmplayer_gst_element_t *)bucket->data;
2191 bucket = bucket->next;
2193 for (; bucket; bucket = bucket->next) {
2194 element = (mmplayer_gst_element_t *)bucket->data;
2196 if (element && element->gst) {
2197 if (prv_element && prv_element->gst) {
2198 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2200 prv_element->gst = tee_element;
2202 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2203 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2204 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2208 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2209 LOGD("linking [%s] to [%s] success",
2210 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2211 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2212 successful_link_count++;
2213 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2214 LOGD("keep audio-tee element for next audio pipeline branch");
2215 tee_element = prv_element->gst;
2218 LOGD("linking [%s] to [%s] failed",
2219 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2220 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2226 prv_element = element;
2231 return successful_link_count;
2235 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2237 GList *bucket = element_bucket;
2238 mmplayer_gst_element_t *element = NULL;
2239 int successful_add_count = 0;
2243 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2244 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2246 for (; bucket; bucket = bucket->next) {
2247 element = (mmplayer_gst_element_t *)bucket->data;
2249 if (element && element->gst) {
2250 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2251 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2252 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2253 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2256 successful_add_count++;
2262 return successful_add_count;
2266 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2268 mmplayer_t *player = (mmplayer_t *)data;
2269 GstCaps *caps = NULL;
2270 GstStructure *str = NULL;
2272 gboolean caps_ret = TRUE;
2276 MMPLAYER_RETURN_IF_FAIL(pad);
2277 MMPLAYER_RETURN_IF_FAIL(unused);
2278 MMPLAYER_RETURN_IF_FAIL(data);
2280 caps = gst_pad_get_current_caps(pad);
2284 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2288 LOGD("name = %s", name);
2290 if (strstr(name, "audio")) {
2291 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2293 if (player->audio_stream_changed_cb) {
2294 LOGE("call the audio stream changed cb");
2295 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2297 } else if (strstr(name, "video")) {
2298 if ((name = gst_structure_get_string(str, "format")))
2299 player->set_mode.video_zc = name[0] == 'S';
2301 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2302 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2304 LOGW("invalid caps info");
2309 gst_caps_unref(caps);
2317 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2322 MMPLAYER_RETURN_IF_FAIL(player);
2324 if (player->audio_stream_buff_list) {
2325 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2326 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2329 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2330 __mmplayer_audio_stream_send_data(player, tmp);
2332 MMPLAYER_FREEIF(tmp->pcm_data);
2333 MMPLAYER_FREEIF(tmp);
2336 g_list_free(player->audio_stream_buff_list);
2337 player->audio_stream_buff_list = NULL;
2344 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2346 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2349 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2351 audio_stream.bitrate = a_buffer->bitrate;
2352 audio_stream.channel = a_buffer->channel;
2353 audio_stream.channel_mask = a_buffer->channel_mask;
2354 audio_stream.data_size = a_buffer->data_size;
2355 audio_stream.data = a_buffer->pcm_data;
2356 audio_stream.pcm_format = a_buffer->pcm_format;
2358 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2360 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2366 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2368 mmplayer_t *player = (mmplayer_t *)data;
2369 const gchar *pcm_format = NULL;
2372 guint64 channel_mask = 0;
2373 void *a_data = NULL;
2375 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2376 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2380 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2382 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2383 a_data = mapinfo.data;
2384 a_size = mapinfo.size;
2386 GstCaps *caps = gst_pad_get_current_caps(pad);
2387 GstStructure *structure = gst_caps_get_structure(caps, 0);
2389 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2391 pcm_format = gst_structure_get_string(structure, "format");
2392 gst_structure_get_int(structure, "rate", &rate);
2393 gst_structure_get_int(structure, "channels", &channel);
2394 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2395 gst_caps_unref(GST_CAPS(caps));
2397 /* In case of the sync is false, use buffer list. *
2398 * The num of buffer list depends on the num of audio channels */
2399 if (player->audio_stream_buff_list) {
2400 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2401 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2403 if (channel_mask == tmp->channel_mask) {
2405 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2407 if (tmp->data_size + a_size < tmp->buff_size) {
2408 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2409 tmp->data_size += a_size;
2411 /* send data to client */
2412 __mmplayer_audio_stream_send_data(player, tmp);
2414 if (a_size > tmp->buff_size) {
2415 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2416 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2417 if (tmp->pcm_data == NULL) {
2418 LOGE("failed to realloc data.");
2421 tmp->buff_size = a_size;
2423 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2424 memcpy(tmp->pcm_data, a_data, a_size);
2425 tmp->data_size = a_size;
2430 LOGE("data is empty in list.");
2436 /* create new audio stream data for newly found audio channel */
2437 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2438 if (a_buffer == NULL) {
2439 LOGE("failed to alloc data.");
2442 a_buffer->bitrate = rate;
2443 a_buffer->channel = channel;
2444 a_buffer->channel_mask = channel_mask;
2445 a_buffer->data_size = a_size;
2446 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2448 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2449 /* If sync is FALSE, use buffer list to reduce the IPC. */
2450 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2451 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2452 if (a_buffer->pcm_data == NULL) {
2453 LOGE("failed to alloc data.");
2454 MMPLAYER_FREEIF(a_buffer);
2457 memcpy(a_buffer->pcm_data, a_data, a_size);
2459 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2461 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2463 /* If sync is TRUE, send data directly. */
2464 a_buffer->pcm_data = a_data;
2465 __mmplayer_audio_stream_send_data(player, a_buffer);
2466 MMPLAYER_FREEIF(a_buffer);
2470 gst_buffer_unmap(buffer, &mapinfo);
2475 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2477 mmplayer_t *player = (mmplayer_t *)data;
2478 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2479 GstPad *sinkpad = NULL;
2480 GstElement *queue = NULL, *sink = NULL;
2483 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2485 queue = gst_element_factory_make("queue", NULL);
2486 if (queue == NULL) {
2487 LOGD("fail make queue");
2491 sink = gst_element_factory_make("fakesink", NULL);
2493 LOGD("fail make fakesink");
2497 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2499 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2500 LOGW("failed to link queue & sink");
2504 sinkpad = gst_element_get_static_pad(queue, "sink");
2506 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2507 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2511 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2513 gst_object_unref(sinkpad);
2514 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2515 g_object_set(sink, "sync", TRUE, NULL);
2516 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2518 /* keep the first sink reference only */
2519 if (!audiobin[MMPLAYER_A_SINK].gst) {
2520 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2521 audiobin[MMPLAYER_A_SINK].gst = sink;
2525 _mmplayer_add_signal_connection(player,
2527 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2529 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2532 __mmplayer_add_sink(player, sink, FALSE);
2534 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2535 LOGE("failed to sync state");
2539 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2540 LOGE("failed to sync state");
2548 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2550 gst_object_unref(GST_OBJECT(queue));
2554 gst_object_unref(GST_OBJECT(sink));
2558 gst_object_unref(GST_OBJECT(sinkpad));
2566 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2568 mmplayer_t *player = (mmplayer_t *)data;
2571 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2573 player->no_more_pad = TRUE;
2574 _mmplayer_pipeline_complete(NULL, player);
2581 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2583 #define MAX_PROPS_LEN 128
2584 mmplayer_gst_element_t *audiobin = NULL;
2585 gint latency_mode = 0;
2586 gchar *stream_type = NULL;
2587 gchar *latency = NULL;
2589 gchar stream_props[MAX_PROPS_LEN] = {0,};
2590 GstStructure *props = NULL;
2593 * It should be set after player creation through attribute.
2594 * But, it can not be changed during playing.
2597 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2599 audiobin = player->pipeline->audiobin;
2601 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2602 if (player->sound.mute) {
2603 LOGD("mute enabled");
2604 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2607 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2608 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2611 snprintf(stream_props, sizeof(stream_props) - 1,
2612 "props,application.process.id.origin=%d", player->client_pid);
2614 snprintf(stream_props, sizeof(stream_props) - 1,
2615 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2616 stream_type, stream_id, player->client_pid);
2618 props = gst_structure_from_string(stream_props, NULL);
2619 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2620 LOGI("props result[%s].", stream_props);
2621 gst_structure_free(props);
2623 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2625 switch (latency_mode) {
2626 case AUDIO_LATENCY_MODE_LOW:
2627 latency = g_strdup("low");
2629 case AUDIO_LATENCY_MODE_MID:
2630 latency = g_strdup("mid");
2632 case AUDIO_LATENCY_MODE_HIGH:
2633 latency = g_strdup("high");
2636 latency = g_strdup("mid");
2640 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2642 LOGD("audiosink property - latency=%s", latency);
2644 MMPLAYER_FREEIF(latency);
2650 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2652 mmplayer_gst_element_t *audiobin = NULL;
2655 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2656 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2658 audiobin = player->pipeline->audiobin;
2660 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2661 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2662 LOGE("failed to create media stream info");
2663 return MM_ERROR_PLAYER_INTERNAL;
2666 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2668 if (player->video360_yaw_radians <= M_PI &&
2669 player->video360_yaw_radians >= -M_PI &&
2670 player->video360_pitch_radians <= M_PI_2 &&
2671 player->video360_pitch_radians >= -M_PI_2) {
2672 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2673 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2674 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2675 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2676 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2677 "source-orientation-y", player->video360_metadata.init_view_heading,
2678 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2682 return MM_ERROR_NONE;
2686 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2688 mmplayer_gst_element_t *audiobin = NULL;
2689 GstPad *sink_pad = NULL;
2690 GstCaps *acaps = NULL;
2692 int pitch_control = 0;
2693 double pitch_value = 1.0;
2696 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2697 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2699 audiobin = player->pipeline->audiobin;
2701 LOGD("make element for normal audio playback");
2703 /* audio bin structure for playback. {} means optional.
2704 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2706 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2707 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2710 /* for pitch control */
2711 mm_attrs_multiple_get(player->attrs, NULL,
2712 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2713 MM_PLAYER_PITCH_VALUE, &pitch_value,
2716 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2717 if (pitch_control && (player->videodec_linked == 0)) {
2718 GstElementFactory *factory;
2720 factory = gst_element_factory_find("pitch");
2722 gst_object_unref(factory);
2725 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2728 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2729 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2731 LOGW("there is no pitch element");
2736 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2738 /* replaygain volume */
2739 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2740 if (player->sound.rg_enable)
2741 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2743 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2746 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2748 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2749 /* currently, only openalsink uses volume element */
2750 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2751 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2753 if (player->sound.mute) {
2754 LOGD("mute enabled");
2755 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2759 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2761 /* audio effect element. if audio effect is enabled */
2762 if ((strcmp(player->ini.audioeffect_element, ""))
2764 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2765 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2767 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2769 if ((!player->bypass_audio_effect)
2770 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2771 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2772 if (!_mmplayer_audio_effect_custom_apply(player))
2773 LOGI("apply audio effect(custom) setting success");
2777 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2778 && (player->set_mode.rich_audio)) {
2779 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2783 /* create audio sink */
2784 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2785 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2786 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2788 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2789 if (player->is_360_feature_enabled &&
2790 player->is_content_spherical &&
2792 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2793 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2794 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2796 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2798 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2800 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2801 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2802 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2803 gst_caps_unref(acaps);
2805 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2807 player->is_openal_plugin_used = TRUE;
2809 if (player->is_360_feature_enabled && player->is_content_spherical)
2810 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2811 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2814 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2815 (player->videodec_linked && player->ini.use_system_clock)) {
2816 LOGD("system clock will be used.");
2817 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2820 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2821 __mmplayer_gst_set_pulsesink_property(player);
2822 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2823 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2828 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2829 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2831 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2832 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2833 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2834 gst_object_unref(GST_OBJECT(sink_pad));
2836 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2839 return MM_ERROR_NONE;
2841 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2843 return MM_ERROR_PLAYER_INTERNAL;
2847 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2849 mmplayer_gst_element_t *audiobin = NULL;
2850 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2852 gchar *dst_format = NULL;
2854 int dst_samplerate = 0;
2855 int dst_channels = 0;
2856 GstCaps *caps = NULL;
2857 char *caps_str = NULL;
2860 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2861 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2863 audiobin = player->pipeline->audiobin;
2865 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2867 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2869 [case 1] extract interleave audio pcm without playback
2870 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2871 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2873 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2875 [case 2] deinterleave for each channel without playback
2876 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2877 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2879 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2880 - fakesink (sync or not)
2883 [case 3] [case 1(sync only)] + playback
2884 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2886 * src - ... - tee - queue1 - playback path
2887 - queue2 - [case1 pipeline with sync]
2889 [case 4] [case 2(sync only)] + playback
2890 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2892 * src - ... - tee - queue1 - playback path
2893 - queue2 - [case2 pipeline with sync]
2897 /* 1. create tee and playback path
2898 'tee' should be added at first to copy the decoded stream
2900 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2901 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2902 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2904 /* tee - path 1 : for playback path */
2905 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2906 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2908 /* tee - path 2 : for extract path */
2909 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2910 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2913 /* if there is tee, 'tee - path 2' is linked here */
2915 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2918 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2920 /* 2. decide the extract pcm format */
2921 mm_attrs_multiple_get(player->attrs, NULL,
2922 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2923 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2924 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2927 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2928 dst_format, dst_len, dst_samplerate, dst_channels);
2930 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2931 mm_attrs_multiple_get(player->attrs, NULL,
2932 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2933 "content_audio_samplerate", &dst_samplerate,
2934 "content_audio_channels", &dst_channels,
2937 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2938 dst_format, dst_len, dst_samplerate, dst_channels);
2940 /* If there is no enough information, set it to platform default value. */
2941 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2942 LOGD("set platform default format");
2943 dst_format = DEFAULT_PCM_OUT_FORMAT;
2945 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2946 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2949 /* 3. create capsfilter */
2950 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2951 caps = gst_caps_new_simple("audio/x-raw",
2952 "format", G_TYPE_STRING, dst_format,
2953 "rate", G_TYPE_INT, dst_samplerate,
2954 "channels", G_TYPE_INT, dst_channels,
2957 caps_str = gst_caps_to_string(caps);
2958 LOGD("new caps : %s", caps_str);
2960 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2963 gst_caps_unref(caps);
2964 MMPLAYER_FREEIF(caps_str);
2966 /* 4-1. create deinterleave to extract pcm for each channel */
2967 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2968 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2969 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
2971 /* audiosink will be added after getting signal for each channel */
2972 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2973 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
2974 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
2975 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
2976 player->no_more_pad = FALSE;
2978 /* 4-2. create fakesink to extract interlevaed pcm */
2979 LOGD("add audio fakesink for interleaved audio");
2980 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
2981 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2982 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
2983 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
2985 _mmplayer_add_signal_connection(player,
2986 G_OBJECT(audiobin[extract_sink_id].gst),
2987 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2989 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2992 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
2996 return MM_ERROR_NONE;
2998 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3000 return MM_ERROR_PLAYER_INTERNAL;
3004 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3006 int ret = MM_ERROR_NONE;
3007 mmplayer_gst_element_t *audiobin = NULL;
3008 GList *element_bucket = NULL;
3011 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3012 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3014 audiobin = player->pipeline->audiobin;
3016 if (player->build_audio_offload) { /* skip all the audio filters */
3017 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3019 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3020 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3021 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3023 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3027 /* FIXME: need to mention the supportable condition at API reference */
3028 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3029 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3031 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3033 if (ret != MM_ERROR_NONE)
3036 LOGD("success to make audio bin element");
3037 *bucket = element_bucket;
3040 return MM_ERROR_NONE;
3043 LOGE("failed to make audio bin element");
3044 g_list_free(element_bucket);
3048 return MM_ERROR_PLAYER_INTERNAL;
3052 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3054 mmplayer_gst_element_t *first_element = NULL;
3055 mmplayer_gst_element_t *audiobin = NULL;
3057 GstPad *ghostpad = NULL;
3058 GList *element_bucket = NULL;
3062 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3065 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3067 LOGE("failed to allocate memory for audiobin");
3068 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3072 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3073 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3074 if (!audiobin[MMPLAYER_A_BIN].gst) {
3075 LOGE("failed to create audiobin");
3080 player->pipeline->audiobin = audiobin;
3082 /* create audio filters and audiosink */
3083 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3086 /* adding created elements to bin */
3087 LOGD("adding created elements to bin");
3088 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3091 /* linking elements in the bucket by added order. */
3092 LOGD("Linking elements in the bucket by added order.");
3093 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3096 /* get first element's sinkpad for creating ghostpad */
3097 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3098 if (!first_element) {
3099 LOGE("failed to get first elem");
3103 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3105 LOGE("failed to get pad from first element of audiobin");
3109 ghostpad = gst_ghost_pad_new("sink", pad);
3111 LOGE("failed to create ghostpad");
3115 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3116 LOGE("failed to add ghostpad to audiobin");
3120 gst_object_unref(pad);
3122 g_list_free(element_bucket);
3125 return MM_ERROR_NONE;
3128 LOGD("ERROR : releasing audiobin");
3131 gst_object_unref(GST_OBJECT(pad));
3134 gst_object_unref(GST_OBJECT(ghostpad));
3137 g_list_free(element_bucket);
3139 /* release element which are not added to bin */
3140 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3141 /* NOTE : skip bin */
3142 if (audiobin[i].gst) {
3143 GstObject *parent = NULL;
3144 parent = gst_element_get_parent(audiobin[i].gst);
3147 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3148 audiobin[i].gst = NULL;
3150 gst_object_unref(GST_OBJECT(parent));
3154 /* release audiobin with it's childs */
3155 if (audiobin[MMPLAYER_A_BIN].gst)
3156 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3158 MMPLAYER_FREEIF(audiobin);
3160 player->pipeline->audiobin = NULL;
3162 return MM_ERROR_PLAYER_INTERNAL;
3166 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3168 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3172 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3174 int ret = MM_ERROR_NONE;
3176 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3177 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3179 MMPLAYER_VIDEO_BO_LOCK(player);
3181 if (player->video_bo_list) {
3182 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3183 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3184 if (tmp && tmp->bo == bo) {
3186 LOGD("release bo %p", bo);
3187 tbm_bo_unref(tmp->bo);
3188 MMPLAYER_VIDEO_BO_UNLOCK(player);
3189 MMPLAYER_VIDEO_BO_SIGNAL(player);
3194 /* hw codec is running or the list was reset for DRC. */
3195 LOGW("there is no bo list.");
3197 MMPLAYER_VIDEO_BO_UNLOCK(player);
3199 LOGW("failed to find bo %p", bo);
3203 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3209 tbm_bo_unref(tmp->bo);
3214 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3217 MMPLAYER_RETURN_IF_FAIL(player);
3219 MMPLAYER_VIDEO_BO_LOCK(player);
3220 if (player->video_bo_list) {
3221 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3222 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3223 player->video_bo_list = NULL;
3225 player->video_bo_size = 0;
3226 MMPLAYER_VIDEO_BO_UNLOCK(player);
3233 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3236 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3237 gboolean ret = TRUE;
3239 /* check DRC, if it is, destroy the prev bo list to create again */
3240 if (player->video_bo_size != size) {
3241 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3242 __mmplayer_video_stream_destroy_bo_list(player);
3243 player->video_bo_size = size;
3246 MMPLAYER_VIDEO_BO_LOCK(player);
3248 if ((!player->video_bo_list) ||
3249 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3251 /* create bo list */
3253 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3255 if (player->video_bo_list) {
3256 /* if bo list did not created all, try it again. */
3257 idx = g_list_length(player->video_bo_list);
3258 LOGD("bo list exist(len: %d)", idx);
3261 for (; idx < player->ini.num_of_video_bo; idx++) {
3262 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3264 LOGE("Fail to alloc bo_info.");
3267 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3269 LOGE("Fail to tbm_bo_alloc.");
3270 MMPLAYER_FREEIF(bo_info);
3273 bo_info->used = FALSE;
3274 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3277 /* update video num buffers */
3278 LOGD("video_num_buffers : %d", idx);
3279 mm_player_set_attribute((MMHandleType)player, NULL,
3280 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3281 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3285 MMPLAYER_VIDEO_BO_UNLOCK(player);
3291 /* get bo from list*/
3292 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3293 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3294 if (tmp && (tmp->used == FALSE)) {
3295 LOGD("found bo %p to use", tmp->bo);
3297 MMPLAYER_VIDEO_BO_UNLOCK(player);
3298 return tbm_bo_ref(tmp->bo);
3302 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3303 MMPLAYER_VIDEO_BO_UNLOCK(player);
3307 if (player->ini.video_bo_timeout <= 0) {
3308 MMPLAYER_VIDEO_BO_WAIT(player);
3310 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3311 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3318 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3320 mmplayer_t *player = (mmplayer_t *)data;
3322 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3324 /* send prerolled pkt */
3325 player->video_stream_prerolled = false;
3327 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3329 /* not to send prerolled pkt again */
3330 player->video_stream_prerolled = true;
3334 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3336 mmplayer_t *player = (mmplayer_t *)data;
3337 mmplayer_video_decoded_data_info_t *stream = NULL;
3338 GstMemory *mem = NULL;
3341 MMPLAYER_RETURN_IF_FAIL(player);
3342 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3344 if (player->video_stream_prerolled) {
3345 player->video_stream_prerolled = false;
3346 LOGD("skip the prerolled pkt not to send it again");
3350 /* clear stream data structure */
3351 stream = __mmplayer_create_stream_from_pad(pad);
3353 LOGE("failed to alloc stream");
3357 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3359 /* set size and timestamp */
3360 mem = gst_buffer_peek_memory(buffer, 0);
3361 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3362 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> mili sec */
3364 /* check zero-copy */
3365 if (player->set_mode.video_zc &&
3366 player->set_mode.video_export &&
3367 gst_is_tizen_memory(mem)) {
3368 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3369 stream->internal_buffer = gst_buffer_ref(buffer);
3370 } else { /* sw codec */
3371 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3374 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3378 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3379 LOGE("failed to send video decoded data.");
3386 LOGE("release video stream resource.");
3387 if (gst_is_tizen_memory(mem)) {
3389 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3391 tbm_bo_unref(stream->bo[i]);
3394 /* unref gst buffer */
3395 if (stream->internal_buffer)
3396 gst_buffer_unref(stream->internal_buffer);
3399 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3401 MMPLAYER_FREEIF(stream);
3406 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3408 mmplayer_gst_element_t *videobin = NULL;
3411 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3413 videobin = player->pipeline->videobin;
3415 /* Set spatial media metadata and/or user settings to the element.
3417 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3418 "projection-type", player->video360_metadata.projection_type, NULL);
3420 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3421 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3423 if (player->video360_metadata.full_pano_width_pixels &&
3424 player->video360_metadata.full_pano_height_pixels &&
3425 player->video360_metadata.cropped_area_image_width &&
3426 player->video360_metadata.cropped_area_image_height) {
3427 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3428 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3429 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3430 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3431 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3432 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3433 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3437 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3438 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3439 "horizontal-fov", player->video360_horizontal_fov,
3440 "vertical-fov", player->video360_vertical_fov, NULL);
3443 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3444 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3445 "zoom", 1.0f / player->video360_zoom, NULL);
3448 if (player->video360_yaw_radians <= M_PI &&
3449 player->video360_yaw_radians >= -M_PI &&
3450 player->video360_pitch_radians <= M_PI_2 &&
3451 player->video360_pitch_radians >= -M_PI_2) {
3452 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3453 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3454 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3455 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3456 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3457 "pose-yaw", player->video360_metadata.init_view_heading,
3458 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3461 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3462 "passthrough", !player->is_video360_enabled, NULL);
3469 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3471 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3472 GList *element_bucket = NULL;
3475 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3477 /* create video360 filter */
3478 if (player->is_360_feature_enabled && player->is_content_spherical) {
3479 LOGD("create video360 element");
3480 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3481 __mmplayer_gst_set_video360_property(player);
3485 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3486 LOGD("skip creating the videoconv and rotator");
3487 return MM_ERROR_NONE;
3490 /* in case of sw codec & overlay surface type, except 360 playback.
3491 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3492 LOGD("create video converter: %s", video_csc);
3493 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3496 *bucket = element_bucket;
3498 return MM_ERROR_NONE;
3500 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3501 g_list_free(element_bucket);
3505 return MM_ERROR_PLAYER_INTERNAL;
3509 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3511 gchar *factory_name = NULL;
3513 switch (surface_type) {
3514 case MM_DISPLAY_SURFACE_OVERLAY:
3515 if (strlen(player->ini.videosink_element_overlay) > 0)
3516 factory_name = player->ini.videosink_element_overlay;
3518 case MM_DISPLAY_SURFACE_REMOTE:
3519 case MM_DISPLAY_SURFACE_NULL:
3520 if (strlen(player->ini.videosink_element_fake) > 0)
3521 factory_name = player->ini.videosink_element_fake;
3524 LOGE("unidentified surface type");
3528 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3529 return factory_name;
3533 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3535 gchar *factory_name = NULL;
3536 mmplayer_gst_element_t *videobin = NULL;
3541 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3543 videobin = player->pipeline->videobin;
3544 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3546 attrs = MMPLAYER_GET_ATTRS(player);
3548 LOGE("cannot get content attribute");
3549 return MM_ERROR_PLAYER_INTERNAL;
3552 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3553 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3554 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3555 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3556 "use-tbm", use_tbm, NULL);
3559 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3560 return MM_ERROR_PLAYER_INTERNAL;
3562 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3565 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3566 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3569 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3571 LOGD("disable last-sample");
3572 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3575 if (player->set_mode.video_export) {
3577 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3578 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3579 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3581 _mmplayer_add_signal_connection(player,
3582 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3583 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3585 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3588 _mmplayer_add_signal_connection(player,
3589 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3590 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3592 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3596 if (videobin[MMPLAYER_V_SINK].gst) {
3597 GstPad *sink_pad = NULL;
3598 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3600 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3601 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3602 gst_object_unref(GST_OBJECT(sink_pad));
3604 LOGE("failed to get sink pad from videosink");
3608 return MM_ERROR_NONE;
3613 * - video overlay surface(arm/x86) : tizenwlsink
3616 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3619 GList *element_bucket = NULL;
3620 mmplayer_gst_element_t *first_element = NULL;
3621 mmplayer_gst_element_t *videobin = NULL;
3622 gchar *videosink_factory_name = NULL;
3625 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3628 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3630 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3632 player->pipeline->videobin = videobin;
3635 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3636 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3637 if (!videobin[MMPLAYER_V_BIN].gst) {
3638 LOGE("failed to create videobin");
3642 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3645 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3646 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3648 /* additional setting for sink plug-in */
3649 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3650 LOGE("failed to set video property");
3654 /* store it as it's sink element */
3655 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3657 /* adding created elements to bin */
3658 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3659 LOGE("failed to add elements");
3663 /* Linking elements in the bucket by added order */
3664 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3665 LOGE("failed to link elements");
3669 /* get first element's sinkpad for creating ghostpad */
3670 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3671 if (!first_element) {
3672 LOGE("failed to get first element from bucket");
3676 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3678 LOGE("failed to get pad from first element");
3682 /* create ghostpad */
3683 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3684 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3685 LOGE("failed to add ghostpad to videobin");
3688 gst_object_unref(pad);
3690 /* done. free allocated variables */
3691 g_list_free(element_bucket);
3695 return MM_ERROR_NONE;
3698 LOGE("ERROR : releasing videobin");
3699 g_list_free(element_bucket);
3702 gst_object_unref(GST_OBJECT(pad));
3704 /* release videobin with it's childs */
3705 if (videobin[MMPLAYER_V_BIN].gst)
3706 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3708 MMPLAYER_FREEIF(videobin);
3709 player->pipeline->videobin = NULL;
3711 return MM_ERROR_PLAYER_INTERNAL;
3715 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3717 GList *element_bucket = NULL;
3718 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3720 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3721 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3722 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3723 "signal-handoffs", FALSE,
3726 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3727 _mmplayer_add_signal_connection(player,
3728 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3729 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3731 G_CALLBACK(__mmplayer_update_subtitle),
3734 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3735 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3737 if (!player->play_subtitle) {
3738 LOGD("add textbin sink as sink element of whole pipeline.");
3739 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3742 /* adding created elements to bin */
3743 LOGD("adding created elements to bin");
3744 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3745 LOGE("failed to add elements");
3749 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3750 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3751 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3753 /* linking elements in the bucket by added order. */
3754 LOGD("Linking elements in the bucket by added order.");
3755 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3756 LOGE("failed to link elements");
3760 /* done. free allocated variables */
3761 g_list_free(element_bucket);
3763 if (textbin[MMPLAYER_T_QUEUE].gst) {
3765 GstPad *ghostpad = NULL;
3767 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3769 LOGE("failed to get sink pad of text queue");
3773 ghostpad = gst_ghost_pad_new("text_sink", pad);
3774 gst_object_unref(pad);
3777 LOGE("failed to create ghostpad of textbin");
3781 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3782 LOGE("failed to add ghostpad to textbin");
3783 gst_object_unref(ghostpad);
3788 return MM_ERROR_NONE;
3791 g_list_free(element_bucket);
3793 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3794 LOGE("remove textbin sink from sink list");
3795 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3798 /* release element at __mmplayer_gst_create_text_sink_bin */
3799 return MM_ERROR_PLAYER_INTERNAL;
3803 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3805 mmplayer_gst_element_t *textbin = NULL;
3806 GList *element_bucket = NULL;
3807 int surface_type = 0;
3812 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3815 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3817 LOGE("failed to allocate memory for textbin");
3818 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3822 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3823 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3824 if (!textbin[MMPLAYER_T_BIN].gst) {
3825 LOGE("failed to create textbin");
3830 player->pipeline->textbin = textbin;
3833 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3834 LOGD("surface type for subtitle : %d", surface_type);
3835 switch (surface_type) {
3836 case MM_DISPLAY_SURFACE_OVERLAY:
3837 case MM_DISPLAY_SURFACE_NULL:
3838 case MM_DISPLAY_SURFACE_REMOTE:
3839 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3840 LOGE("failed to make plain text elements");
3851 return MM_ERROR_NONE;
3855 LOGD("ERROR : releasing textbin");
3857 g_list_free(element_bucket);
3859 /* release signal */
3860 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3862 /* release element which are not added to bin */
3863 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3864 /* NOTE : skip bin */
3865 if (textbin[i].gst) {
3866 GstObject *parent = NULL;
3867 parent = gst_element_get_parent(textbin[i].gst);
3870 gst_object_unref(GST_OBJECT(textbin[i].gst));
3871 textbin[i].gst = NULL;
3873 gst_object_unref(GST_OBJECT(parent));
3878 /* release textbin with it's childs */
3879 if (textbin[MMPLAYER_T_BIN].gst)
3880 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3882 MMPLAYER_FREEIF(textbin);
3883 player->pipeline->textbin = NULL;
3886 return MM_ERROR_PLAYER_INTERNAL;
3890 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3892 mmplayer_gst_element_t *mainbin = NULL;
3893 mmplayer_gst_element_t *textbin = NULL;
3894 MMHandleType attrs = 0;
3895 GstElement *subsrc = NULL;
3896 GstElement *subparse = NULL;
3897 gchar *subtitle_uri = NULL;
3898 const gchar *charset = NULL;
3904 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3906 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3908 mainbin = player->pipeline->mainbin;
3910 attrs = MMPLAYER_GET_ATTRS(player);
3912 LOGE("cannot get content attribute");
3913 return MM_ERROR_PLAYER_INTERNAL;
3916 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3917 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3918 LOGE("subtitle uri is not proper filepath.");
3919 return MM_ERROR_PLAYER_INVALID_URI;
3922 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3923 LOGE("failed to get storage info of subtitle path");
3924 return MM_ERROR_PLAYER_INVALID_URI;
3927 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3929 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3930 player->subtitle_language_list = NULL;
3931 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3933 /* create the subtitle source */
3934 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3936 LOGE("failed to create filesrc element");
3939 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3941 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3942 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3944 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3945 LOGW("failed to add queue");
3946 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3947 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3948 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3953 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3955 LOGE("failed to create subparse element");
3959 charset = _mmplayer_get_charset(subtitle_uri);
3961 LOGD("detected charset is %s", charset);
3962 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3965 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3966 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3968 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3969 LOGW("failed to add subparse");
3970 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
3971 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
3972 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
3976 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
3977 LOGW("failed to link subsrc and subparse");
3981 player->play_subtitle = TRUE;
3982 player->adjust_subtitle_pos = 0;
3984 LOGD("play subtitle using subtitle file");
3986 if (player->pipeline->textbin == NULL) {
3987 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
3988 LOGE("failed to create text sink bin. continuing without text");
3992 textbin = player->pipeline->textbin;
3994 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
3995 LOGW("failed to add textbin");
3997 /* release signal */
3998 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4000 /* release textbin with it's childs */
4001 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4002 MMPLAYER_FREEIF(player->pipeline->textbin);
4003 player->pipeline->textbin = textbin = NULL;
4007 LOGD("link text input selector and textbin ghost pad");
4009 player->textsink_linked = 1;
4010 player->external_text_idx = 0;
4011 LOGI("textsink is linked");
4013 textbin = player->pipeline->textbin;
4014 LOGD("text bin has been created. reuse it.");
4015 player->external_text_idx = 1;
4018 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4019 LOGW("failed to link subparse and textbin");
4023 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4025 LOGE("failed to get sink pad from textsink to probe data");
4029 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4030 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4032 gst_object_unref(pad);
4035 /* create dot. for debugging */
4036 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4039 return MM_ERROR_NONE;
4042 /* release text pipeline resource */
4043 player->textsink_linked = 0;
4045 /* release signal */
4046 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4048 if (player->pipeline->textbin) {
4049 LOGE("remove textbin");
4051 /* release textbin with it's childs */
4052 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4053 MMPLAYER_FREEIF(player->pipeline->textbin);
4054 player->pipeline->textbin = NULL;
4058 /* release subtitle elem */
4059 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4060 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4062 return MM_ERROR_PLAYER_INTERNAL;
4066 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4068 mmplayer_t *player = (mmplayer_t *)data;
4069 MMMessageParamType msg = {0, };
4070 GstClockTime duration = 0;
4071 gpointer text = NULL;
4072 guint text_size = 0;
4073 gboolean ret = TRUE;
4074 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4078 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4079 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4081 if (player->is_subtitle_force_drop) {
4082 LOGW("subtitle is dropped forcedly.");
4086 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4087 text = mapinfo.data;
4088 text_size = mapinfo.size;
4090 if (player->set_mode.subtitle_off) {
4091 LOGD("subtitle is OFF.");
4095 if (!text || (text_size == 0)) {
4096 LOGD("There is no subtitle to be displayed.");
4100 msg.data = (void *)text;
4102 duration = GST_BUFFER_DURATION(buffer);
4104 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4105 if (player->duration > GST_BUFFER_PTS(buffer))
4106 duration = player->duration - GST_BUFFER_PTS(buffer);
4109 LOGI("subtitle duration is invalid, subtitle duration change "
4110 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4112 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4114 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4116 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4117 gst_buffer_unmap(buffer, &mapinfo);
4124 static GstPadProbeReturn
4125 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4127 mmplayer_t *player = (mmplayer_t *)u_data;
4128 GstClockTime cur_timestamp = 0;
4129 gint64 adjusted_timestamp = 0;
4130 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4132 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4134 if (player->set_mode.subtitle_off) {
4135 LOGD("subtitle is OFF.");
4139 if (player->adjust_subtitle_pos == 0) {
4140 LOGD("nothing to do");
4144 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4145 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4147 if (adjusted_timestamp < 0) {
4148 LOGD("adjusted_timestamp under zero");
4153 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4154 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4155 GST_TIME_ARGS(cur_timestamp),
4156 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4158 return GST_PAD_PROBE_OK;
4162 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4166 /* check player and subtitlebin are created */
4167 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4168 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4170 if (position == 0) {
4171 LOGD("nothing to do");
4173 return MM_ERROR_NONE;
4176 /* check current postion */
4177 player->adjust_subtitle_pos = position;
4179 LOGD("save adjust_subtitle_pos in player");
4183 return MM_ERROR_NONE;
4187 * This function is to create audio or video pipeline for playing.
4189 * @param player [in] handle of player
4191 * @return This function returns zero on success.
4196 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4198 int ret = MM_ERROR_NONE;
4199 mmplayer_gst_element_t *mainbin = NULL;
4200 MMHandleType attrs = 0;
4203 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4205 /* get profile attribute */
4206 attrs = MMPLAYER_GET_ATTRS(player);
4208 LOGE("failed to get content attribute");
4212 /* create pipeline handles */
4213 if (player->pipeline) {
4214 LOGE("pipeline should be released before create new one");
4218 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4220 /* create mainbin */
4221 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4222 if (mainbin == NULL)
4225 /* create pipeline */
4226 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4227 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4228 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4229 LOGE("failed to create pipeline");
4234 player->pipeline->mainbin = mainbin;
4236 /* create the source and decoder elements */
4237 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4238 ret = _mmplayer_gst_build_es_pipeline(player);
4240 if (MMPLAYER_USE_DECODEBIN(player))
4241 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4243 ret = _mmplayer_gst_build_pipeline_with_src(player);
4246 if (ret != MM_ERROR_NONE) {
4247 LOGE("failed to create some elements");
4251 /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
4252 if (__mmplayer_check_subtitle(player)
4253 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4254 LOGE("failed to create text pipeline");
4257 ret = _mmplayer_gst_add_bus_watch(player);
4258 if (ret != MM_ERROR_NONE) {
4259 LOGE("failed to add bus watch");
4264 return MM_ERROR_NONE;
4267 _mmplayer_bus_watcher_remove(player);
4268 __mmplayer_gst_destroy_pipeline(player);
4269 return MM_ERROR_PLAYER_INTERNAL;
4273 __mmplayer_reset_gapless_state(mmplayer_t *player)
4276 MMPLAYER_RETURN_IF_FAIL(player
4278 && player->pipeline->audiobin
4279 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4281 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4288 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4291 int ret = MM_ERROR_NONE;
4295 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4297 /* cleanup stuffs */
4298 MMPLAYER_FREEIF(player->type);
4299 player->no_more_pad = FALSE;
4300 player->num_dynamic_pad = 0;
4302 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4303 player->subtitle_language_list = NULL;
4304 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4306 MMPLAYER_RECONFIGURE_LOCK(player);
4307 __mmplayer_reset_gapless_state(player);
4308 MMPLAYER_RECONFIGURE_UNLOCK(player);
4310 if (player->streamer) {
4311 _mm_player_streaming_initialize(player->streamer, FALSE);
4312 _mm_player_streaming_destroy(player->streamer);
4313 player->streamer = NULL;
4316 /* cleanup unlinked mime type */
4317 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4318 MMPLAYER_FREEIF(player->unlinked_video_mime);
4319 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4321 /* cleanup running stuffs */
4322 _mmplayer_cancel_eos_timer(player);
4324 /* cleanup gst stuffs */
4325 if (player->pipeline) {
4326 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4327 GstTagList *tag_list = player->pipeline->tag_list;
4329 /* first we need to disconnect all signal hander */
4330 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4333 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4334 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4335 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4336 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4337 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4338 gst_object_unref(bus);
4340 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4341 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4342 if (ret != MM_ERROR_NONE) {
4343 LOGE("fail to change state to NULL");
4344 return MM_ERROR_PLAYER_INTERNAL;
4347 LOGW("succeeded in changing state to NULL");
4349 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4352 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4353 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4355 /* free avsysaudiosink
4356 avsysaudiosink should be unref when destory pipeline just after start play with BT.
4357 Because audiosink is created but never added to bin, and therefore it will not be unref when pipeline is destroyed.
4359 MMPLAYER_FREEIF(audiobin);
4360 MMPLAYER_FREEIF(videobin);
4361 MMPLAYER_FREEIF(textbin);
4362 MMPLAYER_FREEIF(mainbin);
4366 gst_tag_list_unref(tag_list);
4368 MMPLAYER_FREEIF(player->pipeline);
4370 MMPLAYER_FREEIF(player->album_art);
4372 if (player->type_caps) {
4373 gst_caps_unref(player->type_caps);
4374 player->type_caps = NULL;
4377 if (player->v_stream_caps) {
4378 gst_caps_unref(player->v_stream_caps);
4379 player->v_stream_caps = NULL;
4382 if (player->a_stream_caps) {
4383 gst_caps_unref(player->a_stream_caps);
4384 player->a_stream_caps = NULL;
4387 if (player->s_stream_caps) {
4388 gst_caps_unref(player->s_stream_caps);
4389 player->s_stream_caps = NULL;
4391 _mmplayer_track_destroy(player);
4393 if (player->sink_elements)
4394 g_list_free(player->sink_elements);
4395 player->sink_elements = NULL;
4397 if (player->bufmgr) {
4398 tbm_bufmgr_deinit(player->bufmgr);
4399 player->bufmgr = NULL;
4402 LOGW("finished destroy pipeline");
4410 __mmplayer_gst_realize(mmplayer_t *player)
4413 int ret = MM_ERROR_NONE;
4417 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4419 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4421 ret = __mmplayer_gst_create_pipeline(player);
4423 LOGE("failed to create pipeline");
4427 /* set pipeline state to READY */
4428 /* NOTE : state change to READY must be performed sync. */
4429 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4430 ret = _mmplayer_gst_set_state(player,
4431 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4433 if (ret != MM_ERROR_NONE) {
4434 /* return error if failed to set state */
4435 LOGE("failed to set READY state");
4439 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4441 /* create dot before error-return. for debugging */
4442 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4450 __mmplayer_gst_unrealize(mmplayer_t *player)
4452 int ret = MM_ERROR_NONE;
4456 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4458 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4459 MMPLAYER_PRINT_STATE(player);
4461 /* release miscellaneous information */
4462 __mmplayer_release_misc(player);
4464 /* destroy pipeline */
4465 ret = __mmplayer_gst_destroy_pipeline(player);
4466 if (ret != MM_ERROR_NONE) {
4467 LOGE("failed to destory pipeline");
4471 /* release miscellaneous information.
4472 these info needs to be released after pipeline is destroyed. */
4473 __mmplayer_release_misc_post(player);
4475 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4483 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4488 LOGW("set_message_callback is called with invalid player handle");
4489 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4492 player->msg_cb = callback;
4493 player->msg_cb_param = user_param;
4495 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4499 return MM_ERROR_NONE;
4503 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4505 int ret = MM_ERROR_NONE;
4510 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4511 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4512 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4514 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4516 if (strstr(uri, "es_buff://")) {
4517 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4518 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4519 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4520 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4522 tmp = g_ascii_strdown(uri, strlen(uri));
4523 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4524 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4526 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4528 } else if (strstr(uri, "mms://")) {
4529 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4530 } else if ((path = strstr(uri, "mem://"))) {
4531 ret = __mmplayer_set_mem_uri(data, path, param);
4533 ret = __mmplayer_set_file_uri(data, uri);
4536 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4537 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4538 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4539 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4541 /* dump parse result */
4542 SECURE_LOGW("incoming uri : %s", uri);
4543 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4544 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4552 __mmplayer_can_do_interrupt(mmplayer_t *player)
4554 if (!player || !player->pipeline || !player->attrs) {
4555 LOGW("not initialized");
4559 if (player->audio_decoded_cb) {
4560 LOGW("not support in pcm extraction mode");
4564 /* check if seeking */
4565 if (player->seek_state != MMPLAYER_SEEK_NONE) {
4566 MMMessageParamType msg_param;
4567 memset(&msg_param, 0, sizeof(MMMessageParamType));
4568 msg_param.code = MM_ERROR_PLAYER_SEEK;
4569 player->seek_state = MMPLAYER_SEEK_NONE;
4570 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
4574 /* check other thread */
4575 if (!MMPLAYER_CMD_TRYLOCK(player)) {
4576 LOGW("locked already, cmd state : %d", player->cmd);
4578 /* check application command */
4579 if (player->cmd == MMPLAYER_COMMAND_START || player->cmd == MMPLAYER_COMMAND_RESUME) {
4580 LOGW("playing.. should wait cmd lock then, will be interrupted");
4582 /* lock will be released at mrp_resource_release_cb() */
4583 MMPLAYER_CMD_LOCK(player);
4586 LOGW("nothing to do");
4589 LOGW("can interrupt immediately");
4593 FAILED: /* with CMD UNLOCKED */
4596 INTERRUPT: /* with CMD LOCKED, will do UNLOCK at __resource_release_cb() */
4601 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4604 mmplayer_t *player = NULL;
4605 MMMessageParamType msg = {0, };
4607 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4612 LOGE("user_data is null");
4615 player = (mmplayer_t *)user_data;
4617 if (!__mmplayer_can_do_interrupt(player)) {
4618 LOGW("no need to interrupt, so leave");
4619 /* FIXME: there is no way to avoid releasing resource. */
4623 player->interrupted_by_resource = TRUE;
4625 /* get last play position */
4626 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4627 msg.union_type = MM_MSG_UNION_TIME;
4628 msg.time.elapsed = pos;
4629 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4631 LOGW("failed to get play position.");
4634 LOGD("video resource conflict so, resource will be freed by unrealizing");
4635 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4636 LOGE("failed to unrealize");
4638 /* lock is called in __mmplayer_can_do_interrupt() */
4639 MMPLAYER_CMD_UNLOCK(player);
4641 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4642 player->hw_resource[res_idx] = NULL;
4646 return TRUE; /* release all the resources */
4650 __mmplayer_initialize_video_roi(mmplayer_t *player)
4652 player->video_roi.scale_x = 0.0;
4653 player->video_roi.scale_y = 0.0;
4654 player->video_roi.scale_width = 1.0;
4655 player->video_roi.scale_height = 1.0;
4659 _mmplayer_create_player(MMHandleType handle)
4661 int ret = MM_ERROR_PLAYER_INTERNAL;
4662 bool enabled = false;
4664 mmplayer_t *player = MM_PLAYER_CAST(handle);
4668 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4670 /* initialize player state */
4671 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4672 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4673 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4674 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4676 /* check current state */
4677 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4679 /* construct attributes */
4680 player->attrs = _mmplayer_construct_attribute(handle);
4682 if (!player->attrs) {
4683 LOGE("Failed to construct attributes");
4687 /* initialize gstreamer with configured parameter */
4688 if (!__mmplayer_init_gstreamer(player)) {
4689 LOGE("Initializing gstreamer failed");
4690 _mmplayer_deconstruct_attribute(handle);
4694 /* create lock. note that g_tread_init() has already called in gst_init() */
4695 g_mutex_init(&player->fsink_lock);
4697 /* create update tag lock */
4698 g_mutex_init(&player->update_tag_lock);
4700 /* create gapless play mutex */
4701 g_mutex_init(&player->gapless_play_thread_mutex);
4703 /* create gapless play cond */
4704 g_cond_init(&player->gapless_play_thread_cond);
4706 /* create gapless play thread */
4707 player->gapless_play_thread =
4708 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4709 if (!player->gapless_play_thread) {
4710 LOGE("failed to create gapless play thread");
4711 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4712 g_mutex_clear(&player->gapless_play_thread_mutex);
4713 g_cond_clear(&player->gapless_play_thread_cond);
4717 player->bus_msg_q = g_queue_new();
4718 if (!player->bus_msg_q) {
4719 LOGE("failed to create queue for bus_msg");
4720 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4724 ret = _mmplayer_initialize_video_capture(player);
4725 if (ret != MM_ERROR_NONE) {
4726 LOGE("failed to initialize video capture");
4730 /* initialize resource manager */
4731 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4732 __resource_release_cb, player, &player->resource_manager)
4733 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4734 LOGE("failed to initialize resource manager");
4735 ret = MM_ERROR_PLAYER_INTERNAL;
4739 /* create video bo lock and cond */
4740 g_mutex_init(&player->video_bo_mutex);
4741 g_cond_init(&player->video_bo_cond);
4743 /* create subtitle info lock and cond */
4744 g_mutex_init(&player->subtitle_info_mutex);
4745 g_cond_init(&player->subtitle_info_cond);
4747 player->streaming_type = STREAMING_SERVICE_NONE;
4749 /* give default value of audio effect setting */
4750 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4751 player->sound.rg_enable = false;
4752 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4754 player->play_subtitle = FALSE;
4755 player->has_closed_caption = FALSE;
4756 player->pending_resume = FALSE;
4757 if (player->ini.dump_element_keyword[0][0] == '\0')
4758 player->ini.set_dump_element_flag = FALSE;
4760 player->ini.set_dump_element_flag = TRUE;
4762 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4763 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4764 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4766 /* Set video360 settings to their defaults for just-created player.
4769 player->is_360_feature_enabled = FALSE;
4770 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4771 LOGI("spherical feature info: %d", enabled);
4773 player->is_360_feature_enabled = TRUE;
4775 LOGE("failed to get spherical feature info");
4778 player->is_content_spherical = FALSE;
4779 player->is_video360_enabled = TRUE;
4780 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4781 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4782 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4783 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4784 player->video360_zoom = 1.0f;
4785 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4786 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4788 __mmplayer_initialize_video_roi(player);
4790 /* set player state to null */
4791 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4792 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4796 return MM_ERROR_NONE;
4800 g_mutex_clear(&player->fsink_lock);
4801 /* free update tag lock */
4802 g_mutex_clear(&player->update_tag_lock);
4803 g_queue_free(player->bus_msg_q);
4804 player->bus_msg_q = NULL;
4805 /* free gapless play thread */
4806 if (player->gapless_play_thread) {
4807 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4808 player->gapless_play_thread_exit = TRUE;
4809 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4810 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4812 g_thread_join(player->gapless_play_thread);
4813 player->gapless_play_thread = NULL;
4815 g_mutex_clear(&player->gapless_play_thread_mutex);
4816 g_cond_clear(&player->gapless_play_thread_cond);
4819 /* release attributes */
4820 _mmplayer_deconstruct_attribute(handle);
4828 __mmplayer_init_gstreamer(mmplayer_t *player)
4830 static gboolean initialized = FALSE;
4831 static const int max_argc = 50;
4833 gchar **argv = NULL;
4834 gchar **argv2 = NULL;
4840 LOGD("gstreamer already initialized.");
4845 argc = malloc(sizeof(int));
4846 argv = malloc(sizeof(gchar *) * max_argc);
4847 argv2 = malloc(sizeof(gchar *) * max_argc);
4849 if (!argc || !argv || !argv2)
4852 memset(argv, 0, sizeof(gchar *) * max_argc);
4853 memset(argv2, 0, sizeof(gchar *) * max_argc);
4857 argv[0] = g_strdup("mmplayer");
4860 for (i = 0; i < 5; i++) {
4861 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4862 if (strlen(player->ini.gst_param[i]) > 0) {
4863 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4868 /* we would not do fork for scanning plugins */
4869 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4872 /* check disable registry scan */
4873 if (player->ini.skip_rescan) {
4874 argv[*argc] = g_strdup("--gst-disable-registry-update");
4878 /* check disable segtrap */
4879 if (player->ini.disable_segtrap) {
4880 argv[*argc] = g_strdup("--gst-disable-segtrap");
4884 LOGD("initializing gstreamer with following parameter");
4885 LOGD("argc : %d", *argc);
4888 for (i = 0; i < arg_count; i++) {
4890 LOGD("argv[%d] : %s", i, argv2[i]);
4893 /* initializing gstreamer */
4894 if (!gst_init_check(argc, &argv, &err)) {
4895 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4902 for (i = 0; i < arg_count; i++) {
4904 LOGD("release - argv[%d] : %s", i, argv2[i]);
4906 MMPLAYER_FREEIF(argv2[i]);
4909 MMPLAYER_FREEIF(argv);
4910 MMPLAYER_FREEIF(argv2);
4911 MMPLAYER_FREEIF(argc);
4921 for (i = 0; i < arg_count; i++) {
4922 LOGD("free[%d] : %s", i, argv2[i]);
4923 MMPLAYER_FREEIF(argv2[i]);
4926 MMPLAYER_FREEIF(argv);
4927 MMPLAYER_FREEIF(argv2);
4928 MMPLAYER_FREEIF(argc);
4934 __mmplayer_check_async_state_transition(mmplayer_t *player)
4936 GstState element_state = GST_STATE_VOID_PENDING;
4937 GstState element_pending_state = GST_STATE_VOID_PENDING;
4938 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4939 GstElement *element = NULL;
4940 gboolean async = FALSE;
4942 /* check player handle */
4943 MMPLAYER_RETURN_IF_FAIL(player &&
4945 player->pipeline->mainbin &&
4946 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4949 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4951 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4952 LOGD("don't need to check the pipeline state");
4956 MMPLAYER_PRINT_STATE(player);
4958 /* wait for state transition */
4959 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4960 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4962 if (ret == GST_STATE_CHANGE_FAILURE) {
4963 LOGE(" [%s] state : %s pending : %s",
4964 GST_ELEMENT_NAME(element),
4965 gst_element_state_get_name(element_state),
4966 gst_element_state_get_name(element_pending_state));
4968 /* dump state of all element */
4969 _mmplayer_dump_pipeline_state(player);
4974 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4979 _mmplayer_destroy(MMHandleType handle)
4981 mmplayer_t *player = MM_PLAYER_CAST(handle);
4985 /* check player handle */
4986 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4988 /* destroy can called at anytime */
4989 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4991 /* check async state transition */
4992 __mmplayer_check_async_state_transition(player);
4994 /* release gapless play thread */
4995 if (player->gapless_play_thread) {
4996 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4997 player->gapless_play_thread_exit = TRUE;
4998 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4999 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
5001 LOGD("waitting for gapless play thread exit");
5002 g_thread_join(player->gapless_play_thread);
5003 g_mutex_clear(&player->gapless_play_thread_mutex);
5004 g_cond_clear(&player->gapless_play_thread_cond);
5005 LOGD("gapless play thread released");
5008 _mmplayer_release_video_capture(player);
5010 /* de-initialize resource manager */
5011 if (MM_RESOURCE_MANAGER_ERROR_NONE != mm_resource_manager_destroy(
5012 player->resource_manager))
5013 LOGE("failed to deinitialize resource manager");
5015 /* release miscellaneous information */
5016 __mmplayer_release_misc(player);
5018 /* release pipeline */
5019 if (MM_ERROR_NONE != __mmplayer_gst_destroy_pipeline(player)) {
5020 LOGE("failed to destory pipeline");
5021 return MM_ERROR_PLAYER_INTERNAL;
5024 g_queue_free(player->bus_msg_q);
5026 /* release subtitle info lock and cond */
5027 g_mutex_clear(&player->subtitle_info_mutex);
5028 g_cond_clear(&player->subtitle_info_cond);
5030 __mmplayer_release_dump_list(player->dump_list);
5032 /* release miscellaneous information.
5033 these info needs to be released after pipeline is destroyed. */
5034 __mmplayer_release_misc_post(player);
5036 /* release attributes */
5037 _mmplayer_deconstruct_attribute(handle);
5039 if (player->uri_info.uri_list) {
5040 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5041 player->uri_info.uri_list = NULL;
5045 g_mutex_clear(&player->fsink_lock);
5048 g_mutex_clear(&player->update_tag_lock);
5050 /* release video bo lock and cond */
5051 g_mutex_clear(&player->video_bo_mutex);
5052 g_cond_clear(&player->video_bo_cond);
5056 return MM_ERROR_NONE;
5060 _mmplayer_realize(MMHandleType hplayer)
5062 mmplayer_t *player = (mmplayer_t *)hplayer;
5063 int ret = MM_ERROR_NONE;
5066 MMHandleType attrs = 0;
5070 /* check player handle */
5071 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5073 /* check current state */
5074 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5076 attrs = MMPLAYER_GET_ATTRS(player);
5078 LOGE("fail to get attributes.");
5079 return MM_ERROR_PLAYER_INTERNAL;
5081 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5082 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5084 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5085 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5087 if (ret != MM_ERROR_NONE) {
5088 LOGE("failed to parse profile");
5093 if (uri && (strstr(uri, "es_buff://"))) {
5094 if (strstr(uri, "es_buff://push_mode"))
5095 player->es_player_push_mode = TRUE;
5097 player->es_player_push_mode = FALSE;
5100 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5101 LOGW("mms protocol is not supported format.");
5102 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5105 if (MMPLAYER_IS_STREAMING(player))
5106 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5108 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5110 player->smooth_streaming = FALSE;
5111 player->videodec_linked = 0;
5112 player->audiodec_linked = 0;
5113 player->textsink_linked = 0;
5114 player->is_external_subtitle_present = FALSE;
5115 player->is_external_subtitle_added_now = FALSE;
5116 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5117 player->video360_metadata.is_spherical = -1;
5118 player->is_openal_plugin_used = FALSE;
5119 player->subtitle_language_list = NULL;
5120 player->is_subtitle_force_drop = FALSE;
5122 _mmplayer_track_initialize(player);
5123 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5125 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5126 gint prebuffer_ms = 0, rebuffer_ms = 0;
5128 player->streamer = _mm_player_streaming_create();
5129 _mm_player_streaming_initialize(player->streamer, TRUE);
5131 mm_attrs_multiple_get(player->attrs, NULL,
5132 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5133 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5135 if (prebuffer_ms > 0) {
5136 prebuffer_ms = MAX(prebuffer_ms, 1000);
5137 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5140 if (rebuffer_ms > 0) {
5141 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5142 rebuffer_ms = MAX(rebuffer_ms, 1000);
5143 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5146 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5147 player->streamer->buffering_req.rebuffer_time);
5150 /* realize pipeline */
5151 ret = __mmplayer_gst_realize(player);
5152 if (ret != MM_ERROR_NONE)
5153 LOGE("fail to realize the player.");
5155 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5163 _mmplayer_unrealize(MMHandleType hplayer)
5165 mmplayer_t *player = (mmplayer_t *)hplayer;
5166 int ret = MM_ERROR_NONE;
5170 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5172 MMPLAYER_CMD_UNLOCK(player);
5173 _mmplayer_bus_watcher_remove(player);
5174 /* destroy the gst bus msg thread which is created during realize.
5175 this funct have to be called before getting cmd lock. */
5176 _mmplayer_bus_msg_thread_destroy(player);
5177 MMPLAYER_CMD_LOCK(player);
5179 /* check current state */
5180 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5182 /* check async state transition */
5183 __mmplayer_check_async_state_transition(player);
5185 /* unrealize pipeline */
5186 ret = __mmplayer_gst_unrealize(player);
5188 if (!player->interrupted_by_resource) {
5189 int rm_ret = MM_ERROR_NONE;
5190 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5192 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5193 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5194 if (rm_ret != MM_ERROR_NONE)
5195 LOGE("failed to release [%d] resources", res_idx);
5199 player->interrupted_by_resource = FALSE;
5206 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5208 mmplayer_t *player = (mmplayer_t *)hplayer;
5210 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5212 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5216 _mmplayer_get_state(MMHandleType hplayer, int *state)
5218 mmplayer_t *player = (mmplayer_t *)hplayer;
5220 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5222 *state = MMPLAYER_CURRENT_STATE(player);
5224 return MM_ERROR_NONE;
5228 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5230 GstElement *vol_element = NULL;
5231 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5234 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5235 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5237 /* check pipeline handle */
5238 if (!player->pipeline || !player->pipeline->audiobin) {
5239 LOGD("'%s' will be applied when audiobin is created", prop_name);
5241 /* NOTE : stored value will be used in create_audiobin
5242 * returning MM_ERROR_NONE here makes application to able to
5243 * set audio volume or mute at anytime.
5245 return MM_ERROR_NONE;
5248 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5249 volume_elem_id = MMPLAYER_A_SINK;
5251 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5253 LOGE("failed to get vol element %d", volume_elem_id);
5254 return MM_ERROR_PLAYER_INTERNAL;
5257 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5259 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5260 LOGE("there is no '%s' property", prop_name);
5261 return MM_ERROR_PLAYER_INTERNAL;
5264 if (!strcmp(prop_name, "volume")) {
5265 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5266 } else if (!strcmp(prop_name, "mute")) {
5267 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5269 LOGE("invalid property %s", prop_name);
5270 return MM_ERROR_PLAYER_INTERNAL;
5273 return MM_ERROR_NONE;
5277 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5279 int ret = MM_ERROR_NONE;
5280 mmplayer_t *player = (mmplayer_t *)hplayer;
5283 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5285 LOGD("volume = %f", volume);
5287 /* invalid factor range or not */
5288 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5289 LOGE("Invalid volume value");
5290 return MM_ERROR_INVALID_ARGUMENT;
5293 player->sound.volume = volume;
5295 ret = __mmplayer_gst_set_volume_property(player, "volume");
5302 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5304 mmplayer_t *player = (mmplayer_t *)hplayer;
5308 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5309 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5311 *volume = player->sound.volume;
5313 LOGD("current vol = %f", *volume);
5316 return MM_ERROR_NONE;
5320 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5322 int ret = MM_ERROR_NONE;
5323 mmplayer_t *player = (mmplayer_t *)hplayer;
5326 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5328 LOGD("mute = %d", mute);
5330 player->sound.mute = mute;
5332 ret = __mmplayer_gst_set_volume_property(player, "mute");
5339 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5341 mmplayer_t *player = (mmplayer_t *)hplayer;
5345 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5346 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5348 *mute = player->sound.mute;
5350 LOGD("current mute = %d", *mute);
5354 return MM_ERROR_NONE;
5358 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5360 mmplayer_t *player = (mmplayer_t *)hplayer;
5364 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5366 player->audio_stream_changed_cb = callback;
5367 player->audio_stream_changed_cb_user_param = user_param;
5368 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5372 return MM_ERROR_NONE;
5376 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5378 mmplayer_t *player = (mmplayer_t *)hplayer;
5382 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5384 player->audio_decoded_cb = callback;
5385 player->audio_decoded_cb_user_param = user_param;
5386 player->audio_extract_opt = opt;
5387 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5391 return MM_ERROR_NONE;
5395 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5397 mmplayer_t *player = (mmplayer_t *)hplayer;
5401 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5403 if (callback && !player->bufmgr)
5404 player->bufmgr = tbm_bufmgr_init(-1);
5406 player->set_mode.video_export = (callback) ? true : false;
5407 player->video_decoded_cb = callback;
5408 player->video_decoded_cb_user_param = user_param;
5410 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5414 return MM_ERROR_NONE;
5418 _mmplayer_start(MMHandleType hplayer)
5420 mmplayer_t *player = (mmplayer_t *)hplayer;
5421 gint ret = MM_ERROR_NONE;
5425 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5427 /* check current state */
5428 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5430 /* start pipeline */
5431 ret = _mmplayer_gst_start(player);
5432 if (ret != MM_ERROR_NONE)
5433 LOGE("failed to start player.");
5435 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5436 LOGD("force playing start even during buffering");
5437 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5445 /* NOTE: post "not supported codec message" to application
5446 * when one codec is not found during AUTOPLUGGING in MSL.
5447 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5448 * And, if any codec is not found, don't send message here.
5449 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5452 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5454 MMMessageParamType msg_param;
5455 memset(&msg_param, 0, sizeof(MMMessageParamType));
5456 gboolean post_msg_direct = FALSE;
5460 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5462 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5463 player->not_supported_codec, player->can_support_codec);
5465 if (player->not_found_demuxer) {
5466 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5467 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5469 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5470 MMPLAYER_FREEIF(msg_param.data);
5472 return MM_ERROR_NONE;
5475 if (player->not_supported_codec) {
5476 if (player->can_support_codec) {
5477 // There is one codec to play
5478 post_msg_direct = TRUE;
5480 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5481 post_msg_direct = TRUE;
5484 if (post_msg_direct) {
5485 MMMessageParamType msg_param;
5486 memset(&msg_param, 0, sizeof(MMMessageParamType));
5488 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5489 LOGW("not found AUDIO codec, posting error code to application.");
5491 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5492 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5493 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5494 LOGW("not found VIDEO codec, posting error code to application.");
5496 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5497 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5500 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5502 MMPLAYER_FREEIF(msg_param.data);
5504 return MM_ERROR_NONE;
5506 // no any supported codec case
5507 LOGW("not found any codec, posting error code to application.");
5509 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5510 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5511 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5513 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5514 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5517 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5519 MMPLAYER_FREEIF(msg_param.data);
5525 return MM_ERROR_NONE;
5528 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5530 GstState element_state = GST_STATE_VOID_PENDING;
5531 GstState element_pending_state = GST_STATE_VOID_PENDING;
5532 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5533 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5535 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5537 MMPLAYER_RECONFIGURE_LOCK(player);
5538 if (!player->gapless.reconfigure) {
5539 MMPLAYER_RECONFIGURE_UNLOCK(player);
5543 LOGI("reconfigure is under process");
5544 MMPLAYER_RECONFIGURE_WAIT(player);
5545 MMPLAYER_RECONFIGURE_UNLOCK(player);
5546 LOGI("reconfigure is completed.");
5548 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5549 &element_state, &element_pending_state, timeout * GST_SECOND);
5550 if (result == GST_STATE_CHANGE_FAILURE)
5551 LOGW("failed to get pipeline state in %d sec", timeout);
5556 /* NOTE : it should be able to call 'stop' anytime*/
5558 _mmplayer_stop(MMHandleType hplayer)
5560 mmplayer_t *player = (mmplayer_t *)hplayer;
5561 int ret = MM_ERROR_NONE;
5565 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5567 /* check current state */
5568 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5570 /* need to wait till the rebuilding pipeline is completed */
5571 __mmplayer_check_pipeline_reconfigure_state(player);
5572 MMPLAYER_RECONFIGURE_LOCK(player);
5573 __mmplayer_reset_gapless_state(player);
5574 MMPLAYER_RECONFIGURE_UNLOCK(player);
5576 /* NOTE : application should not wait for EOS after calling STOP */
5577 _mmplayer_cancel_eos_timer(player);
5580 player->seek_state = MMPLAYER_SEEK_NONE;
5583 ret = _mmplayer_gst_stop(player);
5585 if (ret != MM_ERROR_NONE)
5586 LOGE("failed to stop player.");
5594 _mmplayer_pause(MMHandleType hplayer)
5596 mmplayer_t *player = (mmplayer_t *)hplayer;
5597 gint64 pos_nsec = 0;
5598 gboolean async = FALSE;
5599 gint ret = MM_ERROR_NONE;
5603 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5605 /* check current state */
5606 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5608 /* check pipline reconfigure state */
5609 __mmplayer_check_pipeline_reconfigure_state(player);
5611 switch (MMPLAYER_CURRENT_STATE(player)) {
5612 case MM_PLAYER_STATE_READY:
5614 /* check prepare async or not.
5615 * In the case of streaming playback, it's recommned to avoid blocking wait.
5617 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5618 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5620 /* Changing back sync of rtspsrc to async */
5621 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5622 LOGD("async prepare working mode for rtsp");
5628 case MM_PLAYER_STATE_PLAYING:
5630 /* NOTE : store current point to overcome some bad operation
5631 *(returning zero when getting current position in paused state) of some
5634 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5635 LOGW("getting current position failed in paused");
5637 player->last_position = pos_nsec;
5639 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5640 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5641 This causes problem is position calculation during normal pause resume scenarios also.
5642 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5643 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5644 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5645 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5651 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5652 LOGD("doing async pause in case of ms buff src");
5656 /* pause pipeline */
5657 ret = _mmplayer_gst_pause(player, async);
5658 if (ret != MM_ERROR_NONE) {
5659 LOGE("failed to pause player. ret : 0x%x", ret);
5660 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5664 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5665 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5666 LOGE("failed to update display_rotation");
5670 return MM_ERROR_NONE;
5673 /* in case of streaming, pause could take long time.*/
5675 _mmplayer_abort_pause(MMHandleType hplayer)
5677 mmplayer_t *player = (mmplayer_t *)hplayer;
5678 int ret = MM_ERROR_NONE;
5682 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5684 player->pipeline->mainbin,
5685 MM_ERROR_PLAYER_NOT_INITIALIZED);
5687 LOGD("set the pipeline state to READY");
5689 /* set state to READY */
5690 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5691 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5692 if (ret != MM_ERROR_NONE) {
5693 LOGE("fail to change state to READY");
5694 return MM_ERROR_PLAYER_INTERNAL;
5697 LOGD("succeeded in changing state to READY");
5702 _mmplayer_resume(MMHandleType hplayer)
5704 mmplayer_t *player = (mmplayer_t *)hplayer;
5705 int ret = MM_ERROR_NONE;
5706 gboolean async = FALSE;
5710 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5712 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5713 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5714 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5718 /* Changing back sync mode rtspsrc to async */
5719 LOGD("async resume for rtsp case");
5723 /* check current state */
5724 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5726 ret = _mmplayer_gst_resume(player, async);
5727 if (ret != MM_ERROR_NONE)
5728 LOGE("failed to resume player.");
5730 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5731 LOGD("force resume even during buffering");
5732 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5741 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5743 mmplayer_t *player = (mmplayer_t *)hplayer;
5744 gint64 pos_nsec = 0;
5745 int ret = MM_ERROR_NONE;
5747 signed long long start = 0, stop = 0;
5748 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5751 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5752 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5754 /* The sound of video is not supported under 0.0 and over 2.0. */
5755 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5756 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5759 _mmplayer_set_mute(hplayer, mute);
5761 if (player->playback_rate == rate)
5762 return MM_ERROR_NONE;
5764 /* If the position is reached at start potion during fast backward, EOS is posted.
5765 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5767 player->playback_rate = rate;
5769 current_state = MMPLAYER_CURRENT_STATE(player);
5771 if (current_state != MM_PLAYER_STATE_PAUSED)
5772 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5774 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5776 if ((current_state == MM_PLAYER_STATE_PAUSED)
5777 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5778 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5779 pos_nsec = player->last_position;
5784 stop = GST_CLOCK_TIME_NONE;
5786 start = GST_CLOCK_TIME_NONE;
5790 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5791 player->playback_rate,
5793 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5794 GST_SEEK_TYPE_SET, start,
5795 GST_SEEK_TYPE_SET, stop)) {
5796 LOGE("failed to set speed playback");
5797 return MM_ERROR_PLAYER_SEEK;
5800 LOGD("succeeded to set speed playback as %0.1f", rate);
5804 return MM_ERROR_NONE;;
5808 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5810 mmplayer_t *player = (mmplayer_t *)hplayer;
5811 int ret = MM_ERROR_NONE;
5815 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5817 /* check pipline reconfigure state */
5818 __mmplayer_check_pipeline_reconfigure_state(player);
5820 ret = _mmplayer_gst_set_position(player, position, FALSE);
5828 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5830 mmplayer_t *player = (mmplayer_t *)hplayer;
5831 int ret = MM_ERROR_NONE;
5833 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5834 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5836 if (g_strrstr(player->type, "video/mpegts"))
5837 __mmplayer_update_duration_value(player);
5839 *duration = player->duration;
5844 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5846 mmplayer_t *player = (mmplayer_t *)hplayer;
5847 int ret = MM_ERROR_NONE;
5849 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5851 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5857 _mmplayer_adjust_subtitle_postion(MMHandleType hplayer, int position)
5859 mmplayer_t *player = (mmplayer_t *)hplayer;
5860 int ret = MM_ERROR_NONE;
5864 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5866 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5874 __mmplayer_is_midi_type(gchar *str_caps)
5876 if ((g_strrstr(str_caps, "audio/midi")) ||
5877 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5878 (g_strrstr(str_caps, "application/x-smaf")) ||
5879 (g_strrstr(str_caps, "audio/x-imelody")) ||
5880 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5881 (g_strrstr(str_caps, "audio/xmf")) ||
5882 (g_strrstr(str_caps, "audio/mxmf"))) {
5891 __mmplayer_is_only_mp3_type(gchar *str_caps)
5893 if (g_strrstr(str_caps, "application/x-id3") ||
5894 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5900 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5902 GstStructure *caps_structure = NULL;
5903 gint samplerate = 0;
5907 MMPLAYER_RETURN_IF_FAIL(player && caps);
5909 caps_structure = gst_caps_get_structure(caps, 0);
5911 /* set stream information */
5912 gst_structure_get_int(caps_structure, "rate", &samplerate);
5913 gst_structure_get_int(caps_structure, "channels", &channels);
5915 mm_player_set_attribute((MMHandleType)player, NULL,
5916 "content_audio_samplerate", samplerate,
5917 "content_audio_channels", channels, NULL);
5919 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5923 __mmplayer_update_content_type_info(mmplayer_t *player)
5926 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5928 if (__mmplayer_is_midi_type(player->type)) {
5929 player->bypass_audio_effect = TRUE;
5933 if (!player->streamer) {
5934 LOGD("no need to check streaming type");
5938 if (g_strrstr(player->type, "application/x-hls")) {
5939 /* If it can't know exact type when it parses uri because of redirection case,
5940 * it will be fixed by typefinder or when doing autoplugging.
5942 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5943 player->streamer->is_adaptive_streaming = TRUE;
5944 } else if (g_strrstr(player->type, "application/dash+xml")) {
5945 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5946 player->streamer->is_adaptive_streaming = TRUE;
5949 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5950 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5951 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5953 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5954 if (player->streamer->is_adaptive_streaming)
5955 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5957 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5961 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5966 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5967 GstCaps *caps, gpointer data)
5969 mmplayer_t *player = (mmplayer_t *)data;
5973 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5975 /* store type string */
5976 if (player->type_caps) {
5977 gst_caps_unref(player->type_caps);
5978 player->type_caps = NULL;
5981 player->type_caps = gst_caps_copy(caps);
5982 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5984 MMPLAYER_FREEIF(player->type);
5985 player->type = gst_caps_to_string(caps);
5987 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5988 player, player->type, probability, gst_caps_get_size(caps));
5990 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5991 (g_strrstr(player->type, "audio/x-raw-int"))) {
5992 LOGE("not support media format");
5994 if (player->msg_posted == FALSE) {
5995 MMMessageParamType msg_param;
5996 memset(&msg_param, 0, sizeof(MMMessageParamType));
5998 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5999 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
6001 /* don't post more if one was sent already */
6002 player->msg_posted = TRUE;
6007 __mmplayer_update_content_type_info(player);
6009 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
6012 pad = gst_element_get_static_pad(tf, "src");
6014 LOGE("fail to get typefind src pad.");
6018 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6019 gboolean async = FALSE;
6020 LOGE("failed to autoplug %s", player->type);
6022 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6024 if (async && player->msg_posted == FALSE)
6025 __mmplayer_handle_missed_plugin(player);
6027 gst_object_unref(GST_OBJECT(pad));
6034 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6036 GstElement *decodebin = NULL;
6040 /* create decodebin */
6041 decodebin = gst_element_factory_make("decodebin", NULL);
6044 LOGE("fail to create decodebin");
6048 /* raw pad handling signal */
6049 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6050 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6052 /* no-more-pad pad handling signal */
6053 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6054 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6056 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6057 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6059 /* This signal is emitted when a pad for which there is no further possible
6060 decoding is added to the decodebin.*/
6061 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6062 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6064 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6065 before looking for any elements that can handle that stream.*/
6066 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6067 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6069 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6070 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6071 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6073 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6074 before looking for any elements that can handle that stream.*/
6075 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6076 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6078 /* This signal is emitted once decodebin has finished decoding all the data.*/
6079 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6080 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6082 /* This signal is emitted when a element is added to the bin.*/
6083 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6084 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6091 __mmplayer_gst_make_queue2(mmplayer_t *player)
6093 GstElement *queue2 = NULL;
6094 gint64 dur_bytes = 0L;
6095 mmplayer_gst_element_t *mainbin = NULL;
6096 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6099 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6101 mainbin = player->pipeline->mainbin;
6103 queue2 = gst_element_factory_make("queue2", "queue2");
6105 LOGE("failed to create buffering queue element");
6109 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6110 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6112 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6114 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6115 * skip the pull mode(file or ring buffering) setting. */
6116 if (dur_bytes > 0) {
6117 if (!g_strrstr(player->type, "video/mpegts")) {
6118 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6119 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6125 _mm_player_streaming_set_queue2(player->streamer,
6129 (guint64)dur_bytes); /* no meaning at the moment */
6135 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6137 mmplayer_gst_element_t *mainbin = NULL;
6138 GstElement *decodebin = NULL;
6139 GstElement *queue2 = NULL;
6140 GstPad *sinkpad = NULL;
6141 GstPad *qsrcpad = NULL;
6144 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6146 mainbin = player->pipeline->mainbin;
6148 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6150 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6151 LOGW("need to check: muxed buffer is not null");
6154 queue2 = __mmplayer_gst_make_queue2(player);
6156 LOGE("failed to make queue2");
6160 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6161 LOGE("failed to add buffering queue");
6165 sinkpad = gst_element_get_static_pad(queue2, "sink");
6166 qsrcpad = gst_element_get_static_pad(queue2, "src");
6168 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6169 LOGE("failed to link [%s:%s]-[%s:%s]",
6170 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6174 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6175 LOGE("failed to sync queue2 state with parent");
6179 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6180 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6184 gst_object_unref(GST_OBJECT(sinkpad));
6188 /* create decodebin */
6189 decodebin = _mmplayer_gst_make_decodebin(player);
6191 LOGE("failed to make decodebin");
6195 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6196 LOGE("failed to add decodebin");
6200 /* to force caps on the decodebin element and avoid reparsing stuff by
6201 * typefind. It also avoids a deadlock in the way typefind activates pads in
6202 * the state change */
6203 g_object_set(decodebin, "sink-caps", caps, NULL);
6205 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6207 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6208 LOGE("failed to link [%s:%s]-[%s:%s]",
6209 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6213 gst_object_unref(GST_OBJECT(sinkpad));
6215 gst_object_unref(GST_OBJECT(qsrcpad));
6218 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6219 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6221 /* set decodebin property about buffer in streaming playback. *
6222 * in case of HLS/DASH, it does not need to have big buffer *
6223 * because it is kind of adaptive streaming. */
6224 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6225 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6226 gint high_percent = 0;
6228 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6229 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6231 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6233 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6235 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6236 "high-percent", high_percent,
6237 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6238 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6239 "max-size-buffers", 0, NULL); // disable or automatic
6242 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6243 LOGE("failed to sync decodebin state with parent");
6254 gst_object_unref(GST_OBJECT(sinkpad));
6257 gst_object_unref(GST_OBJECT(qsrcpad));
6260 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6261 * You need to explicitly set elements to the NULL state before
6262 * dropping the final reference, to allow them to clean up.
6264 gst_element_set_state(queue2, GST_STATE_NULL);
6266 /* And, it still has a parent "player".
6267 * You need to let the parent manage the object instead of unreffing the object directly.
6269 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6270 gst_object_unref(queue2);
6275 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6276 * You need to explicitly set elements to the NULL state before
6277 * dropping the final reference, to allow them to clean up.
6279 gst_element_set_state(decodebin, GST_STATE_NULL);
6281 /* And, it still has a parent "player".
6282 * You need to let the parent manage the object instead of unreffing the object directly.
6285 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6286 gst_object_unref(decodebin);
6294 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6298 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6299 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6301 LOGD("class : %s, mime : %s", factory_class, mime);
6303 /* add missing plugin */
6304 /* NOTE : msl should check missing plugin for image mime type.
6305 * Some motion jpeg clips can have playable audio track.
6306 * So, msl have to play audio after displaying popup written video format not supported.
6308 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6309 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6310 LOGD("not found demuxer");
6311 player->not_found_demuxer = TRUE;
6312 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6318 if (!g_strrstr(factory_class, "Demuxer")) {
6319 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6320 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6321 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6323 /* check that clip have multi tracks or not */
6324 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6325 LOGD("video plugin is already linked");
6327 LOGW("add VIDEO to missing plugin");
6328 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6329 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6331 } else if (g_str_has_prefix(mime, "audio")) {
6332 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6333 LOGD("audio plugin is already linked");
6335 LOGW("add AUDIO to missing plugin");
6336 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6337 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6345 return MM_ERROR_NONE;
6349 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6351 mmplayer_t *player = (mmplayer_t *)data;
6355 MMPLAYER_RETURN_IF_FAIL(player);
6357 /* remove fakesink. */
6358 if (!_mmplayer_gst_remove_fakesink(player,
6359 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6360 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6361 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6362 * source element are not same. To overcome this situation, this function will called
6363 * several places and several times. Therefore, this is not an error case.
6368 LOGD("[handle: %p] pipeline has completely constructed", player);
6370 if ((player->msg_posted == FALSE) &&
6371 (player->cmd >= MMPLAYER_COMMAND_START))
6372 __mmplayer_handle_missed_plugin(player);
6374 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6378 __mmplayer_check_profile(void)
6381 static int profile_tv = -1;
6383 if (__builtin_expect(profile_tv != -1, 1))
6386 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6387 switch (*profileName) {
6402 __mmplayer_get_next_uri(mmplayer_t *player)
6404 mmplayer_parse_profile_t profile;
6406 guint num_of_list = 0;
6409 num_of_list = g_list_length(player->uri_info.uri_list);
6410 uri_idx = player->uri_info.uri_idx;
6412 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6413 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6414 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6416 LOGW("next uri does not exist");
6420 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6421 LOGE("failed to parse profile");
6425 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6426 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6427 LOGW("uri type is not supported(%d)", profile.uri_type);
6431 LOGD("success to find next uri %d", uri_idx);
6435 if (!uri || uri_idx == num_of_list) {
6436 LOGE("failed to find next uri");
6440 player->uri_info.uri_idx = uri_idx;
6441 if (mm_player_set_attribute((MMHandleType)player, NULL,
6442 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6443 LOGE("failed to set attribute");
6447 SECURE_LOGD("next playback uri: %s", uri);
6452 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6454 #define REPEAT_COUNT_INFINITE -1
6455 #define REPEAT_COUNT_MIN 2
6456 #define ORIGINAL_URI_ONLY 1
6458 MMHandleType attrs = 0;
6462 guint num_of_uri = 0;
6463 int profile_tv = -1;
6467 LOGD("checking for gapless play option");
6469 if (player->build_audio_offload) {
6470 LOGE("offload path is not supportable.");
6474 if (player->pipeline->textbin) {
6475 LOGE("subtitle path is enabled. gapless play is not supported.");
6479 attrs = MMPLAYER_GET_ATTRS(player);
6481 LOGE("fail to get attributes.");
6485 mm_attrs_multiple_get(player->attrs, NULL,
6486 "content_video_found", &video,
6487 "profile_play_count", &count,
6488 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6490 /* gapless playback is not supported in case of video at TV profile. */
6491 profile_tv = __mmplayer_check_profile();
6492 if (profile_tv && video) {
6493 LOGW("not support video gapless playback");
6497 /* check repeat count in case of audio */
6499 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6500 LOGW("gapless is disabled");
6504 num_of_uri = g_list_length(player->uri_info.uri_list);
6506 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6508 if (num_of_uri == ORIGINAL_URI_ONLY) {
6509 /* audio looping path */
6510 if (count >= REPEAT_COUNT_MIN) {
6511 /* decrease play count */
6512 /* we succeeded to rewind. update play count and then wait for next EOS */
6514 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6515 } else if (count != REPEAT_COUNT_INFINITE) {
6516 LOGD("there is no next uri and no repeat");
6519 LOGD("looping cnt %d", count);
6521 /* gapless playback path */
6522 if (!__mmplayer_get_next_uri(player)) {
6523 LOGE("failed to get next uri");
6530 LOGE("unable to play gapless path. EOS will be posted soon");
6535 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6537 GstPad *sinkpad = g_value_get_object (item);
6538 GstElement *element = GST_ELEMENT(user_data);
6539 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6540 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6544 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6546 mmplayer_gst_element_t *sinkbin = NULL;
6547 main_element_id_e concatId = MMPLAYER_M_NUM;
6548 main_element_id_e sinkId = MMPLAYER_M_NUM;
6549 gboolean send_notice = FALSE;
6550 GstElement *element;
6554 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6556 LOGD("type %d", type);
6559 case MM_PLAYER_TRACK_TYPE_AUDIO:
6560 concatId = MMPLAYER_M_A_CONCAT;
6561 sinkId = MMPLAYER_A_BIN;
6562 sinkbin = player->pipeline->audiobin;
6564 case MM_PLAYER_TRACK_TYPE_VIDEO:
6565 concatId = MMPLAYER_M_V_CONCAT;
6566 sinkId = MMPLAYER_V_BIN;
6567 sinkbin = player->pipeline->videobin;
6570 case MM_PLAYER_TRACK_TYPE_TEXT:
6571 concatId = MMPLAYER_M_T_CONCAT;
6572 sinkId = MMPLAYER_T_BIN;
6573 sinkbin = player->pipeline->textbin;
6576 LOGE("requested type is not supportable");
6581 element = player->pipeline->mainbin[concatId].gst;
6585 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6586 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6587 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6588 if (srcpad && sinkpad) {
6589 /* after getting drained signal there is no data flows, so no need to do pad_block */
6590 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6591 gst_pad_unlink(srcpad, sinkpad);
6593 /* send custom event to sink pad to handle it at video sink */
6595 LOGD("send custom event to sinkpad");
6596 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6597 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6598 gst_pad_send_event(sinkpad, event);
6601 gst_object_unref(srcpad);
6602 gst_object_unref(sinkpad);
6605 LOGD("release concat request pad");
6606 /* release and unref requests pad from the selector */
6607 iter = gst_element_iterate_sink_pads(element);
6608 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6609 gst_iterator_resync(iter);
6610 gst_iterator_free(iter);
6616 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6618 mmplayer_track_t *selector = &player->track[type];
6619 mmplayer_gst_element_t *sinkbin = NULL;
6620 main_element_id_e selectorId = MMPLAYER_M_NUM;
6621 main_element_id_e sinkId = MMPLAYER_M_NUM;
6622 GstPad *srcpad = NULL;
6623 GstPad *sinkpad = NULL;
6624 gboolean send_notice = FALSE;
6627 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6629 LOGD("type %d", type);
6632 case MM_PLAYER_TRACK_TYPE_AUDIO:
6633 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6634 sinkId = MMPLAYER_A_BIN;
6635 sinkbin = player->pipeline->audiobin;
6637 case MM_PLAYER_TRACK_TYPE_VIDEO:
6638 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6639 sinkId = MMPLAYER_V_BIN;
6640 sinkbin = player->pipeline->videobin;
6643 case MM_PLAYER_TRACK_TYPE_TEXT:
6644 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6645 sinkId = MMPLAYER_T_BIN;
6646 sinkbin = player->pipeline->textbin;
6649 LOGE("requested type is not supportable");
6654 if (player->pipeline->mainbin[selectorId].gst) {
6657 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6659 if (selector->event_probe_id != 0)
6660 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6661 selector->event_probe_id = 0;
6663 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6664 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6666 if (srcpad && sinkpad) {
6667 /* after getting drained signal there is no data flows, so no need to do pad_block */
6668 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6669 gst_pad_unlink(srcpad, sinkpad);
6671 /* send custom event to sink pad to handle it at video sink */
6673 LOGD("send custom event to sinkpad");
6674 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6675 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6676 gst_pad_send_event(sinkpad, event);
6680 gst_object_unref(sinkpad);
6683 gst_object_unref(srcpad);
6686 LOGD("selector release");
6688 /* release and unref requests pad from the selector */
6689 for (n = 0; n < selector->streams->len; n++) {
6690 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6691 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6694 g_ptr_array_set_size(selector->streams, 0);
6696 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6697 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6699 player->pipeline->mainbin[selectorId].gst = NULL;
6707 __mmplayer_deactivate_old_path(mmplayer_t *player)
6710 MMPLAYER_RETURN_IF_FAIL(player);
6712 if (MMPLAYER_USE_DECODEBIN(player)) {
6713 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6714 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6715 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6716 LOGE("deactivate selector error");
6720 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6721 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6722 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6723 LOGE("deactivate concat error");
6728 _mmplayer_track_destroy(player);
6729 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6731 if (player->streamer) {
6732 _mm_player_streaming_initialize(player->streamer, FALSE);
6733 _mm_player_streaming_destroy(player->streamer);
6734 player->streamer = NULL;
6737 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6743 if (!player->msg_posted) {
6744 MMMessageParamType msg = {0,};
6747 msg.code = MM_ERROR_PLAYER_INTERNAL;
6748 LOGE("gapless_uri_play> deactivate error");
6750 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6751 player->msg_posted = TRUE;
6757 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6759 int result = MM_ERROR_NONE;
6760 mmplayer_t *player = (mmplayer_t *)hplayer;
6763 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6764 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6766 if (mm_player_set_attribute(hplayer, NULL,
6767 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6768 LOGE("failed to set attribute");
6769 result = MM_ERROR_PLAYER_INTERNAL;
6771 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6772 LOGE("failed to add the original uri in the uri list.");
6780 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6782 mmplayer_t *player = (mmplayer_t *)hplayer;
6783 guint num_of_list = 0;
6787 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6788 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6790 if (player->pipeline && player->pipeline->textbin) {
6791 LOGE("subtitle path is enabled.");
6792 return MM_ERROR_PLAYER_INVALID_STATE;
6795 num_of_list = g_list_length(player->uri_info.uri_list);
6797 if (is_first_path) {
6798 if (num_of_list == 0) {
6799 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6800 SECURE_LOGD("add original path : %s", uri);
6802 player->uri_info.uri_list = g_list_delete_link(player->uri_info.uri_list, g_list_nth(player->uri_info.uri_list, 0));
6803 player->uri_info.uri_list = g_list_insert(player->uri_info.uri_list, g_strdup(uri), 0);
6805 SECURE_LOGD("change original path : %s", uri);
6808 MMHandleType attrs = 0;
6809 attrs = MMPLAYER_GET_ATTRS(player);
6811 if (num_of_list == 0) {
6812 char *original_uri = NULL;
6815 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6817 if (!original_uri) {
6818 LOGE("there is no original uri.");
6819 return MM_ERROR_PLAYER_INVALID_STATE;
6822 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6823 player->uri_info.uri_idx = 0;
6825 SECURE_LOGD("add original path at first : %s", original_uri);
6829 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6830 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6834 return MM_ERROR_NONE;
6838 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6840 mmplayer_t *player = (mmplayer_t *)hplayer;
6841 char *next_uri = NULL;
6842 guint num_of_list = 0;
6845 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6847 num_of_list = g_list_length(player->uri_info.uri_list);
6849 if (num_of_list > 0) {
6850 gint uri_idx = player->uri_info.uri_idx;
6852 if (uri_idx < num_of_list - 1)
6857 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6858 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6860 *uri = g_strdup(next_uri);
6864 return MM_ERROR_NONE;
6868 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6869 GstCaps *caps, gpointer data)
6871 mmplayer_t *player = (mmplayer_t *)data;
6872 const gchar *klass = NULL;
6873 const gchar *mime = NULL;
6874 gchar *caps_str = NULL;
6876 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6877 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6878 caps_str = gst_caps_to_string(caps);
6880 LOGW("unknown type of caps : %s from %s",
6881 caps_str, GST_ELEMENT_NAME(elem));
6883 MMPLAYER_FREEIF(caps_str);
6885 /* There is no available codec. */
6886 __mmplayer_check_not_supported_codec(player, klass, mime);
6890 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6891 GstCaps *caps, gpointer data)
6893 mmplayer_t *player = (mmplayer_t *)data;
6894 const char *mime = NULL;
6895 gboolean ret = TRUE;
6897 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6898 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6900 if (g_str_has_prefix(mime, "audio")) {
6901 GstStructure *caps_structure = NULL;
6902 gint samplerate = 0;
6904 gchar *caps_str = NULL;
6906 caps_structure = gst_caps_get_structure(caps, 0);
6907 gst_structure_get_int(caps_structure, "rate", &samplerate);
6908 gst_structure_get_int(caps_structure, "channels", &channels);
6910 if ((channels > 0 && samplerate == 0)) {
6911 LOGD("exclude audio...");
6915 caps_str = gst_caps_to_string(caps);
6916 /* set it directly because not sent by TAG */
6917 if (g_strrstr(caps_str, "mobile-xmf"))
6918 mm_player_set_attribute((MMHandleType)player, NULL,
6919 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6921 MMPLAYER_FREEIF(caps_str);
6922 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6923 LOGD("already video linked");
6926 LOGD("found new stream");
6933 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6935 gboolean ret = FALSE;
6936 GDBusConnection *conn = NULL;
6938 GVariant *result = NULL;
6939 const gchar *dbus_device_type = NULL;
6940 const gchar *dbus_ret = NULL;
6943 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6945 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6950 result = g_dbus_connection_call_sync(conn,
6951 "org.pulseaudio.Server",
6952 "/org/pulseaudio/StreamManager",
6953 "org.pulseaudio.StreamManager",
6954 "GetCurrentMediaRoutingPath",
6955 g_variant_new("(s)", "out"),
6956 G_VARIANT_TYPE("(ss)"),
6957 G_DBUS_CALL_FLAGS_NONE,
6961 if (!result || err) {
6962 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6967 /* device type is listed in stream-map.json at mmfw-sysconf */
6968 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6970 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6971 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6974 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6975 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6976 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6977 LOGD("audio offload is supportable");
6983 LOGD("audio offload is not supportable");
6986 g_variant_unref(result);
6988 g_object_unref(conn);
6993 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6995 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6996 gint64 position = 0;
6998 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6999 player->pipeline && player->pipeline->mainbin);
7001 MMPLAYER_CMD_LOCK(player);
7002 current_state = MMPLAYER_CURRENT_STATE(player);
7004 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
7005 LOGW("getting current position failed in paused");
7007 _mmplayer_unrealize((MMHandleType)player);
7008 _mmplayer_realize((MMHandleType)player);
7010 _mmplayer_set_position((MMHandleType)player, position);
7012 /* async not to be blocked in streaming case */
7013 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7015 _mmplayer_pause((MMHandleType)player);
7017 if (current_state == MM_PLAYER_STATE_PLAYING)
7018 _mmplayer_start((MMHandleType)player);
7019 MMPLAYER_CMD_UNLOCK(player);
7021 LOGD("rebuilding audio pipeline is completed.");
7024 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7026 mmplayer_t *player = (mmplayer_t *)user_data;
7027 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7028 gboolean is_supportable = FALSE;
7030 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7031 LOGW("failed to get device type");
7033 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7035 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7036 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7037 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7038 LOGD("ignore this dev connected info");
7042 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7043 if (player->build_audio_offload == is_supportable) {
7044 LOGD("keep current pipeline without re-building");
7048 /* rebuild pipeline */
7049 LOGD("re-build pipeline - offload: %d", is_supportable);
7050 player->build_audio_offload = FALSE;
7051 __mmplayer_rebuild_audio_pipeline(player);
7057 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7059 unsigned int id = 0;
7061 if (player->audio_device_cb_id != 0) {
7062 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7066 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7067 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7068 LOGD("added device connected cb (%u)", id);
7069 player->audio_device_cb_id = id;
7071 LOGW("failed to add device connected cb");
7078 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7080 mmplayer_t *player = (mmplayer_t *)hplayer;
7083 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7084 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7086 *activated = player->build_audio_offload;
7088 LOGD("offload activated : %d", (int)*activated);
7091 return MM_ERROR_NONE;
7095 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7098 this function need to be updated according to the supported media format
7099 @see player->ini.audio_offload_media_format */
7101 if (__mmplayer_is_only_mp3_type(player->type)) {
7102 LOGD("offload supportable media format type");
7110 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7112 gboolean ret = FALSE;
7113 GstElementFactory *factory = NULL;
7116 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7118 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7119 if (!__mmplayer_is_offload_supported_type(player))
7122 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7123 LOGD("there is no audio offload sink");
7127 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7128 LOGW("there is no audio device type to support offload");
7132 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7134 LOGW("there is no installed audio offload sink element");
7137 gst_object_unref(factory);
7139 if (_mmplayer_acquire_hw_resource(player,
7140 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7141 LOGE("failed to acquire audio offload decoder resource");
7145 if (!__mmplayer_add_audio_device_connected_cb(player))
7148 if (!__mmplayer_is_audio_offload_device_type(player))
7151 LOGD("audio offload can be built");
7156 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7162 static GstAutoplugSelectResult
7163 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7165 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7166 int audio_offload = 0;
7168 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7169 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7171 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7172 LOGD("expose audio path to build offload output path");
7173 player->build_audio_offload = TRUE;
7174 /* update codec info */
7175 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7176 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7177 player->audiodec_linked = 1;
7179 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7183 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7184 And need to consider the multi-track audio content.
7185 There is no HW audio decoder in public. */
7187 /* set stream information */
7188 if (!player->audiodec_linked)
7189 _mmplayer_set_audio_attrs(player, caps);
7191 /* update codec info */
7192 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7193 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7194 player->audiodec_linked = 1;
7196 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7198 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7199 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7201 /* mark video decoder for acquire */
7202 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7203 LOGW("video decoder resource is already acquired, skip it.");
7204 ret = GST_AUTOPLUG_SELECT_SKIP;
7208 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7209 LOGE("failed to acquire video decoder resource");
7210 ret = GST_AUTOPLUG_SELECT_SKIP;
7213 player->interrupted_by_resource = FALSE;
7216 /* update codec info */
7217 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7218 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7219 player->videodec_linked = 1;
7227 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7228 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7230 #define DEFAULT_IDX 0xFFFF
7231 #define MIN_FACTORY_NUM 2
7232 mmplayer_t *player = (mmplayer_t *)data;
7233 GValueArray *new_factories = NULL;
7234 GValue val = { 0, };
7235 GstElementFactory *factory = NULL;
7236 const gchar *klass = NULL;
7237 gchar *factory_name = NULL;
7238 guint hw_dec_idx = DEFAULT_IDX;
7239 guint first_sw_dec_idx = DEFAULT_IDX;
7240 guint last_sw_dec_idx = DEFAULT_IDX;
7241 guint new_pos = DEFAULT_IDX;
7242 guint rm_pos = DEFAULT_IDX;
7243 int audio_codec_type;
7244 int video_codec_type;
7245 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7247 if (factories->n_values < MIN_FACTORY_NUM)
7250 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7251 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7254 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7256 for (int i = 0 ; i < factories->n_values ; i++) {
7257 gchar *hw_dec_info = NULL;
7258 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7260 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7262 LOGW("failed to get factory object");
7265 klass = gst_element_factory_get_klass(factory);
7266 factory_name = GST_OBJECT_NAME(factory);
7269 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7271 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7272 if (!player->need_audio_dec_sorting) {
7273 LOGD("sorting is not required");
7276 codec_type = audio_codec_type;
7277 hw_dec_info = player->ini.audiocodec_element_hw;
7278 sw_dec_info = player->ini.audiocodec_element_sw;
7279 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7280 if (!player->need_video_dec_sorting) {
7281 LOGD("sorting is not required");
7284 codec_type = video_codec_type;
7285 hw_dec_info = player->ini.videocodec_element_hw;
7286 sw_dec_info = player->ini.videocodec_element_sw;
7291 if (g_strrstr(factory_name, hw_dec_info)) {
7294 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7295 if (strstr(factory_name, sw_dec_info[j])) {
7296 last_sw_dec_idx = i;
7297 if (first_sw_dec_idx == DEFAULT_IDX) {
7298 first_sw_dec_idx = i;
7303 if (first_sw_dec_idx == DEFAULT_IDX)
7304 LOGW("unknown codec %s", factory_name);
7308 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7311 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7312 if (hw_dec_idx < first_sw_dec_idx)
7314 new_pos = first_sw_dec_idx;
7315 rm_pos = hw_dec_idx + 1;
7316 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7317 if (last_sw_dec_idx < hw_dec_idx)
7319 new_pos = last_sw_dec_idx + 1;
7320 rm_pos = hw_dec_idx;
7325 /* change position - insert H/W decoder according to the new position */
7326 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7328 LOGW("failed to get factory object");
7331 new_factories = g_value_array_copy(factories);
7332 g_value_init (&val, G_TYPE_OBJECT);
7333 g_value_set_object (&val, factory);
7334 g_value_array_insert(new_factories, new_pos, &val);
7335 g_value_unset (&val);
7336 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7338 for (int i = 0 ; i < new_factories->n_values ; i++) {
7339 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7341 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7342 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7344 LOGE("[Re-arranged] failed to get factory object");
7347 return new_factories;
7351 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7352 GstCaps *caps, GstElementFactory *factory, gpointer data)
7354 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7355 mmplayer_t *player = (mmplayer_t *)data;
7357 gchar *factory_name = NULL;
7358 gchar *caps_str = NULL;
7359 const gchar *klass = NULL;
7362 factory_name = GST_OBJECT_NAME(factory);
7363 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7364 caps_str = gst_caps_to_string(caps);
7366 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7368 /* store type string */
7369 if (player->type == NULL) {
7370 player->type = gst_caps_to_string(caps);
7371 __mmplayer_update_content_type_info(player);
7374 /* filtering exclude keyword */
7375 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7376 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7377 LOGW("skipping [%s] by exculde keyword [%s]",
7378 factory_name, player->ini.exclude_element_keyword[idx]);
7380 result = GST_AUTOPLUG_SELECT_SKIP;
7385 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7386 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7387 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7388 factory_name, player->ini.unsupported_codec_keyword[idx]);
7389 result = GST_AUTOPLUG_SELECT_SKIP;
7394 /* exclude webm format */
7395 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7396 * because webm format is not supportable.
7397 * If webm is disabled in "autoplug-continue", there is no state change
7398 * failure or error because the decodebin will expose the pad directly.
7399 * It make MSL invoke _prepare_async_callback.
7400 * So, we need to disable webm format in "autoplug-select" */
7401 if (caps_str && strstr(caps_str, "webm")) {
7402 LOGW("webm is not supported");
7403 result = GST_AUTOPLUG_SELECT_SKIP;
7407 /* check factory class for filtering */
7408 /* NOTE : msl don't need to use image plugins.
7409 * So, those plugins should be skipped for error handling.
7411 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7412 LOGD("skipping [%s] by not required", factory_name);
7413 result = GST_AUTOPLUG_SELECT_SKIP;
7417 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7418 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7419 // TO CHECK : subtitle if needed, add subparse exception.
7420 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7421 result = GST_AUTOPLUG_SELECT_SKIP;
7425 if (g_strrstr(factory_name, "mpegpsdemux")) {
7426 LOGD("skipping PS container - not support");
7427 result = GST_AUTOPLUG_SELECT_SKIP;
7431 if (g_strrstr(factory_name, "mssdemux"))
7432 player->smooth_streaming = TRUE;
7434 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7435 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7438 GstStructure *str = NULL;
7439 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7441 /* don't make video because of not required */
7442 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7443 (!player->set_mode.video_export)) {
7444 LOGD("no need video decoding, expose pad");
7445 result = GST_AUTOPLUG_SELECT_EXPOSE;
7449 /* get w/h for omx state-tune */
7450 /* FIXME: deprecated? */
7451 str = gst_caps_get_structure(caps, 0);
7452 gst_structure_get_int(str, "width", &width);
7455 if (player->v_stream_caps) {
7456 gst_caps_unref(player->v_stream_caps);
7457 player->v_stream_caps = NULL;
7460 player->v_stream_caps = gst_caps_copy(caps);
7461 LOGD("take caps for video state tune");
7462 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7466 if (g_strrstr(klass, "Codec/Decoder")) {
7467 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7468 if (result != GST_AUTOPLUG_SELECT_TRY) {
7469 LOGW("skip add decoder");
7475 MMPLAYER_FREEIF(caps_str);
7481 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7484 //mmplayer_t *player = (mmplayer_t *)data;
7485 GstCaps *caps = NULL;
7487 LOGD("[Decodebin2] pad-removed signal");
7489 caps = gst_pad_query_caps(new_pad, NULL);
7491 LOGW("query caps is NULL");
7495 gchar *caps_str = NULL;
7496 caps_str = gst_caps_to_string(caps);
7498 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7500 MMPLAYER_FREEIF(caps_str);
7501 gst_caps_unref(caps);
7505 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7507 mmplayer_t *player = (mmplayer_t *)data;
7510 MMPLAYER_RETURN_IF_FAIL(player);
7512 LOGD("got about to finish signal");
7514 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7515 LOGW("Fail to get cmd lock");
7519 if (!__mmplayer_verify_gapless_play_path(player)) {
7520 LOGD("decoding is finished.");
7521 MMPLAYER_CMD_UNLOCK(player);
7525 _mmplayer_set_reconfigure_state(player, TRUE);
7526 MMPLAYER_CMD_UNLOCK(player);
7528 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL);
7529 __mmplayer_deactivate_old_path(player);
7535 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7537 mmplayer_t *player = (mmplayer_t *)data;
7538 GstIterator *iter = NULL;
7539 GValue item = { 0, };
7541 gboolean done = FALSE;
7542 gboolean is_all_drained = TRUE;
7545 MMPLAYER_RETURN_IF_FAIL(player);
7547 LOGD("got drained signal");
7549 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7550 LOGW("Fail to get cmd lock");
7554 if (!__mmplayer_verify_gapless_play_path(player)) {
7555 LOGD("decoding is finished.");
7556 MMPLAYER_CMD_UNLOCK(player);
7560 _mmplayer_set_reconfigure_state(player, TRUE);
7561 MMPLAYER_CMD_UNLOCK(player);
7563 /* check decodebin src pads whether they received EOS or not */
7564 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7567 switch (gst_iterator_next(iter, &item)) {
7568 case GST_ITERATOR_OK:
7569 pad = g_value_get_object(&item);
7570 if (pad && !GST_PAD_IS_EOS(pad)) {
7571 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7572 is_all_drained = FALSE;
7575 g_value_reset(&item);
7577 case GST_ITERATOR_RESYNC:
7578 gst_iterator_resync(iter);
7580 case GST_ITERATOR_ERROR:
7581 case GST_ITERATOR_DONE:
7586 g_value_unset(&item);
7587 gst_iterator_free(iter);
7589 if (!is_all_drained) {
7590 LOGD("Wait util the all pads get EOS.");
7595 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7596 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7598 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7599 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7600 __mmplayer_deactivate_old_path(player);
7606 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7608 mmplayer_t *player = (mmplayer_t *)data;
7609 const gchar *klass = NULL;
7610 gchar *factory_name = NULL;
7612 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7613 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7615 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7617 if (__mmplayer_add_dump_buffer_probe(player, element))
7618 LOGD("add buffer probe");
7620 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7621 gchar *selected = NULL;
7622 selected = g_strdup(GST_ELEMENT_NAME(element));
7623 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7625 /* update codec info */
7626 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7627 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7628 player->audiodec_linked = 1;
7629 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7630 /* update codec info */
7631 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7632 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7633 player->videodec_linked = 1;
7636 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7637 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7638 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7640 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7641 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7643 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7644 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7645 "max-video-width", player->adaptive_info.limit.width,
7646 "max-video-height", player->adaptive_info.limit.height, NULL);
7648 } else if (g_strrstr(klass, "Demuxer")) {
7650 LOGD("plugged element is demuxer. take it");
7652 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7653 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7656 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7657 int surface_type = 0;
7659 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7662 // to support trust-zone only
7663 if (g_strrstr(factory_name, "asfdemux")) {
7664 LOGD("set file-location %s", player->profile.uri);
7665 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7666 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7667 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7668 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7669 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7670 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7671 (__mmplayer_is_only_mp3_type(player->type))) {
7672 LOGD("[mpegaudioparse] set streaming pull mode.");
7673 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7675 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7676 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7679 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7680 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7681 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7683 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7684 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7686 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7687 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7688 (MMPLAYER_IS_DASH_STREAMING(player))) {
7689 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7690 _mm_player_streaming_set_multiqueue(player->streamer, element);
7691 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7700 __mmplayer_release_misc(mmplayer_t *player)
7703 bool cur_mode = player->set_mode.rich_audio;
7706 MMPLAYER_RETURN_IF_FAIL(player);
7708 player->sent_bos = FALSE;
7709 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7711 player->seek_state = MMPLAYER_SEEK_NONE;
7713 player->total_bitrate = 0;
7714 player->total_maximum_bitrate = 0;
7716 player->not_found_demuxer = 0;
7718 player->last_position = 0;
7719 player->duration = 0;
7720 player->http_content_size = 0;
7721 player->not_supported_codec = MISSING_PLUGIN_NONE;
7722 player->can_support_codec = FOUND_PLUGIN_NONE;
7723 player->pending_seek.is_pending = false;
7724 player->pending_seek.pos = 0;
7725 player->msg_posted = FALSE;
7726 player->has_many_types = FALSE;
7727 player->is_subtitle_force_drop = FALSE;
7728 player->play_subtitle = FALSE;
7729 player->adjust_subtitle_pos = 0;
7730 player->has_closed_caption = FALSE;
7731 player->set_mode.video_export = false;
7732 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7733 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7735 player->set_mode.rich_audio = cur_mode;
7737 if (player->audio_device_cb_id > 0 &&
7738 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7739 LOGW("failed to remove audio device_connected_callback");
7740 player->audio_device_cb_id = 0;
7742 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7743 player->bitrate[i] = 0;
7744 player->maximum_bitrate[i] = 0;
7747 /* free memory related to audio effect */
7748 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7750 if (player->adaptive_info.var_list) {
7751 g_list_free_full(player->adaptive_info.var_list, g_free);
7752 player->adaptive_info.var_list = NULL;
7755 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7756 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7757 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7759 /* Reset video360 settings to their defaults in case if the pipeline is to be
7762 player->video360_metadata.is_spherical = -1;
7763 player->is_openal_plugin_used = FALSE;
7765 player->is_content_spherical = FALSE;
7766 player->is_video360_enabled = TRUE;
7767 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7768 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7769 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7770 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7771 player->video360_zoom = 1.0f;
7772 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7773 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7775 player->sound.rg_enable = false;
7777 __mmplayer_initialize_video_roi(player);
7782 __mmplayer_release_misc_post(mmplayer_t *player)
7784 char *original_uri = NULL;
7787 /* player->pipeline is already released before. */
7788 MMPLAYER_RETURN_IF_FAIL(player);
7790 player->video_decoded_cb = NULL;
7791 player->video_decoded_cb_user_param = NULL;
7792 player->video_stream_prerolled = false;
7794 player->audio_decoded_cb = NULL;
7795 player->audio_decoded_cb_user_param = NULL;
7796 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7798 player->audio_stream_changed_cb = NULL;
7799 player->audio_stream_changed_cb_user_param = NULL;
7801 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7803 /* clean found audio decoders */
7804 if (player->audio_decoders) {
7805 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7806 player->audio_decoders = NULL;
7809 /* clean the uri list except original uri */
7810 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7812 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7813 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7814 g_list_free_full(tmp, (GDestroyNotify)g_free);
7817 LOGW("failed to get original uri info");
7819 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7820 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7824 /* clear the audio stream buffer list */
7825 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7827 /* clear the video stream bo list */
7828 __mmplayer_video_stream_destroy_bo_list(player);
7829 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7831 if (player->profile.input_mem.buf) {
7832 free(player->profile.input_mem.buf);
7833 player->profile.input_mem.buf = NULL;
7835 player->profile.input_mem.len = 0;
7836 player->profile.input_mem.offset = 0;
7838 player->uri_info.uri_idx = 0;
7843 __mmplayer_check_subtitle(mmplayer_t *player)
7845 MMHandleType attrs = 0;
7846 char *subtitle_uri = NULL;
7850 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7852 /* get subtitle attribute */
7853 attrs = MMPLAYER_GET_ATTRS(player);
7857 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7858 if (!subtitle_uri || !strlen(subtitle_uri))
7861 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7862 player->is_external_subtitle_present = TRUE;
7870 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7872 MMPLAYER_RETURN_IF_FAIL(player);
7874 if (player->eos_timer) {
7875 LOGD("cancel eos timer");
7876 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7877 player->eos_timer = 0;
7884 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7888 MMPLAYER_RETURN_IF_FAIL(player);
7889 MMPLAYER_RETURN_IF_FAIL(sink);
7892 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7894 player->sink_elements = g_list_append(player->sink_elements, sink);
7900 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7904 MMPLAYER_RETURN_IF_FAIL(player);
7905 MMPLAYER_RETURN_IF_FAIL(sink);
7907 player->sink_elements = g_list_remove(player->sink_elements, sink);
7913 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7914 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7916 mmplayer_signal_item_t *item = NULL;
7919 MMPLAYER_RETURN_IF_FAIL(player);
7921 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7922 LOGE("invalid signal type [%d]", type);
7926 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7928 LOGE("cannot connect signal [%s]", signal);
7933 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7934 player->signals[type] = g_list_append(player->signals[type], item);
7940 /* NOTE : be careful with calling this api. please refer to below glib comment
7941 * glib comment : Note that there is a bug in GObject that makes this function much
7942 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7943 * will no longer be called, but, the signal handler is not currently disconnected.
7944 * If the instance is itself being freed at the same time than this doesn't matter,
7945 * since the signal will automatically be removed, but if instance persists,
7946 * then the signal handler will leak. You should not remove the signal yourself
7947 * because in a future versions of GObject, the handler will automatically be
7950 * It's possible to work around this problem in a way that will continue to work
7951 * with future versions of GObject by checking that the signal handler is still
7952 * connected before disconnected it:
7954 * if (g_signal_handler_is_connected(instance, id))
7955 * g_signal_handler_disconnect(instance, id);
7958 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7960 GList *sig_list = NULL;
7961 mmplayer_signal_item_t *item = NULL;
7965 MMPLAYER_RETURN_IF_FAIL(player);
7967 LOGD("release signals type : %d", type);
7969 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7970 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7971 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7972 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7973 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7974 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7978 sig_list = player->signals[type];
7980 for (; sig_list; sig_list = sig_list->next) {
7981 item = sig_list->data;
7983 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7984 if (g_signal_handler_is_connected(item->obj, item->sig))
7985 g_signal_handler_disconnect(item->obj, item->sig);
7988 MMPLAYER_FREEIF(item);
7991 g_list_free(player->signals[type]);
7992 player->signals[type] = NULL;
8000 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
8002 mmplayer_t *player = 0;
8003 int prev_display_surface_type = 0;
8007 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
8009 player = MM_PLAYER_CAST(handle);
8011 /* check video sinkbin is created */
8012 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
8013 LOGW("Videosink is already created");
8014 return MM_ERROR_NONE;
8017 LOGD("videosink element is not yet ready");
8019 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8020 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8022 return MM_ERROR_INVALID_ARGUMENT;
8025 /* load previous attributes */
8026 if (player->attrs) {
8027 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8028 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8029 if (prev_display_surface_type == surface_type) {
8030 LOGD("incoming display surface type is same as previous one, do nothing..");
8032 return MM_ERROR_NONE;
8035 LOGE("failed to load attributes");
8037 return MM_ERROR_PLAYER_INTERNAL;
8040 /* videobin is not created yet, so we just set attributes related to display surface */
8041 LOGD("store display attribute for given surface type(%d)", surface_type);
8042 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8043 "display_overlay", wl_surface_id, NULL);
8046 return MM_ERROR_NONE;
8049 /* Note : if silent is true, then subtitle would not be displayed. :*/
8051 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8053 mmplayer_t *player = (mmplayer_t *)hplayer;
8057 /* check player handle */
8058 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8060 player->set_mode.subtitle_off = silent;
8062 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8066 return MM_ERROR_NONE;
8070 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8072 mmplayer_gst_element_t *mainbin = NULL;
8073 mmplayer_gst_element_t *textbin = NULL;
8074 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8075 GstState current_state = GST_STATE_VOID_PENDING;
8076 GstState element_state = GST_STATE_VOID_PENDING;
8077 GstState element_pending_state = GST_STATE_VOID_PENDING;
8079 GstEvent *event = NULL;
8080 int result = MM_ERROR_NONE;
8082 GstClock *curr_clock = NULL;
8083 GstClockTime base_time, start_time, curr_time;
8088 /* check player handle */
8089 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8091 player->pipeline->mainbin &&
8092 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8094 mainbin = player->pipeline->mainbin;
8095 textbin = player->pipeline->textbin;
8097 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8099 // sync clock with current pipeline
8100 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8101 curr_time = gst_clock_get_time(curr_clock);
8103 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8104 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8106 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8107 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8109 if (current_state > GST_STATE_READY) {
8110 // sync state with current pipeline
8111 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8112 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8113 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8115 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8116 if (GST_STATE_CHANGE_FAILURE == ret) {
8117 LOGE("fail to state change.");
8118 result = MM_ERROR_PLAYER_INTERNAL;
8122 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8123 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8126 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8127 gst_object_unref(curr_clock);
8130 // seek to current position
8131 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8132 result = MM_ERROR_PLAYER_INVALID_STATE;
8133 LOGE("gst_element_query_position failed, invalid state");
8137 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8138 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);
8140 _mmplayer_gst_send_event_to_sink(player, event);
8142 result = MM_ERROR_PLAYER_INTERNAL;
8143 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8147 /* sync state with current pipeline */
8148 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8149 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8150 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8152 return MM_ERROR_NONE;
8155 /* release text pipeline resource */
8156 player->textsink_linked = 0;
8158 /* release signal */
8159 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8161 /* release textbin with it's childs */
8162 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8163 MMPLAYER_FREEIF(player->pipeline->textbin);
8164 player->pipeline->textbin = NULL;
8166 /* release subtitle elem */
8167 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8168 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8174 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8176 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8177 GstState current_state = GST_STATE_VOID_PENDING;
8179 MMHandleType attrs = 0;
8180 mmplayer_gst_element_t *mainbin = NULL;
8181 mmplayer_gst_element_t *textbin = NULL;
8183 gchar *subtitle_uri = NULL;
8184 int result = MM_ERROR_NONE;
8185 const gchar *charset = NULL;
8189 /* check player handle */
8190 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8192 player->pipeline->mainbin &&
8193 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8194 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8196 mainbin = player->pipeline->mainbin;
8197 textbin = player->pipeline->textbin;
8199 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8200 if (current_state < GST_STATE_READY) {
8201 result = MM_ERROR_PLAYER_INVALID_STATE;
8202 LOGE("Pipeline is not in proper state");
8206 attrs = MMPLAYER_GET_ATTRS(player);
8208 LOGE("cannot get content attribute");
8209 result = MM_ERROR_PLAYER_INTERNAL;
8213 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8214 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8215 LOGE("subtitle uri is not proper filepath");
8216 result = MM_ERROR_PLAYER_INVALID_URI;
8220 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8221 LOGE("failed to get storage info of subtitle path");
8222 result = MM_ERROR_PLAYER_INVALID_URI;
8226 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8227 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8229 if (!strcmp(filepath, subtitle_uri)) {
8230 LOGD("subtitle path is not changed");
8233 if (mm_player_set_attribute((MMHandleType)player, NULL,
8234 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8235 LOGE("failed to set attribute");
8240 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8241 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8242 player->subtitle_language_list = NULL;
8243 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8245 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8246 if (ret != GST_STATE_CHANGE_SUCCESS) {
8247 LOGE("failed to change state of textbin to READY");
8248 result = MM_ERROR_PLAYER_INTERNAL;
8252 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8253 if (ret != GST_STATE_CHANGE_SUCCESS) {
8254 LOGE("failed to change state of subparse to READY");
8255 result = MM_ERROR_PLAYER_INTERNAL;
8259 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8260 if (ret != GST_STATE_CHANGE_SUCCESS) {
8261 LOGE("failed to change state of filesrc to READY");
8262 result = MM_ERROR_PLAYER_INTERNAL;
8266 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8268 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8270 charset = _mmplayer_get_charset(filepath);
8272 LOGD("detected charset is %s", charset);
8273 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8276 result = _mmplayer_sync_subtitle_pipeline(player);
8283 /* API to switch between external subtitles */
8285 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8287 int result = MM_ERROR_NONE;
8288 mmplayer_t *player = (mmplayer_t *)hplayer;
8293 /* check player handle */
8294 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8296 /* filepath can be null in idle state */
8298 /* check file path */
8299 if ((path = strstr(filepath, "file://")))
8300 result = _mmplayer_exist_file_path(path + 7);
8302 result = _mmplayer_exist_file_path(filepath);
8304 if (result != MM_ERROR_NONE) {
8305 LOGE("invalid subtitle path 0x%X", result);
8306 return result; /* file not found or permission denied */
8310 if (!player->pipeline) {
8312 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8313 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8314 LOGE("failed to set attribute");
8315 return MM_ERROR_PLAYER_INTERNAL;
8318 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8319 /* check filepath */
8320 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8322 if (!__mmplayer_check_subtitle(player)) {
8323 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8324 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8325 LOGE("failed to set attribute");
8326 return MM_ERROR_PLAYER_INTERNAL;
8329 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8330 LOGE("fail to create text pipeline");
8331 return MM_ERROR_PLAYER_INTERNAL;
8334 result = _mmplayer_sync_subtitle_pipeline(player);
8336 result = __mmplayer_change_external_subtitle_language(player, filepath);
8339 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8340 player->is_external_subtitle_added_now = TRUE;
8342 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8343 if (!player->subtitle_language_list) {
8344 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8345 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8346 LOGW("subtitle language list is not updated yet");
8348 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8356 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8358 guint active_idx = 0;
8359 GstStream *stream = NULL;
8360 GList *streams = NULL;
8361 GstEvent *ev = NULL;
8362 GstCaps *caps = NULL;
8364 LOGD("Switching Streams... type: %d, index: %d", type, index);
8366 player->track[type].active_track_index = index;
8368 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8369 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8370 if (player->track[i].total_track_num > 0) {
8371 active_idx = player->track[i].active_track_index;
8372 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8373 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8374 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8376 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8377 caps = gst_stream_get_caps(stream);
8379 _mmplayer_set_audio_attrs(player, caps);
8380 gst_caps_unref(caps);
8386 ev = gst_event_new_select_streams(streams);
8387 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8388 g_list_free(streams);
8390 return MM_ERROR_NONE;
8394 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8396 int result = MM_ERROR_NONE;
8397 gchar *change_pad_name = NULL;
8398 GstPad *sinkpad = NULL;
8399 mmplayer_gst_element_t *mainbin = NULL;
8400 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8401 GstCaps *caps = NULL;
8402 gint total_track_num = 0;
8406 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8407 MM_ERROR_PLAYER_NOT_INITIALIZED);
8409 LOGD("Change Track(%d) to %d", type, index);
8411 mainbin = player->pipeline->mainbin;
8413 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8414 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8415 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8416 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8418 /* Changing Video Track is not supported. */
8419 LOGE("Track Type Error");
8423 if (mainbin[elem_idx].gst == NULL) {
8424 result = MM_ERROR_PLAYER_NO_OP;
8425 LOGD("Req track doesn't exist");
8429 total_track_num = player->track[type].total_track_num;
8430 if (total_track_num <= 0) {
8431 result = MM_ERROR_PLAYER_NO_OP;
8432 LOGD("Language list is not available");
8436 if ((index < 0) || (index >= total_track_num)) {
8437 result = MM_ERROR_INVALID_ARGUMENT;
8438 LOGD("Not a proper index : %d", index);
8442 /*To get the new pad from the selector*/
8443 change_pad_name = g_strdup_printf("sink_%u", index);
8444 if (change_pad_name == NULL) {
8445 result = MM_ERROR_PLAYER_INTERNAL;
8446 LOGD("Pad does not exists");
8450 LOGD("new active pad name: %s", change_pad_name);
8452 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8453 if (sinkpad == NULL) {
8454 LOGD("sinkpad is NULL");
8455 result = MM_ERROR_PLAYER_INTERNAL;
8459 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8460 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8462 caps = gst_pad_get_current_caps(sinkpad);
8463 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8466 gst_object_unref(sinkpad);
8468 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8469 _mmplayer_set_audio_attrs(player, caps);
8472 gst_caps_unref(caps);
8475 MMPLAYER_FREEIF(change_pad_name);
8480 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8482 int result = MM_ERROR_NONE;
8483 mmplayer_t *player = NULL;
8484 mmplayer_gst_element_t *mainbin = NULL;
8486 gint current_active_index = 0;
8488 GstState current_state = GST_STATE_VOID_PENDING;
8493 player = (mmplayer_t *)hplayer;
8494 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8496 if (!player->pipeline) {
8497 LOGE("Track %d pre setting -> %d", type, index);
8499 player->track[type].active_track_index = index;
8503 mainbin = player->pipeline->mainbin;
8505 current_active_index = player->track[type].active_track_index;
8507 /*If index is same as running index no need to change the pad*/
8508 if (current_active_index == index)
8511 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8512 result = MM_ERROR_PLAYER_INVALID_STATE;
8516 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8517 if (current_state < GST_STATE_PAUSED) {
8518 result = MM_ERROR_PLAYER_INVALID_STATE;
8519 LOGW("Pipeline not in porper state");
8523 if (MMPLAYER_USE_DECODEBIN(player))
8524 result = __mmplayer_change_selector_pad(player, type, index);
8526 result = __mmplayer_switch_stream(player, type, index);
8528 if (result != MM_ERROR_NONE) {
8529 LOGE("failed to change track");
8533 player->track[type].active_track_index = index;
8535 if (MMPLAYER_USE_DECODEBIN(player)) {
8536 GstEvent *event = NULL;
8537 if (current_state == GST_STATE_PLAYING) {
8538 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8539 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8540 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8542 _mmplayer_gst_send_event_to_sink(player, event);
8544 result = MM_ERROR_PLAYER_INTERNAL;
8555 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8557 mmplayer_t *player = (mmplayer_t *)hplayer;
8561 /* check player handle */
8562 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8564 *silent = player->set_mode.subtitle_off;
8566 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8570 return MM_ERROR_NONE;
8574 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8576 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8577 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8579 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8580 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8584 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8585 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8586 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8587 mmplayer_dump_t *dump_s;
8588 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8589 if (dump_s == NULL) {
8590 LOGE("malloc fail");
8594 dump_s->dump_element_file = NULL;
8595 dump_s->dump_pad = NULL;
8596 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8598 if (dump_s->dump_pad) {
8599 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8600 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]);
8601 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8602 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);
8603 /* add list for removed buffer probe and close FILE */
8604 player->dump_list = g_list_append(player->dump_list, dump_s);
8605 LOGD("%s sink pad added buffer probe for dump", factory_name);
8608 MMPLAYER_FREEIF(dump_s);
8609 LOGE("failed to get %s sink pad added", factory_name);
8616 static GstPadProbeReturn
8617 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8619 FILE *dump_data = (FILE *)u_data;
8621 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8622 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8624 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8626 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8628 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8630 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8632 gst_buffer_unmap(buffer, &probe_info);
8634 return GST_PAD_PROBE_OK;
8638 __mmplayer_release_dump_list(GList *dump_list)
8640 GList *d_list = dump_list;
8645 for (; d_list; d_list = g_list_next(d_list)) {
8646 mmplayer_dump_t *dump_s = d_list->data;
8647 if (dump_s->dump_pad) {
8648 if (dump_s->probe_handle_id)
8649 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8650 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8652 if (dump_s->dump_element_file) {
8653 fclose(dump_s->dump_element_file);
8654 dump_s->dump_element_file = NULL;
8656 MMPLAYER_FREEIF(dump_s);
8658 g_list_free(dump_list);
8663 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8665 mmplayer_t *player = (mmplayer_t *)hplayer;
8669 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8670 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8672 *exist = (bool)player->has_closed_caption;
8676 return MM_ERROR_NONE;
8680 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8685 LOGD("unref internal gst buffer %p", buffer);
8687 gst_buffer_unref((GstBuffer *)buffer);
8694 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8696 mmplayer_t *player = (mmplayer_t *)hplayer;
8700 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8701 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8703 if (MMPLAYER_IS_STREAMING(player))
8704 *timeout = (int)player->ini.live_state_change_timeout;
8706 *timeout = (int)player->ini.localplayback_state_change_timeout;
8708 LOGD("timeout = %d", *timeout);
8711 return MM_ERROR_NONE;
8715 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8719 MMPLAYER_RETURN_IF_FAIL(player);
8721 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8723 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8724 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8725 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8726 player->storage_info[i].id = -1;
8727 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8729 if (path_type != MMPLAYER_PATH_MAX)
8738 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8740 int ret = MM_ERROR_NONE;
8741 mmplayer_t *player = (mmplayer_t *)hplayer;
8742 MMMessageParamType msg_param = {0, };
8745 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8747 LOGW("state changed storage %d:%d", id, state);
8749 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8750 return MM_ERROR_NONE;
8752 /* FIXME: text path should be handled seperately. */
8753 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8754 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8755 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8756 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8757 LOGW("external storage is removed");
8759 if (player->msg_posted == FALSE) {
8760 memset(&msg_param, 0, sizeof(MMMessageParamType));
8761 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8762 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8763 player->msg_posted = TRUE;
8766 /* unrealize the player */
8767 ret = _mmplayer_unrealize(hplayer);
8768 if (ret != MM_ERROR_NONE)
8769 LOGE("failed to unrealize");
8777 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8779 int ret = MM_ERROR_NONE;
8780 mmplayer_t *player = (mmplayer_t *)hplayer;
8781 int idx = 0, total = 0;
8782 gchar *result = NULL, *tmp = NULL;
8785 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8786 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8788 total = *num = g_list_length(player->adaptive_info.var_list);
8790 LOGW("There is no stream variant info.");
8794 result = g_strdup("");
8795 for (idx = 0 ; idx < total ; idx++) {
8796 stream_variant_t *v_data = NULL;
8797 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8800 gchar data[64] = {0};
8801 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8803 tmp = g_strconcat(result, data, NULL);
8807 LOGW("There is no variant data in %d", idx);
8812 *var_info = (char *)result;
8814 LOGD("variant info %d:%s", *num, *var_info);
8820 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8822 int ret = MM_ERROR_NONE;
8823 mmplayer_t *player = (mmplayer_t *)hplayer;
8826 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8828 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8830 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8831 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8832 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8834 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8835 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8836 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8837 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8839 /* FIXME: seek to current position for applying new variant limitation */
8848 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8850 int ret = MM_ERROR_NONE;
8851 mmplayer_t *player = (mmplayer_t *)hplayer;
8854 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8855 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8857 *bandwidth = player->adaptive_info.limit.bandwidth;
8858 *width = player->adaptive_info.limit.width;
8859 *height = player->adaptive_info.limit.height;
8861 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8868 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8870 int ret = MM_ERROR_NONE;
8871 mmplayer_t *player = (mmplayer_t *)hplayer;
8874 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8875 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8876 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8878 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8880 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8881 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8882 else /* live case */
8883 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8885 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8892 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8894 #define IDX_FIRST_SW_CODEC 0
8895 mmplayer_t *player = (mmplayer_t *)hplayer;
8896 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8897 const char *attr_name = NULL;
8898 const char *default_type = NULL;
8899 const char *element_hw = NULL;
8900 const char *element_sw = NULL;
8903 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8905 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8907 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8908 switch (stream_type) {
8909 case MM_PLAYER_STREAM_TYPE_AUDIO:
8910 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8911 default_type = player->ini.audiocodec_default_type;
8912 element_hw = player->ini.audiocodec_element_hw;
8913 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8915 case MM_PLAYER_STREAM_TYPE_VIDEO:
8916 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8917 default_type = player->ini.videocodec_default_type;
8918 element_hw = player->ini.videocodec_element_hw;
8919 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8922 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8923 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8927 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8929 if (!strcmp(default_type, "sw"))
8930 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8932 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8934 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8935 codec_type = default_codec_type;
8937 /* to support codec selection, codec info have to be added in ini file.
8938 in case of hw codec is selected, filter elements should be applied
8939 depending on the hw capabilities. */
8940 if (codec_type != default_codec_type) {
8941 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
8942 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
8943 LOGE("There is no codec for type %d", codec_type);
8944 return MM_ERROR_PLAYER_NO_OP;
8947 LOGD("sorting is required");
8948 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
8949 player->need_audio_dec_sorting = TRUE;
8951 player->need_video_dec_sorting = TRUE;
8954 LOGD("update %s codec_type to %d", attr_name, codec_type);
8955 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8958 return MM_ERROR_NONE;
8962 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8964 mmplayer_t *player = (mmplayer_t *)hplayer;
8965 GstElement *rg_vol_element = NULL;
8969 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8971 player->sound.rg_enable = enabled;
8973 /* just hold rgvolume enable value if pipeline is not ready */
8974 if (!player->pipeline || !player->pipeline->audiobin) {
8975 LOGD("pipeline is not ready. holding rgvolume enable value");
8976 return MM_ERROR_NONE;
8979 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8981 if (!rg_vol_element) {
8982 LOGD("rgvolume element is not created");
8983 return MM_ERROR_PLAYER_INTERNAL;
8987 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8989 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8993 return MM_ERROR_NONE;
8997 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8999 mmplayer_t *player = (mmplayer_t *)hplayer;
9000 GstElement *rg_vol_element = NULL;
9001 gboolean enable = FALSE;
9005 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9006 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
9008 /* just hold enable_rg value if pipeline is not ready */
9009 if (!player->pipeline || !player->pipeline->audiobin) {
9010 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
9011 *enabled = player->sound.rg_enable;
9012 return MM_ERROR_NONE;
9015 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9017 if (!rg_vol_element) {
9018 LOGD("rgvolume element is not created");
9019 return MM_ERROR_PLAYER_INTERNAL;
9022 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9023 *enabled = (bool)enable;
9027 return MM_ERROR_NONE;
9031 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9033 mmplayer_t *player = (mmplayer_t *)hplayer;
9034 MMHandleType attrs = 0;
9036 int ret = MM_ERROR_NONE;
9040 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9042 attrs = MMPLAYER_GET_ATTRS(player);
9043 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9045 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9047 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9048 return MM_ERROR_PLAYER_INTERNAL;
9051 player->video_roi.scale_x = scale_x;
9052 player->video_roi.scale_y = scale_y;
9053 player->video_roi.scale_width = scale_width;
9054 player->video_roi.scale_height = scale_height;
9056 /* check video sinkbin is created */
9057 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9058 return MM_ERROR_NONE;
9060 if (!gst_video_overlay_set_video_roi_area(
9061 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9062 scale_x, scale_y, scale_width, scale_height))
9063 ret = MM_ERROR_PLAYER_INTERNAL;
9065 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9066 scale_x, scale_y, scale_width, scale_height);
9074 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9076 mmplayer_t *player = (mmplayer_t *)hplayer;
9077 int ret = MM_ERROR_NONE;
9081 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9082 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9084 *scale_x = player->video_roi.scale_x;
9085 *scale_y = player->video_roi.scale_y;
9086 *scale_width = player->video_roi.scale_width;
9087 *scale_height = player->video_roi.scale_height;
9089 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9090 *scale_x, *scale_y, *scale_width, *scale_height);
9096 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9098 mmplayer_t *player = (mmplayer_t *)hplayer;
9102 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9104 player->client_pid = pid;
9106 LOGD("client pid[%d] %p", pid, player);
9110 return MM_ERROR_NONE;
9114 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9116 mmplayer_t *player = (mmplayer_t *)hplayer;
9117 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9118 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9122 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9123 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9126 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9128 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9130 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9131 return MM_ERROR_NONE;
9133 /* in case of audio codec default type is HW */
9135 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9136 if (player->ini.support_audio_effect)
9137 return MM_ERROR_NONE;
9138 elem_id = MMPLAYER_A_FILTER;
9140 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9141 if (player->ini.support_replaygain_control)
9142 return MM_ERROR_NONE;
9143 elem_id = MMPLAYER_A_RGVOL;
9145 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9146 if (player->ini.support_pitch_control)
9147 return MM_ERROR_NONE;
9148 elem_id = MMPLAYER_A_PITCH;
9150 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9151 if (player->ini.support_audio_effect)
9152 return MM_ERROR_NONE;
9154 /* default case handling is not required */
9157 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9158 LOGW("audio control option [%d] is not available", opt);
9161 /* setting pcm exporting option is allowed before READY state */
9162 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9163 return MM_ERROR_PLAYER_INVALID_STATE;
9165 /* check whether the audio filter exist or not after READY state,
9166 because the sw codec could be added during auto-plugging in some cases */
9167 if (!player->pipeline ||
9168 !player->pipeline->audiobin ||
9169 !player->pipeline->audiobin[elem_id].gst) {
9170 LOGW("there is no audio elem [%d]", elem_id);
9175 LOGD("audio control opt %d, available %d", opt, *available);
9179 return MM_ERROR_NONE;
9183 __mmplayer_update_duration_value(mmplayer_t *player)
9185 gboolean ret = FALSE;
9186 gint64 dur_nsec = 0;
9187 LOGD("try to update duration");
9189 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9190 player->duration = dur_nsec;
9191 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9195 if (player->duration < 0) {
9196 LOGW("duration is Non-Initialized !!!");
9197 player->duration = 0;
9200 /* update streaming service type */
9201 player->streaming_type = _mmplayer_get_stream_service_type(player);
9203 /* check duration is OK */
9204 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9205 /* FIXIT : find another way to get duration here. */
9206 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9212 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9214 /* update audio params
9215 NOTE : We need original audio params and it can be only obtained from src pad of audio
9216 decoder. Below code only valid when we are not using 'resampler' just before
9217 'audioconverter'. */
9218 GstCaps *caps_a = NULL;
9220 gint samplerate = 0, channels = 0;
9221 GstStructure *p = NULL;
9222 GstElement *aconv = NULL;
9224 LOGD("try to update audio attrs");
9226 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9228 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9229 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9230 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9231 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9233 LOGE("there is no audio converter");
9237 pad = gst_element_get_static_pad(aconv, "sink");
9240 LOGW("failed to get pad from audio converter");
9244 caps_a = gst_pad_get_current_caps(pad);
9246 LOGW("not ready to get audio caps");
9247 gst_object_unref(pad);
9251 p = gst_caps_get_structure(caps_a, 0);
9253 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9255 gst_structure_get_int(p, "rate", &samplerate);
9256 gst_structure_get_int(p, "channels", &channels);
9258 mm_player_set_attribute((MMHandleType)player, NULL,
9259 "content_audio_samplerate", samplerate,
9260 "content_audio_channels", channels, NULL);
9262 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9264 gst_caps_unref(caps_a);
9265 gst_object_unref(pad);
9271 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9273 LOGD("try to update video attrs");
9275 GstCaps *caps_v = NULL;
9279 GstStructure *p = NULL;
9281 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9282 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9284 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9286 LOGD("no videosink sink pad");
9290 caps_v = gst_pad_get_current_caps(pad);
9291 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9292 if (!caps_v && player->v_stream_caps) {
9293 caps_v = player->v_stream_caps;
9294 gst_caps_ref(caps_v);
9298 LOGD("no negitiated caps from videosink");
9299 gst_object_unref(pad);
9303 p = gst_caps_get_structure(caps_v, 0);
9304 gst_structure_get_int(p, "width", &width);
9305 gst_structure_get_int(p, "height", &height);
9307 mm_player_set_attribute((MMHandleType)player, NULL,
9308 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9310 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9312 SECURE_LOGD("width : %d height : %d", width, height);
9314 gst_caps_unref(caps_v);
9315 gst_object_unref(pad);
9318 mm_player_set_attribute((MMHandleType)player, NULL,
9319 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9320 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9327 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9329 gboolean ret = FALSE;
9330 guint64 data_size = 0;
9334 /* FIXIT : please make it clear the dependancy with duration/codec/uritype */
9335 if (!player->duration)
9338 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9339 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9340 if (stat(path, &sb) == 0)
9341 data_size = (guint64)sb.st_size;
9343 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9344 data_size = player->http_content_size;
9347 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9350 guint64 bitrate = 0;
9351 guint64 msec_dur = 0;
9353 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9355 bitrate = data_size * 8 * 1000 / msec_dur;
9356 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9357 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9358 mm_player_set_attribute((MMHandleType)player, NULL,
9359 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9362 LOGD("player duration is less than 0");
9366 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9367 if (player->total_bitrate) {
9368 mm_player_set_attribute((MMHandleType)player, NULL,
9369 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9378 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9380 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9381 data->uri_type = uri_type;
9385 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9387 int ret = MM_ERROR_PLAYER_INVALID_URI;
9389 char *buffer = NULL;
9390 char *seperator = strchr(path, ',');
9391 char ext[100] = {0,}, size[100] = {0,};
9394 if ((buffer = strstr(path, "ext="))) {
9395 buffer += strlen("ext=");
9397 if (strlen(buffer)) {
9398 strncpy(ext, buffer, 99);
9400 if ((seperator = strchr(ext, ','))
9401 || (seperator = strchr(ext, ' '))
9402 || (seperator = strchr(ext, '\0'))) {
9403 seperator[0] = '\0';
9408 if ((buffer = strstr(path, "size="))) {
9409 buffer += strlen("size=");
9411 if (strlen(buffer) > 0) {
9412 strncpy(size, buffer, 99);
9414 if ((seperator = strchr(size, ','))
9415 || (seperator = strchr(size, ' '))
9416 || (seperator = strchr(size, '\0'))) {
9417 seperator[0] = '\0';
9420 mem_size = atoi(size);
9425 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9427 if (mem_size && param) {
9428 if (data->input_mem.buf)
9429 free(data->input_mem.buf);
9430 data->input_mem.buf = malloc(mem_size);
9432 if (data->input_mem.buf) {
9433 memcpy(data->input_mem.buf, param, mem_size);
9434 data->input_mem.len = mem_size;
9435 ret = MM_ERROR_NONE;
9437 LOGE("failed to alloc mem %d", mem_size);
9438 ret = MM_ERROR_PLAYER_INTERNAL;
9441 data->input_mem.offset = 0;
9442 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9449 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9451 gchar *location = NULL;
9454 int ret = MM_ERROR_NONE;
9456 if ((path = strstr(uri, "file://"))) {
9457 location = g_filename_from_uri(uri, NULL, &err);
9458 if (!location || (err != NULL)) {
9459 LOGE("Invalid URI '%s' for filesrc: %s", path,
9460 (err != NULL) ? err->message : "unknown error");
9464 MMPLAYER_FREEIF(location);
9466 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9467 return MM_ERROR_PLAYER_INVALID_URI;
9469 LOGD("path from uri: %s", location);
9472 path = (location != NULL) ? (location) : ((char *)uri);
9475 ret = _mmplayer_exist_file_path(path);
9477 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9478 if (ret == MM_ERROR_NONE) {
9479 if (_mmplayer_is_sdp_file(path)) {
9480 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9481 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9482 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9484 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9485 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9487 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9488 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9490 LOGE("invalid uri, could not play..");
9491 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9494 MMPLAYER_FREEIF(location);
9499 static mmplayer_video_decoded_data_info_t *
9500 __mmplayer_create_stream_from_pad(GstPad *pad)
9502 GstCaps *caps = NULL;
9503 GstStructure *structure = NULL;
9504 unsigned int fourcc = 0;
9505 const gchar *string_format = NULL;
9506 mmplayer_video_decoded_data_info_t *stream = NULL;
9508 MMPixelFormatType format;
9511 caps = gst_pad_get_current_caps(pad);
9513 LOGE("Caps is NULL.");
9518 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9520 structure = gst_caps_get_structure(caps, 0);
9521 gst_structure_get_int(structure, "width", &width);
9522 gst_structure_get_int(structure, "height", &height);
9523 string_format = gst_structure_get_string(structure, "format");
9526 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9527 format = _mmplayer_get_pixtype(fourcc);
9528 gst_video_info_from_caps(&info, caps);
9529 gst_caps_unref(caps);
9532 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9533 LOGE("Wrong condition!!");
9537 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9539 LOGE("failed to alloc mem for video data");
9543 stream->width = width;
9544 stream->height = height;
9545 stream->format = format;
9546 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9552 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9554 unsigned int pitch = 0;
9555 unsigned int size = 0;
9557 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9560 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9561 bo = gst_tizen_memory_get_bos(mem, index);
9563 stream->bo[index] = tbm_bo_ref(bo);
9565 LOGE("failed to get bo for index %d", index);
9568 for (index = 0; index < stream->plane_num; index++) {
9569 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9570 stream->stride[index] = pitch;
9572 stream->elevation[index] = size / pitch;
9574 stream->elevation[index] = stream->height;
9579 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9581 if (stream->format == MM_PIXEL_FORMAT_I420) {
9582 int ret = TBM_SURFACE_ERROR_NONE;
9583 tbm_surface_h surface;
9584 tbm_surface_info_s info;
9586 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9588 ret = tbm_surface_get_info(surface, &info);
9589 if (ret != TBM_SURFACE_ERROR_NONE) {
9590 tbm_surface_destroy(surface);
9594 tbm_surface_destroy(surface);
9595 stream->stride[0] = info.planes[0].stride;
9596 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9597 stream->stride[1] = info.planes[1].stride;
9598 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9599 stream->stride[2] = info.planes[2].stride;
9600 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9601 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9602 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9603 stream->stride[0] = stream->width * 4;
9604 stream->elevation[0] = stream->height;
9605 stream->bo_size = stream->stride[0] * stream->height;
9607 LOGE("Not support format %d", stream->format);
9615 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9617 tbm_bo_handle thandle;
9619 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9620 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9621 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9625 unsigned char *src = NULL;
9626 unsigned char *dest = NULL;
9627 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9629 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9631 LOGE("fail to gst_memory_map");
9635 if (!mapinfo.data) {
9636 LOGE("data pointer is wrong");
9640 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9641 if (!stream->bo[0]) {
9642 LOGE("Fail to tbm_bo_alloc!!");
9646 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9648 LOGE("thandle pointer is wrong");
9652 if (stream->format == MM_PIXEL_FORMAT_I420) {
9653 src_stride[0] = GST_ROUND_UP_4(stream->width);
9654 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9655 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9656 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9659 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9660 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9662 for (i = 0; i < 3; i++) {
9663 src = mapinfo.data + src_offset[i];
9664 dest = thandle.ptr + dest_offset[i];
9669 for (j = 0; j < stream->height >> k; j++) {
9670 memcpy(dest, src, stream->width>>k);
9671 src += src_stride[i];
9672 dest += stream->stride[i];
9675 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9676 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9678 LOGE("Not support format %d", stream->format);
9682 tbm_bo_unmap(stream->bo[0]);
9683 gst_memory_unmap(mem, &mapinfo);
9689 tbm_bo_unmap(stream->bo[0]);
9692 gst_memory_unmap(mem, &mapinfo);
9698 __mmplayer_set_pause_state(mmplayer_t *player)
9700 if (player->sent_bos)
9703 /* rtsp case, get content attrs by GstMessage */
9704 if (MMPLAYER_IS_RTSP_STREAMING(player))
9707 /* it's first time to update all content attrs. */
9708 _mmplayer_update_content_attrs(player, ATTR_ALL);
9712 __mmplayer_set_playing_state(mmplayer_t *player)
9714 gchar *audio_codec = NULL;
9716 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9717 /* initialize because auto resume is done well. */
9718 player->resumed_by_rewind = FALSE;
9719 player->playback_rate = 1.0;
9722 if (player->sent_bos)
9725 /* try to get content metadata */
9727 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9728 * c-api since c-api doesn't use _start() anymore. It may not work propery with
9729 * legacy mmfw-player api
9731 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9733 if ((player->cmd == MMPLAYER_COMMAND_START)
9734 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9735 __mmplayer_handle_missed_plugin(player);
9738 /* check audio codec field is set or not
9739 * we can get it from typefinder or codec's caps.
9741 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9743 /* The codec format can't be sent for audio only case like amr, mid etc.
9744 * Because, parser don't make related TAG.
9745 * So, if it's not set yet, fill it with found data.
9748 if (g_strrstr(player->type, "audio/midi"))
9749 audio_codec = "MIDI";
9750 else if (g_strrstr(player->type, "audio/x-amr"))
9751 audio_codec = "AMR";
9752 else if (g_strrstr(player->type, "audio/mpeg")
9753 && !g_strrstr(player->type, "mpegversion=(int)1"))
9754 audio_codec = "AAC";
9756 audio_codec = "unknown";
9758 if (mm_player_set_attribute((MMHandleType)player, NULL,
9759 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9760 LOGE("failed to set attribute");
9762 LOGD("set audio codec type with caps");