4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: JongHyuk Choi <jhchoi.choi@samsung.com>, YeJin Cho <cho.yejin@samsung.com>,
7 * Seungbae Shin <seungbae.shin@samsung.com>, YoungHwan An <younghwan_.an@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 /*===========================================================================================
27 ========================================================================================== */
30 #include <gst/video/videooverlay.h>
31 #include <gst/audio/gstaudiobasesink.h>
44 #include "mm_player_priv.h"
45 #include "mm_player_ini.h"
46 #include "mm_player_capture.h"
47 #include "mm_player_utils.h"
48 #include "mm_player_tracks.h"
49 #include "mm_player_360.h"
50 #include "mm_player_gst.h"
52 #include <system_info.h>
53 #include <sound_manager.h>
54 #include <gst/allocators/gsttizenmemory.h>
55 #include <tbm_surface_internal.h>
57 /*===========================================================================================
59 | LOCAL DEFINITIONS AND DECLARATIONS FOR MODULE |
61 ========================================================================================== */
63 /*---------------------------------------------------------------------------
64 | GLOBAL CONSTANT DEFINITIONS: |
65 ---------------------------------------------------------------------------*/
67 /*---------------------------------------------------------------------------
68 | IMPORTED VARIABLE DECLARATIONS: |
69 ---------------------------------------------------------------------------*/
71 /*---------------------------------------------------------------------------
72 | IMPORTED FUNCTION DECLARATIONS: |
73 ---------------------------------------------------------------------------*/
75 /*---------------------------------------------------------------------------
77 ---------------------------------------------------------------------------*/
78 #define TRICK_PLAY_MUTE_THRESHOLD_MAX 2.0
79 #define TRICK_PLAY_MUTE_THRESHOLD_MIN 0.0
81 #define MM_VOLUME_FACTOR_DEFAULT 1.0
82 #define MM_VOLUME_FACTOR_MIN 0
83 #define MM_VOLUME_FACTOR_MAX 1.0
85 /* Don't need to sleep for sound fadeout
86 * fadeout related function will be deleted(Deprecated)
88 #define MM_PLAYER_FADEOUT_TIME_DEFAULT 0
90 #define DEFAULT_PLAYBACK_RATE 1.0
92 #define PLAYER_DISPLAY_MODE_DST_ROI 5
94 #define ADAPTIVE_VARIANT_DEFAULT_VALUE -1 /* auto */
96 #define PLAYER_SPHERICAL_DEFAULT_YAW 0 /* sync from video360 plugin */
97 #define PLAYER_SPHERICAL_DEFAULT_PITCH 0
98 #define PLAYER_SPHERICAL_DEFAULT_H_FOV 120
99 #define PLAYER_SPHERICAL_DEFAULT_V_FOV 67
101 #define SPATIAL_AUDIO_CAPS "audio/x-raw,format=S16LE,channels=4"
102 #define FEATURE_NAME_SPHERICAL_VIDEO "http://tizen.org/feature/multimedia.player.spherical_video"
104 #define FAKE_SINK_MAX_LATENESS G_GINT64_CONSTANT(20000000) /* set 20ms as waylandsink */
106 #define DEFAULT_PCM_OUT_FORMAT "F32LE"
107 #define DEFAULT_PCM_OUT_SAMPLERATE 44100
108 #define DEFAULT_PCM_OUT_CHANNEL 2
110 /*---------------------------------------------------------------------------
111 | LOCAL CONSTANT DEFINITIONS: |
112 ---------------------------------------------------------------------------*/
114 /*---------------------------------------------------------------------------
115 | LOCAL DATA TYPE DEFINITIONS: |
116 ---------------------------------------------------------------------------*/
117 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed
118 We are defining our own and will be removed when it actually exposed */
120 GST_AUTOPLUG_SELECT_TRY,
121 GST_AUTOPLUG_SELECT_EXPOSE,
122 GST_AUTOPLUG_SELECT_SKIP
123 } GstAutoplugSelectResult;
125 /*---------------------------------------------------------------------------
126 | GLOBAL VARIABLE DEFINITIONS: |
127 ---------------------------------------------------------------------------*/
129 /*---------------------------------------------------------------------------
130 | LOCAL VARIABLE DEFINITIONS: |
131 ---------------------------------------------------------------------------*/
132 static sound_stream_info_h stream_info;
134 /*---------------------------------------------------------------------------
135 | LOCAL FUNCTION PROTOTYPES: |
136 ---------------------------------------------------------------------------*/
137 static int __mmplayer_gst_create_pipeline(mmplayer_t *player);
138 static int __mmplayer_gst_destroy_pipeline(mmplayer_t *player);
139 static int __mmplayer_gst_create_text_pipeline(mmplayer_t *player);
140 static int __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type);
141 static int __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player);
142 static int __mmplayer_gst_create_text_sink_bin(mmplayer_t *player);
143 static void __mmplayer_gst_create_sink_bin(GstElement *decodebin, GstPad *pad, GstCaps *ref_caps, gpointer data);
144 static gboolean __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps);
145 static gboolean __mmplayer_is_midi_type(gchar *str_caps);
146 static gboolean __mmplayer_is_only_mp3_type(gchar *str_caps);
148 static gboolean __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
149 static void __mmplayer_release_misc(mmplayer_t *player);
150 static void __mmplayer_release_misc_post(mmplayer_t *player);
151 static gboolean __mmplayer_init_gstreamer(mmplayer_t *player);
152 static void __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
153 static void __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
154 static GstPadProbeReturn __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
155 static int __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index);
157 static gboolean __mmplayer_check_subtitle(mmplayer_t *player);
158 static int __mmplayer_handle_missed_plugin(mmplayer_t *player);
159 static int __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime);
160 static void __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first);
161 static void __mmplayer_del_sink(mmplayer_t *player, GstElement *sink);
162 static void __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type);
163 static gpointer __mmplayer_gapless_play_thread(gpointer data);
164 static gboolean __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element);
165 static GstPadProbeReturn __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
166 static void __mmplayer_release_dump_list(GList *dump_list);
167 static int __mmplayer_gst_realize(mmplayer_t *player);
168 static int __mmplayer_gst_unrealize(mmplayer_t *player);
169 static int __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position);
170 static int __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param);
173 static gboolean __mmplayer_verify_gapless_play_path(mmplayer_t *player);
174 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player);
175 static gboolean __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type);
176 static gboolean __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type);
177 static void __mmplayer_deactivate_old_path(mmplayer_t *player);
178 static int __mmplayer_gst_create_plain_text_elements(mmplayer_t *player);
179 static guint32 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name);
180 static void __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data);
181 static void __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer);
182 static void __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type);
183 static gboolean __mmplayer_update_duration_value(mmplayer_t *player);
184 static gboolean __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs);
185 static gboolean __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs);
186 static gboolean __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs);
188 static void __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type);
189 static int __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param);
190 static int __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri);
192 static mmplayer_video_decoded_data_info_t *__mmplayer_create_stream_from_pad(GstPad *pad);
193 static void __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
194 static gboolean __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream);
195 static gboolean __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem);
197 static void __mmplayer_set_pause_state(mmplayer_t *player);
198 static void __mmplayer_set_playing_state(mmplayer_t *player);
199 /*===========================================================================================
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 application 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("incoming 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 browser
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 LOGD("commit [%d type] resource", type);
588 rm_ret = mm_resource_manager_commit(player->resource_manager);
589 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
590 LOGE("failed to commit of resource, ret(0x%x)", rm_ret);
591 return MM_ERROR_PLAYER_INTERNAL;
595 return MM_ERROR_NONE;
598 static void __mmplayer_destroy_hw_resource(mmplayer_t *player)
600 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
602 MMPLAYER_RETURN_IF_FAIL(player);
603 MMPLAYER_RETURN_IF_FAIL(player->resource_manager);
605 rm_ret = mm_resource_manager_mark_all_for_release(player->resource_manager);
606 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
607 LOGW("failed to mark all for release of resource, ret(0x%x)", rm_ret);
611 rm_ret = mm_resource_manager_commit(player->resource_manager);
612 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE)
613 LOGW("failed to commit resource, ret(0x%x)", rm_ret);
616 /* de-initialize resource manager */
617 rm_ret = mm_resource_manager_destroy(player->resource_manager);
618 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
619 LOGW("failed to destroy resource manager, ret(0x%x)", rm_ret);
623 player->resource_manager = NULL;
625 LOGD("resource manager is destroyed");
628 static int __mmplayer_release_hw_resource(mmplayer_t *player, mmplayer_resource_type_e type)
630 int rm_ret = MM_RESOURCE_MANAGER_ERROR_NONE;
634 if (player->hw_resource[type] == NULL) {
635 LOGD("there is no acquired [%d type] resource", type);
636 return MM_ERROR_NONE;
639 LOGD("mark for release [%d type] resource", type);
640 rm_ret = mm_resource_manager_mark_for_release(player->resource_manager, player->hw_resource[type]);
641 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
642 LOGE("failed to mark resource for release, ret(0x%x)", rm_ret);
643 return MM_ERROR_PLAYER_INTERNAL;
646 player->hw_resource[type] = NULL;
648 LOGD("commit [%d type] resource", type);
649 rm_ret = mm_resource_manager_commit(player->resource_manager);
650 if (rm_ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
651 LOGE("failed to commit resource, ret(0x%x)", rm_ret);
652 return MM_ERROR_PLAYER_INTERNAL;
656 return MM_ERROR_NONE;
660 __mmplayer_initialize_gapless_play(mmplayer_t *player)
666 player->smooth_streaming = FALSE;
667 player->videodec_linked = 0;
668 player->audiodec_linked = 0;
669 player->textsink_linked = 0;
670 player->is_external_subtitle_present = FALSE;
671 player->is_external_subtitle_added_now = FALSE;
672 player->not_supported_codec = MISSING_PLUGIN_NONE;
673 player->can_support_codec = FOUND_PLUGIN_NONE;
674 player->pending_seek.is_pending = false;
675 player->pending_seek.pos = 0;
676 player->msg_posted = FALSE;
677 player->has_many_types = FALSE;
678 player->no_more_pad = FALSE;
679 player->not_found_demuxer = 0;
680 player->seek_state = MMPLAYER_SEEK_NONE;
681 player->is_subtitle_force_drop = FALSE;
682 player->play_subtitle = FALSE;
683 player->adjust_subtitle_pos = 0;
685 player->total_bitrate = 0;
686 player->total_maximum_bitrate = 0;
688 _mmplayer_track_initialize(player);
689 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
691 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
692 player->bitrate[i] = 0;
693 player->maximum_bitrate[i] = 0;
696 if (player->v_stream_caps) {
697 gst_caps_unref(player->v_stream_caps);
698 player->v_stream_caps = NULL;
701 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
703 /* clean found audio decoders */
704 if (player->audio_decoders) {
705 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
706 player->audio_decoders = NULL;
709 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER);
714 void _mmplayer_set_reconfigure_state(mmplayer_t *player, gboolean state)
716 LOGI("set pipeline reconfigure state %d", state);
717 MMPLAYER_RECONFIGURE_LOCK(player);
718 player->gapless.reconfigure = state;
719 if (!state) /* wake up the waiting job */
720 MMPLAYER_RECONFIGURE_SIGNAL(player);
721 MMPLAYER_RECONFIGURE_UNLOCK(player);
725 __mmplayer_gapless_play_thread(gpointer data)
727 mmplayer_t *player = (mmplayer_t *)data;
728 mmplayer_gst_element_t *mainbin = NULL;
730 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
732 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
733 while (!player->gapless_play_thread_exit) {
734 LOGD("gapless play thread started. waiting for signal.");
735 MMPLAYER_GAPLESS_PLAY_THREAD_WAIT(player);
737 LOGD("reconfigure pipeline for gapless play.");
739 if (player->gapless_play_thread_exit) {
740 _mmplayer_set_reconfigure_state(player, FALSE);
741 LOGD("exiting gapless play thread");
745 mainbin = player->pipeline->mainbin;
747 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_MUXED_S_BUFFER);
748 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_ID3DEMUX);
749 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_AUTOPLUG);
750 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_TYPEFIND);
751 MMPLAYER_RELEASE_ELEMENT(player, mainbin, MMPLAYER_M_SRC);
753 /* Initialize Player values */
754 __mmplayer_initialize_gapless_play(player);
756 _mmplayer_activate_next_source(player, GST_STATE_PLAYING);
758 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
764 __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id)
766 GSource *source = NULL;
770 source = g_main_context_find_source_by_id(context, source_id);
771 if (source != NULL) {
772 LOGW("context: %p, source id: %d, source: %p", context, source_id, source);
773 g_source_destroy(source);
780 _mmplayer_watcher_removed_notify(gpointer data)
782 mmplayer_t *player = (mmplayer_t *)data;
783 MMPLAYER_RETURN_IF_FAIL(player);
785 MMPLAYER_BUS_WATCHER_LOCK(player);
786 player->bus_watcher = 0;
787 MMPLAYER_BUS_WATCHER_SIGNAL(player);
788 MMPLAYER_BUS_WATCHER_UNLOCK(player);
792 _mmplayer_bus_watcher_remove(MMHandleType hplayer)
794 mmplayer_t *player = (mmplayer_t *)hplayer;
797 MMPLAYER_RETURN_IF_FAIL(player);
799 /* disconnecting bus watch */
800 if (player->bus_watcher > 0) {
801 __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
802 MMPLAYER_BUS_WATCHER_LOCK(player);
803 end_time = g_get_monotonic_time () + 2 * G_TIME_SPAN_SECOND;
804 while (player->bus_watcher > 0)
805 MMPLAYER_BUS_WATCHER_WAIT_UNTIL(player, end_time);
806 MMPLAYER_BUS_WATCHER_UNLOCK(player);
808 g_mutex_clear(&player->bus_watcher_mutex);
809 g_cond_clear(&player->bus_watcher_cond);
816 _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
818 mmplayer_t *player = (mmplayer_t *)hplayer;
819 GstMessage *msg = NULL;
820 GQueue *queue = NULL;
823 MMPLAYER_RETURN_IF_FAIL(player);
825 /* destroy the gst bus msg thread */
826 if (player->bus_msg_thread) {
827 MMPLAYER_BUS_MSG_THREAD_LOCK(player);
828 player->bus_msg_thread_exit = TRUE;
829 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
830 MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
832 LOGD("gst bus msg thread exit.");
833 g_thread_join(player->bus_msg_thread); /* can request cmd lock */
834 player->bus_msg_thread = NULL;
836 g_mutex_clear(&player->bus_msg_thread_mutex);
837 g_cond_clear(&player->bus_msg_thread_cond);
840 g_mutex_lock(&player->bus_msg_q_lock);
841 queue = player->bus_msg_q;
842 while (!g_queue_is_empty(queue)) {
843 msg = (GstMessage *)g_queue_pop_head(queue);
848 LOGW("remove remained %s msg", GST_MESSAGE_TYPE_NAME(msg));
849 gst_message_unref(msg);
851 g_mutex_unlock(&player->bus_msg_q_lock);
857 _mmplayer_gst_remove_fakesink(mmplayer_t *player, mmplayer_gst_element_t *fakesink)
859 GstElement *parent = NULL;
861 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
862 MMPLAYER_RETURN_VAL_IF_FAIL(fakesink && fakesink->gst, TRUE);
865 MMPLAYER_FSINK_LOCK(player);
867 /* get parent of fakesink */
868 parent = (GstElement *)gst_object_get_parent((GstObject *)fakesink->gst);
870 LOGD("fakesink already removed");
874 gst_element_set_locked_state(fakesink->gst, TRUE);
876 /* setting the state to NULL never returns async
877 * so no need to wait for completion of state transition
879 if (GST_STATE_CHANGE_FAILURE == gst_element_set_state(fakesink->gst, GST_STATE_NULL))
880 LOGE("fakesink state change failure!");
881 /* FIXIT : should I return here? or try to proceed to next? */
884 /* remove fakesink from it's parent */
885 if (!gst_bin_remove(GST_BIN(parent), fakesink->gst)) {
886 LOGE("failed to remove fakesink");
888 gst_object_unref(parent);
893 gst_object_unref(parent);
895 LOGD("state-holder removed");
897 gst_element_set_locked_state(fakesink->gst, FALSE);
899 MMPLAYER_FSINK_UNLOCK(player);
904 gst_element_set_locked_state(fakesink->gst, FALSE);
906 MMPLAYER_FSINK_UNLOCK(player);
910 static GstPadProbeReturn
911 __mmplayer_gst_selector_blocked(GstPad *pad, GstPadProbeInfo *info, gpointer data)
913 LOGD("pad(%s:%s) is blocked", GST_DEBUG_PAD_NAME(pad));
914 return GST_PAD_PROBE_OK;
918 __mmplayer_gst_selector_update_start_time(mmplayer_t *player, mmplayer_track_type_e stream_type)
920 gint64 stop_running_time = 0;
921 gint64 position_running_time = 0;
925 for (idx = MM_PLAYER_TRACK_TYPE_AUDIO; idx < MM_PLAYER_TRACK_TYPE_TEXT; idx++) {
926 if ((player->gapless.update_segment[idx] == TRUE) ||
927 !(player->track[idx].event_probe_id)) {
929 LOGW("[%d] skip", idx);
934 if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].stop)) {
936 gst_segment_to_running_time(&player->gapless.segment[idx],
937 GST_FORMAT_TIME, player->gapless.segment[idx].stop);
938 } else if (GST_CLOCK_TIME_IS_VALID(player->gapless.segment[idx].duration)) {
940 gst_segment_to_running_time(&player->gapless.segment[idx],
941 GST_FORMAT_TIME, player->gapless.segment[idx].duration);
943 LOGD("duration: %"GST_TIME_FORMAT, GST_TIME_ARGS(player->duration));
945 gst_segment_to_running_time(&player->gapless.segment[idx],
946 GST_FORMAT_TIME, player->duration);
949 position_running_time =
950 gst_segment_to_running_time(&player->gapless.segment[idx],
951 GST_FORMAT_TIME, player->gapless.segment[idx].position);
953 LOGD("[type:%d] time info %" GST_TIME_FORMAT " , %"
954 GST_TIME_FORMAT" , %" GST_TIME_FORMAT,
956 GST_TIME_ARGS(stop_running_time),
957 GST_TIME_ARGS(position_running_time),
958 GST_TIME_ARGS(gst_segment_to_running_time(&player->gapless.segment[idx],
959 GST_FORMAT_TIME, player->gapless.segment[idx].start)));
961 position_running_time = MAX(position_running_time, stop_running_time);
962 position_running_time -= gst_segment_to_running_time(&player->gapless.segment[idx],
963 GST_FORMAT_TIME, player->gapless.segment[idx].start);
964 position_running_time = MAX(0, position_running_time);
965 position = MAX(position, position_running_time);
969 LOGD("[%d]GST_EVENT_STREAM_START: start_time from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT,
970 stream_type, GST_TIME_ARGS(player->gapless.start_time[stream_type]),
971 GST_TIME_ARGS(player->gapless.start_time[stream_type] + position));
973 player->gapless.start_time[stream_type] += position;
979 static GstPadProbeReturn
980 __mmplayer_gst_selector_event_probe(GstPad *pad, GstPadProbeInfo *info, gpointer data)
982 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
983 GstEvent *event = GST_PAD_PROBE_INFO_DATA(info);
984 mmplayer_t *player = (mmplayer_t *)data;
985 GstCaps *caps = NULL;
986 GstStructure *str = NULL;
987 const gchar *name = NULL;
988 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
989 gboolean caps_ret = TRUE;
991 if (GST_EVENT_TYPE(event) != GST_EVENT_STREAM_START &&
992 GST_EVENT_TYPE(event) != GST_EVENT_FLUSH_STOP &&
993 GST_EVENT_TYPE(event) != GST_EVENT_SEGMENT &&
994 GST_EVENT_TYPE(event) != GST_EVENT_EOS &&
995 GST_EVENT_TYPE(event) != GST_EVENT_QOS)
998 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1002 if (strstr(name, "audio")) {
1003 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1004 } else if (strstr(name, "video")) {
1005 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1007 /* text track is not supportable */
1008 LOGE("invalid name %s", name);
1012 switch (GST_EVENT_TYPE(event)) {
1015 /* in case of gapless, drop eos event not to send it to sink */
1016 if (player->gapless.reconfigure && !player->msg_posted) {
1017 LOGD("[%d] %s:%s EOS received but will be drop", stream_type, GST_DEBUG_PAD_NAME(pad));
1018 ret = GST_PAD_PROBE_DROP;
1022 case GST_EVENT_STREAM_START:
1024 __mmplayer_gst_selector_update_start_time(player, stream_type);
1027 case GST_EVENT_FLUSH_STOP:
1029 LOGD("[%d] GST_EVENT_FLUSH_STOP", stream_type);
1030 gst_segment_init(&player->gapless.segment[stream_type], GST_FORMAT_UNDEFINED);
1031 player->gapless.start_time[stream_type] = 0;
1034 case GST_EVENT_SEGMENT:
1039 LOGD("[%d] GST_EVENT_SEGMENT", stream_type);
1040 gst_event_copy_segment(event, &segment);
1042 if (segment.format != GST_FORMAT_TIME)
1045 LOGD("segment base:%" GST_TIME_FORMAT ", offset:%" GST_TIME_FORMAT
1046 ", start:%" GST_TIME_FORMAT ", stop: %" GST_TIME_FORMAT
1047 ", time: %" GST_TIME_FORMAT ", pos: %" GST_TIME_FORMAT ", dur: %" GST_TIME_FORMAT,
1048 GST_TIME_ARGS(segment.base), GST_TIME_ARGS(segment.offset),
1049 GST_TIME_ARGS(segment.start), GST_TIME_ARGS(segment.stop),
1050 GST_TIME_ARGS(segment.time), GST_TIME_ARGS(segment.position), GST_TIME_ARGS(segment.duration));
1052 /* keep the all the segment ev to cover the seeking */
1053 gst_segment_copy_into(&segment, &player->gapless.segment[stream_type]);
1054 player->gapless.update_segment[stream_type] = TRUE;
1056 if (!player->gapless.running)
1059 player->gapless.segment[stream_type].base = player->gapless.start_time[stream_type];
1061 LOGD("[%d] new base: %" GST_TIME_FORMAT, stream_type, GST_TIME_ARGS(player->gapless.segment[stream_type].base));
1063 tmpev = gst_event_new_segment(&player->gapless.segment[stream_type]);
1064 gst_event_set_seqnum(tmpev, gst_event_get_seqnum(event));
1065 gst_event_unref(event);
1066 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1072 gdouble proportion = 0.0;
1073 GstClockTimeDiff diff = 0;
1074 GstClockTime timestamp = 0;
1075 gint64 running_time_diff = -1;
1076 GstQOSType type = 0;
1077 GstEvent *tmpev = NULL;
1079 running_time_diff = player->gapless.segment[stream_type].base;
1081 if (running_time_diff <= 0) /* don't need to adjust */
1084 gst_event_parse_qos(event, &type, &proportion, &diff, ×tamp);
1085 gst_event_unref(event);
1087 if (timestamp < running_time_diff) {
1088 LOGW("QOS event from previous group");
1089 ret = GST_PAD_PROBE_DROP;
1094 LOGD("[%d] Adjusting QOS event: %" GST_TIME_FORMAT
1095 " - %" GST_TIME_FORMAT " = %" GST_TIME_FORMAT,
1096 stream_type, GST_TIME_ARGS(timestamp),
1097 GST_TIME_ARGS(running_time_diff),
1098 GST_TIME_ARGS(timestamp - running_time_diff));
1101 timestamp -= running_time_diff;
1103 /* That case is invalid for QoS events */
1104 if (diff < 0 && -diff > timestamp) {
1105 LOGW("QOS event from previous group");
1106 ret = GST_PAD_PROBE_DROP;
1110 tmpev = gst_event_new_qos(GST_QOS_TYPE_UNDERFLOW, proportion, diff, timestamp);
1111 GST_PAD_PROBE_INFO_DATA(info) = tmpev;
1121 gst_caps_unref(caps);
1125 /* create fakesink for audio or video path without audiobin or videobin */
1127 __mmplayer_gst_make_fakesink(mmplayer_t *player, GstPad *pad, const gchar *name)
1129 GstElement *pipeline = NULL;
1130 GstElement *fakesink = NULL;
1131 GstPad *sinkpad = NULL;
1134 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1136 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1139 fakesink = gst_element_factory_make("fakesink", NULL);
1140 if (fakesink == NULL) {
1141 LOGE("failed to create fakesink");
1145 /* store it as it's sink element */
1146 __mmplayer_add_sink(player, fakesink, FALSE);
1148 gst_bin_add(GST_BIN(pipeline), fakesink);
1151 sinkpad = gst_element_get_static_pad(fakesink, "sink");
1153 LOGD("pad link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1155 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1156 LOGE("failed to link fakesink");
1157 gst_object_unref(GST_OBJECT(fakesink));
1161 if (strstr(name, "video")) {
1162 if (player->v_stream_caps) {
1163 gst_caps_unref(player->v_stream_caps);
1164 player->v_stream_caps = NULL;
1166 if (player->ini.set_dump_element_flag)
1167 __mmplayer_add_dump_buffer_probe(player, fakesink);
1170 g_object_set(G_OBJECT(fakesink), "sync", TRUE, NULL);
1171 gst_element_set_state(fakesink, GST_STATE_PAUSED);
1175 gst_object_unref(GST_OBJECT(sinkpad));
1182 __mmplayer_gst_make_concat(mmplayer_t *player, main_element_id_e elem_idx)
1184 GstElement *pipeline = NULL;
1185 GstElement *concat = NULL;
1188 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1190 concat = gst_element_factory_make("concat", NULL);
1192 LOGE("failed to create concat");
1196 LOGD("Create concat [%d] element", elem_idx);
1198 player->pipeline->mainbin[elem_idx].id = elem_idx;
1199 player->pipeline->mainbin[elem_idx].gst = concat;
1201 gst_element_set_state(concat, GST_STATE_PAUSED);
1203 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1204 gst_bin_add(GST_BIN(pipeline), concat);
1211 __mmplayer_gst_make_selector(mmplayer_t *player, main_element_id_e elem_idx, mmplayer_track_type_e stream_type)
1213 GstElement *pipeline = NULL;
1214 GstElement *selector = NULL;
1215 GstPad *srcpad = NULL;
1218 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
1220 selector = gst_element_factory_make("input-selector", NULL);
1222 LOGE("failed to create input-selector");
1225 g_object_set(selector, "sync-streams", TRUE, NULL);
1227 player->pipeline->mainbin[elem_idx].id = elem_idx;
1228 player->pipeline->mainbin[elem_idx].gst = selector;
1230 /* player->track[stream_type].active_track_index = DEFAULT_TRACK; */
1232 srcpad = gst_element_get_static_pad(selector, "src");
1234 LOGD("blocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1235 player->track[stream_type].block_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM,
1236 __mmplayer_gst_selector_blocked, NULL, NULL);
1237 player->track[stream_type].event_probe_id = gst_pad_add_probe(srcpad, GST_PAD_PROBE_TYPE_EVENT_BOTH|GST_PAD_PROBE_TYPE_EVENT_FLUSH,
1238 __mmplayer_gst_selector_event_probe, player, NULL);
1240 gst_element_set_state(selector, GST_STATE_PAUSED);
1242 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1243 gst_bin_add(GST_BIN(pipeline), selector);
1245 gst_object_unref(GST_OBJECT(srcpad));
1252 _mmplayer_gst_decode_pad_added(GstElement *elem, GstPad *pad, gpointer data)
1254 mmplayer_t *player = (mmplayer_t *)data;
1255 GstElement *combiner = NULL;
1256 GstCaps *caps = NULL;
1257 GstStructure *str = NULL;
1258 const gchar *name = NULL;
1259 GstPad *sinkpad = NULL;
1260 gboolean first_track = FALSE;
1261 gboolean caps_ret = TRUE;
1263 main_element_id_e elem_idx = MMPLAYER_M_NUM;
1264 mmplayer_track_type_e stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1267 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1268 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
1270 LOGD("pad-added signal handling");
1272 /* get mimetype from caps */
1273 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1277 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
1279 LOGD("detected mimetype : %s", name);
1282 if (strstr(name, "video")) {
1284 gchar *caps_str = NULL;
1286 caps_str = gst_caps_to_string(caps);
1287 if (caps_str && (strstr(caps_str, "ST12") || strstr(caps_str, "SN12") ||
1288 strstr(caps_str, "SN21") || strstr(caps_str, "S420") || strstr(caps_str, "SR32")))
1289 player->set_mode.video_zc = true;
1291 MMPLAYER_FREEIF(caps_str);
1293 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", TRUE, NULL);
1294 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
1296 LOGD("surface type : %d", stype);
1298 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1299 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1303 /* in case of exporting video frame, it requires the 360 video filter.
1304 * it will be handled in _no_more_pads(). */
1305 if ((stype == MM_DISPLAY_SURFACE_NULL) && (!player->set_mode.video_export)) {
1306 __mmplayer_gst_make_fakesink(player, pad, name);
1310 if (MMPLAYER_USE_DECODEBIN(player)) {
1311 LOGD("video selector is required");
1312 elem_idx = MMPLAYER_M_V_INPUT_SELECTOR;
1314 LOGD("video concat is required");
1315 elem_idx = MMPLAYER_M_V_CONCAT;
1317 stream_type = MM_PLAYER_TRACK_TYPE_VIDEO;
1318 } else if (strstr(name, "audio")) {
1319 gint samplerate = 0;
1322 if (MMPLAYER_IS_MS_BUFF_SRC(player) || player->build_audio_offload) {
1323 if (player->build_audio_offload)
1324 player->no_more_pad = TRUE; /* remove state holder */
1325 __mmplayer_gst_create_sink_bin(elem, pad, caps, player);
1329 gst_structure_get_int(str, "rate", &samplerate);
1330 gst_structure_get_int(str, "channels", &channels);
1332 if ((channels > 0 && samplerate == 0)) { /* exclude audio decoding */
1333 __mmplayer_gst_make_fakesink(player, pad, name);
1336 if (MMPLAYER_USE_DECODEBIN(player)) {
1337 LOGD("audio selector is required");
1338 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
1340 LOGD("audio concat is required");
1341 elem_idx = MMPLAYER_M_A_CONCAT;
1343 stream_type = MM_PLAYER_TRACK_TYPE_AUDIO;
1345 } else if (strstr(name, "text")) {
1346 if (MMPLAYER_USE_DECODEBIN(player)) {
1347 LOGD("text selector is required");
1348 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
1350 LOGD("text concat is required");
1351 elem_idx = MMPLAYER_M_T_CONCAT;
1353 stream_type = MM_PLAYER_TRACK_TYPE_TEXT;
1355 LOGE("invalid caps info");
1359 /* check selector and create it */
1360 if (!(combiner = player->pipeline->mainbin[elem_idx].gst)) {
1361 if (MMPLAYER_USE_DECODEBIN(player))
1362 combiner = __mmplayer_gst_make_selector(player, elem_idx, stream_type);
1364 combiner = __mmplayer_gst_make_concat(player, elem_idx);
1370 LOGD("Combiner element is already created.");
1374 sinkpad = gst_element_get_request_pad(combiner, "sink_%u");
1376 LOGD("pad link: %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1378 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1379 LOGE("failed to link combiner");
1380 gst_object_unref(GST_OBJECT(combiner));
1385 if (MMPLAYER_USE_DECODEBIN(player)) {
1386 LOGD("this track will be activated");
1387 g_object_set(combiner, "active-pad", sinkpad, NULL);
1391 if (MMPLAYER_USE_DECODEBIN(player)) {
1392 _mmplayer_track_update_stream(player, stream_type, sinkpad);
1394 /* apply the text track information */
1395 if (stream_type == MM_PLAYER_TRACK_TYPE_TEXT)
1396 mm_player_set_attribute((MMHandleType)player, NULL,
1397 "content_text_track_num", player->track[stream_type].total_track_num,
1398 "current_text_track_index", player->track[stream_type].active_track_index, NULL);
1399 __mmplayer_create_sink_path(player, combiner, stream_type, caps);
1406 gst_caps_unref(caps);
1409 gst_object_unref(GST_OBJECT(sinkpad));
1417 __mmplayer_create_sink_path(mmplayer_t *player, GstElement *combiner, mmplayer_track_type_e type, GstCaps *caps)
1419 GstPad *srcpad = NULL;
1422 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1424 LOGD("type %d", type);
1427 LOGD("there is no %d track", type);
1431 srcpad = gst_element_get_static_pad(combiner, "src");
1433 LOGE("failed to get srcpad from combiner");
1437 LOGD("got pad %s:%s from combiner", GST_DEBUG_PAD_NAME(srcpad));
1439 __mmplayer_gst_create_sink_bin(combiner, srcpad, caps, player);
1441 LOGD("unblocking %s:%s", GST_DEBUG_PAD_NAME(srcpad));
1442 if (player->track[type].block_id) {
1443 gst_pad_remove_probe(srcpad, player->track[type].block_id);
1444 player->track[type].block_id = 0;
1448 gst_object_unref(GST_OBJECT(srcpad));
1457 __mmplayer_set_decode_track_info(mmplayer_t *player, mmplayer_track_type_e type)
1459 gint active_index = 0;
1462 MMPLAYER_RETURN_IF_FAIL(player);
1464 LOGD("type: %d, the num of track: %d", type, player->track[type].total_track_num);
1466 /* change track to active pad */
1467 active_index = player->track[type].active_track_index;
1468 if ((active_index != DEFAULT_TRACK) &&
1469 (__mmplayer_change_selector_pad(player, type, active_index) != MM_ERROR_NONE)) {
1470 LOGW("failed to change %d type track to %d", type, active_index);
1471 player->track[type].active_track_index = DEFAULT_TRACK;
1475 if (type == MM_PLAYER_TRACK_TYPE_TEXT)
1476 mm_player_set_attribute((MMHandleType)player, NULL,
1477 "content_text_track_num", player->track[type].total_track_num,
1478 "current_text_track_index", player->track[type].active_track_index, NULL);
1485 __mmplayer_create_audio_sink_path(mmplayer_t *player, GstElement *audio_selector)
1488 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, FALSE);
1490 if (!audio_selector) {
1491 LOGD("there is no audio track, num_dynamic_pad %d", player->num_dynamic_pad);
1493 /* in case the source is changed, output can be changed. */
1494 if ((player->pipeline->audiobin) && (player->pipeline->audiobin[MMPLAYER_A_BIN].gst)) {
1495 LOGD("remove previous audiobin if it exist");
1497 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
1498 __mmplayer_del_sink(player, player->pipeline->audiobin[MMPLAYER_A_SINK].gst);
1500 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->audiobin, MMPLAYER_A_BIN);
1501 MMPLAYER_FREEIF(player->pipeline->audiobin);
1504 if (player->num_dynamic_pad == 0) /* FIXME: num_dynamic_pad is only for rtsp? */
1505 _mmplayer_pipeline_complete(NULL, player);
1510 /* apply the audio track information */
1511 if (MMPLAYER_USE_DECODEBIN(player))
1512 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_AUDIO);
1514 /* create audio sink path */
1515 if (!__mmplayer_create_sink_path(player, audio_selector, MM_PLAYER_TRACK_TYPE_AUDIO, NULL)) {
1516 LOGE("failed to create audio sink path");
1525 __mmplayer_create_text_sink_path(mmplayer_t *player, GstElement *text_selector)
1528 MMPLAYER_RETURN_VAL_IF_FAIL(player && text_selector, FALSE);
1530 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
1531 LOGD("text path is not supported");
1535 /* apply the text track information */
1536 __mmplayer_set_decode_track_info(player, MM_PLAYER_TRACK_TYPE_TEXT);
1538 if (player->track[MM_PLAYER_TRACK_TYPE_TEXT].total_track_num > 0)
1539 player->has_closed_caption = TRUE;
1541 /* create text decode path */
1542 player->no_more_pad = TRUE;
1544 if (!__mmplayer_create_sink_path(player, text_selector, MM_PLAYER_TRACK_TYPE_TEXT, NULL)) {
1545 LOGE("failed to create text sink path");
1554 __mmplayer_gst_set_queue2_buffering(mmplayer_t *player)
1556 gint64 dur_bytes = 0L;
1559 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
1560 player->pipeline->mainbin && player->streamer, FALSE);
1562 if (!gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
1563 LOGE("fail to get duration.");
1565 /* there is no mq, enable use-buffering on queue2 (ex) wav streaming
1566 * use file information was already set on Q2 when it was created. */
1567 _mm_player_streaming_set_queue2(player->streamer,
1568 player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst,
1569 TRUE, /* use_buffering */
1570 MUXED_BUFFER_TYPE_MAX, /* use previous buffer type setting */
1571 ((dur_bytes > 0) ? ((guint64)dur_bytes) : 0));
1578 _mmplayer_gst_decode_no_more_pads(GstElement *elem, gpointer data)
1580 mmplayer_t *player = NULL;
1581 GstElement *video_selector = NULL;
1582 GstElement *audio_selector = NULL;
1583 GstElement *text_selector = NULL;
1586 player = (mmplayer_t *)data;
1588 LOGD("no-more-pad signal handling");
1590 if ((player->cmd == MMPLAYER_COMMAND_DESTROY) ||
1591 (player->cmd == MMPLAYER_COMMAND_UNREALIZE)) {
1592 LOGW("player is shutting down");
1596 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
1597 (!player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst) &&
1598 (player->pipeline->mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst)) {
1599 if (!__mmplayer_gst_set_queue2_buffering(player)) {
1600 LOGE("failed to set queue2 buffering");
1605 video_selector = player->pipeline->mainbin[MMPLAYER_M_V_INPUT_SELECTOR].gst;
1606 audio_selector = player->pipeline->mainbin[MMPLAYER_M_A_INPUT_SELECTOR].gst;
1607 text_selector = player->pipeline->mainbin[MMPLAYER_M_T_INPUT_SELECTOR].gst;
1609 if (!video_selector && !audio_selector && !text_selector) {
1610 LOGW("there is no selector");
1611 player->no_more_pad = TRUE;
1615 /* create video path followed by video-select */
1616 if (video_selector && !audio_selector && !text_selector)
1617 player->no_more_pad = TRUE;
1619 if (!__mmplayer_create_sink_path(player, video_selector, MM_PLAYER_TRACK_TYPE_VIDEO, NULL))
1622 /* create audio path followed by audio-select */
1623 if (audio_selector && !text_selector)
1624 player->no_more_pad = TRUE;
1626 if (!__mmplayer_create_audio_sink_path(player, audio_selector))
1629 /* create text path followed by text-select */
1630 __mmplayer_create_text_sink_path(player, text_selector);
1633 _mmplayer_set_reconfigure_state(player, FALSE);
1638 __mmplayer_gst_add_sinkbin_to_pipeline(mmplayer_t *player, GstElement *sinkbin, GstPad *pad, gboolean reusing, gchar *sink_pad_name)
1640 gboolean ret = FALSE;
1641 GstElement *pipeline = NULL;
1642 GstPad *sinkpad = NULL;
1645 MMPLAYER_RETURN_VAL_IF_FAIL(sinkbin && pad, FALSE);
1646 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
1648 pipeline = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
1650 sinkpad = gst_element_get_static_pad(GST_ELEMENT(sinkbin), sink_pad_name);
1652 LOGE("failed to get pad from sinkbin");
1658 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1659 LOGE("failed to link sinkbin for reusing");
1660 goto EXIT; /* exit either pass or fail */
1664 if (gst_element_set_state(sinkbin, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) {
1665 LOGE("failed to set state(READY) to sinkbin");
1670 if (!gst_bin_add(GST_BIN(pipeline), sinkbin)) {
1671 LOGE("failed to add sinkbin to pipeline");
1676 if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
1677 LOGE("failed to link %s:%s - %s:%s", GST_DEBUG_PAD_NAME(pad), GST_DEBUG_PAD_NAME(sinkpad));
1682 if (gst_element_set_state(sinkbin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
1683 LOGE("failed to set state(PAUSED) to sinkbin");
1692 gst_object_unref(GST_OBJECT(sinkpad));
1700 __mmplayer_gst_create_sink_bin(GstElement *elem, GstPad *pad, GstCaps *ref_caps, gpointer data)
1702 mmplayer_t *player = NULL;
1703 GstCaps *caps = NULL;
1704 gchar *caps_str = NULL;
1705 GstStructure *str = NULL;
1706 const gchar *name = NULL;
1707 GstElement *sinkbin = NULL;
1708 gboolean reusing = FALSE;
1709 gboolean caps_ret = TRUE;
1710 gchar *sink_pad_name = "sink";
1713 player = (mmplayer_t *)data;
1716 MMPLAYER_RETURN_IF_FAIL(elem && pad);
1717 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && MMPLAYER_GET_ATTRS(player));
1718 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
1720 MMPLAYER_GST_GET_CAPS_INFO(ref_caps, str, name, caps_ret);
1724 gst_caps_unref(caps);
1725 caps = gst_caps_ref(ref_caps);
1728 caps_str = gst_caps_to_string(caps);
1730 LOGD("detected mimetype : %s", name);
1732 if (strstr(name, "audio")) {
1733 if (player->pipeline->audiobin == NULL) {
1734 const gchar *audio_format = gst_structure_get_string(str, "format");
1736 LOGD("original audio format %s", audio_format);
1737 mm_player_set_attribute((MMHandleType)player, NULL,
1738 "content_audio_format", audio_format, strlen(audio_format), NULL);
1741 if (__mmplayer_gst_create_audio_sink_bin(player) != MM_ERROR_NONE) {
1742 LOGE("failed to create audiobin. continuing without audio");
1746 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1747 LOGD("creating audiobin success");
1750 sinkbin = player->pipeline->audiobin[MMPLAYER_A_BIN].gst;
1751 LOGD("reusing audiobin");
1752 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
1754 } else if (strstr(name, "video")) {
1755 /* 1. zero copy is updated at _decode_pad_added()
1756 * 2. NULL surface type is handled in _decode_pad_added() */
1757 LOGD("zero copy %d", player->set_mode.video_zc);
1758 if (player->pipeline->videobin == NULL) {
1759 int surface_type = 0;
1760 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
1761 LOGD("display_surface_type (%d)", surface_type);
1763 if ((surface_type == MM_DISPLAY_SURFACE_OVERLAY) &&
1764 (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE)) {
1765 LOGE("failed to acquire video overlay resource");
1769 player->interrupted_by_resource = FALSE;
1771 if (__mmplayer_gst_create_video_sink_bin(player, caps, surface_type) != MM_ERROR_NONE) {
1772 LOGE("failed to create videobin. continuing without video");
1776 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1777 LOGD("creating videosink bin success");
1780 sinkbin = player->pipeline->videobin[MMPLAYER_V_BIN].gst;
1781 LOGD("re-using videobin");
1782 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
1784 } else if (strstr(name, "text")) {
1785 if (player->pipeline->textbin == NULL) {
1786 if (__mmplayer_gst_create_text_sink_bin(player) != MM_ERROR_NONE) {
1787 LOGE("failed to create text sink bin. continuing without text");
1791 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1792 player->textsink_linked = 1;
1793 LOGD("creating textsink bin success");
1795 if (!player->textsink_linked) {
1796 LOGD("re-using textbin");
1798 sinkbin = player->pipeline->textbin[MMPLAYER_T_BIN].gst;
1799 player->textsink_linked = 1;
1801 /* linked textbin exist which means that the external subtitle path exist already */
1802 LOGW("ignoring internal subtitle since external subtitle is available");
1805 sink_pad_name = "text_sink";
1807 LOGW("unknown mime type %s, ignoring it", name);
1811 if (!__mmplayer_gst_add_sinkbin_to_pipeline(player, sinkbin, pad, reusing, sink_pad_name))
1814 LOGD("[handle: %p] success to create and link sink bin", player);
1816 /* FIXIT : we cannot hold callback for 'no-more-pad' signal because signal was emitted in
1817 * streaming task. if the task blocked, then buffer will not flow to the next element
1818 *(autoplugging element). so this is special hack for streaming. please try to remove it
1820 /* dec stream count. we can remove fakesink if it's zero */
1821 if (player->num_dynamic_pad)
1822 player->num_dynamic_pad--;
1824 LOGD("no more pads: %d, stream count dec : %d(num of dynamic pad)", player->no_more_pad, player->num_dynamic_pad);
1826 if ((player->no_more_pad) && (player->num_dynamic_pad == 0))
1827 _mmplayer_pipeline_complete(NULL, player);
1831 MMPLAYER_FREEIF(caps_str);
1834 gst_caps_unref(caps);
1840 __mmplayer_get_property_value_for_rotation(mmplayer_t *player, int display_angle, int orientation, int *value)
1842 int required_angle = 0; /* Angle required for straight view */
1843 int rotation_angle = 0;
1845 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
1846 MMPLAYER_RETURN_VAL_IF_FAIL(value, FALSE);
1848 /* Counter clockwise */
1849 switch (orientation) {
1854 required_angle = 270;
1857 required_angle = 180;
1860 required_angle = 90;
1864 rotation_angle = display_angle + required_angle;
1865 if (rotation_angle >= 360)
1866 rotation_angle -= 360;
1868 /* check if supported or not */
1869 if (rotation_angle % 90) {
1870 LOGD("not supported rotation angle = %d", rotation_angle);
1874 switch (rotation_angle) {
1876 *value = MM_DISPLAY_ROTATION_NONE;
1879 *value = MM_DISPLAY_ROTATION_90;
1882 *value = MM_DISPLAY_ROTATION_180;
1885 *value = MM_DISPLAY_ROTATION_270;
1889 LOGD("setting rotation property value : %d", *value);
1895 _mmplayer_get_video_angle(mmplayer_t *player, int *display_angle, int *orientation)
1897 int display_rotation = 0;
1898 gchar *org_orient = NULL;
1899 MMHandleType attrs = MMPLAYER_GET_ATTRS(player);
1902 LOGE("cannot get content attribute");
1903 return MM_ERROR_PLAYER_INTERNAL;
1906 if (display_angle) {
1907 /* update user rotation */
1908 mm_attrs_get_int_by_name(attrs, "display_rotation", &display_rotation);
1910 /* Counter clockwise */
1911 switch (display_rotation) {
1912 case MM_DISPLAY_ROTATION_NONE:
1915 case MM_DISPLAY_ROTATION_90:
1916 *display_angle = 90;
1918 case MM_DISPLAY_ROTATION_180:
1919 *display_angle = 180;
1921 case MM_DISPLAY_ROTATION_270:
1922 *display_angle = 270;
1925 LOGW("wrong angle type : %d", display_rotation);
1928 LOGD("check user angle: %d", *display_angle);
1932 /* Counter clockwise */
1933 mm_attrs_get_string_by_name(attrs, "content_video_orientation", &org_orient);
1936 if (!strcmp(org_orient, "rotate-90"))
1938 else if (!strcmp(org_orient, "rotate-180"))
1940 else if (!strcmp(org_orient, "rotate-270"))
1943 LOGD("original rotation is %s", org_orient);
1945 LOGD("content_video_orientation get fail");
1948 LOGD("check orientation: %d", *orientation);
1951 return MM_ERROR_NONE;
1954 static void __mmplayer_video_param_set_display_rotation(mmplayer_t *player)
1956 int rotation_value = 0;
1957 int orientations = 0; // current supported angle values are 0, 90, 180, 270
1958 int display_angle = 0;
1961 /* check video sinkbin is created */
1962 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1965 _mmplayer_get_video_angle(player, &display_angle, &orientations);
1967 /* get rotation value to set */
1968 __mmplayer_get_property_value_for_rotation(player, display_angle, orientations, &rotation_value);
1969 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "rotate", rotation_value, NULL);
1970 LOGD("set video param : rotate %d", rotation_value);
1973 static void __mmplayer_video_param_set_display_visible(mmplayer_t *player)
1975 MMHandleType attrs = 0;
1979 /* check video sinkbin is created */
1980 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
1983 attrs = MMPLAYER_GET_ATTRS(player);
1984 MMPLAYER_RETURN_IF_FAIL(attrs);
1986 mm_attrs_get_int_by_name(attrs, "display_visible", &visible);
1987 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "visible", visible, NULL);
1988 LOGD("set video param : visible %d", visible);
1991 static void __mmplayer_video_param_set_display_method(mmplayer_t *player)
1993 MMHandleType attrs = 0;
1994 int display_method = 0;
1997 /* check video sinkbin is created */
1998 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2001 attrs = MMPLAYER_GET_ATTRS(player);
2002 MMPLAYER_RETURN_IF_FAIL(attrs);
2004 mm_attrs_get_int_by_name(attrs, "display_method", &display_method);
2005 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "display-geometry-method", display_method, NULL);
2006 LOGD("set video param : method %d", display_method);
2009 static void __mmplayer_video_param_set_video_roi_area(mmplayer_t *player)
2011 MMHandleType attrs = 0;
2015 /* check video sinkbin is created */
2016 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2019 attrs = MMPLAYER_GET_ATTRS(player);
2020 MMPLAYER_RETURN_IF_FAIL(attrs);
2022 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2023 MMPLAYER_RETURN_IF_FAIL(handle);
2025 gst_video_overlay_set_video_roi_area(
2026 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2027 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2028 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
2029 player->video_roi.scale_x, player->video_roi.scale_y, player->video_roi.scale_width, player->video_roi.scale_height);
2032 static void __mmplayer_video_param_set_roi_area(mmplayer_t *player)
2034 MMHandleType attrs = 0;
2039 int win_roi_width = 0;
2040 int win_roi_height = 0;
2043 /* check video sinkbin is created */
2044 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2047 attrs = MMPLAYER_GET_ATTRS(player);
2048 MMPLAYER_RETURN_IF_FAIL(attrs);
2050 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2051 MMPLAYER_RETURN_IF_FAIL(handle);
2053 /* It should be set after setting window */
2054 mm_attrs_multiple_get(attrs, NULL,
2055 "display_win_roi_x", &win_roi_x,
2056 "display_win_roi_y", &win_roi_y,
2057 "display_win_roi_width", &win_roi_width,
2058 "display_win_roi_height", &win_roi_height, NULL);
2060 /* After setting window handle, set display roi area */
2061 gst_video_overlay_set_display_roi_area(
2062 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2063 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2064 LOGD("set video param : roi area : x(%d) y(%d) width(%d) height(%d)",
2065 win_roi_x, win_roi_y, win_roi_width, win_roi_height);
2068 static void __mmplayer_video_param_set_display_overlay(mmplayer_t *player)
2070 MMHandleType attrs = 0;
2073 /* check video sinkbin is created */
2074 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY))
2077 attrs = MMPLAYER_GET_ATTRS(player);
2078 MMPLAYER_RETURN_IF_FAIL(attrs);
2080 /* common case if using overlay surface */
2081 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
2082 MMPLAYER_RETURN_IF_FAIL(handle);
2084 /* default is using wl_surface_id */
2085 LOGD("set video param : wl_surface_id %d", handle);
2086 gst_video_overlay_set_wl_window_wl_surface_id(
2087 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
2092 _mmplayer_update_video_overlay_param(mmplayer_t *player, const char *param_name)
2094 gboolean update_all_param = FALSE;
2098 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_OVERLAY)) {
2099 LOGW("videosink is not ready yet");
2100 return MM_ERROR_PLAYER_NOT_INITIALIZED;
2103 if (strcmp(player->ini.videosink_element_overlay, "tizenwlsink")) {
2104 LOGE("invalid videosink [%s]", player->ini.videosink_element_overlay);
2105 return MM_ERROR_PLAYER_INTERNAL;
2108 LOGD("param_name : %s", param_name);
2109 if (!g_strcmp0(param_name, "update_all_param"))
2110 update_all_param = TRUE;
2112 if (update_all_param || !g_strcmp0(param_name, "display_overlay"))
2113 __mmplayer_video_param_set_display_overlay(player);
2114 if (update_all_param || !g_strcmp0(param_name, "display_method"))
2115 __mmplayer_video_param_set_display_method(player);
2116 if (update_all_param || !g_strcmp0(param_name, "display_visible"))
2117 __mmplayer_video_param_set_display_visible(player);
2118 if (update_all_param || !g_strcmp0(param_name, "display_rotation"))
2119 __mmplayer_video_param_set_display_rotation(player);
2120 if (update_all_param || !g_strcmp0(param_name, "display_win_roi_x"))
2121 __mmplayer_video_param_set_roi_area(player);
2122 if (update_all_param)
2123 __mmplayer_video_param_set_video_roi_area(player);
2127 return MM_ERROR_NONE;
2131 _mmplayer_set_audio_only(MMHandleType hplayer, bool audio_only)
2133 gboolean disable_overlay = FALSE;
2134 mmplayer_t *player = (mmplayer_t *)hplayer;
2137 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2138 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2139 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2140 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2142 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2143 LOGW("Display control is not supported");
2144 return MM_ERROR_PLAYER_INTERNAL;
2147 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2149 if (audio_only == (bool)disable_overlay) {
2150 LOGE("It's the same with current setting: (%d)", audio_only);
2151 return MM_ERROR_NONE;
2155 LOGE("disable overlay");
2156 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", TRUE, NULL);
2158 /* release overlay resource */
2159 if (__mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2160 LOGE("failed to release overlay resource");
2164 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_OVERLAY) != MM_ERROR_NONE) {
2165 LOGE("failed to acquire video overlay resource");
2168 player->interrupted_by_resource = FALSE;
2170 LOGD("enable overlay");
2171 __mmplayer_video_param_set_display_overlay(player);
2172 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", FALSE, NULL);
2177 return MM_ERROR_NONE;
2181 _mmplayer_get_audio_only(MMHandleType hplayer, bool *paudio_only)
2183 mmplayer_t *player = (mmplayer_t *)hplayer;
2184 gboolean disable_overlay = FALSE;
2188 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
2189 MMPLAYER_RETURN_VAL_IF_FAIL(paudio_only, MM_ERROR_INVALID_ARGUMENT);
2190 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin &&
2191 player->pipeline->videobin[MMPLAYER_V_SINK].gst,
2192 MM_ERROR_PLAYER_NO_OP); /* invalid op */
2194 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "disable-overlay")) {
2195 LOGW("Display control is not supported");
2196 return MM_ERROR_PLAYER_INTERNAL;
2199 g_object_get(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "disable-overlay", &disable_overlay, NULL);
2201 *paudio_only = (bool)disable_overlay;
2203 LOGD("audio_only : %d", *paudio_only);
2207 return MM_ERROR_NONE;
2211 _mmplayer_gst_element_link_bucket(GList *element_bucket)
2213 GList *bucket = element_bucket;
2214 mmplayer_gst_element_t *element = NULL;
2215 mmplayer_gst_element_t *prv_element = NULL;
2216 GstElement *tee_element = NULL;
2217 gint successful_link_count = 0;
2221 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, -1);
2223 prv_element = (mmplayer_gst_element_t *)bucket->data;
2224 bucket = bucket->next;
2226 for (; bucket; bucket = bucket->next) {
2227 element = (mmplayer_gst_element_t *)bucket->data;
2229 if (element && element->gst) {
2230 if (prv_element && prv_element->gst) {
2231 if (strstr(GST_ELEMENT_NAME(element->gst), "audio-tee-queue") && strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2233 prv_element->gst = tee_element;
2235 LOGD("failed to make new audio branch - linking [%s] to [%s] is not supported",
2236 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2237 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2241 if (gst_element_link(GST_ELEMENT(prv_element->gst), GST_ELEMENT(element->gst))) {
2242 LOGD("linking [%s] to [%s] success",
2243 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2244 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2245 successful_link_count++;
2246 if (!strcmp(GST_ELEMENT_NAME(prv_element->gst), "audio-tee")) {
2247 LOGD("keep audio-tee element for next audio pipeline branch");
2248 tee_element = prv_element->gst;
2251 LOGD("linking [%s] to [%s] failed",
2252 GST_ELEMENT_NAME(GST_ELEMENT(prv_element->gst)),
2253 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
2259 prv_element = element;
2264 return successful_link_count;
2268 _mmplayer_gst_element_add_bucket_to_bin(GstBin *bin, GList *element_bucket)
2270 GList *bucket = element_bucket;
2271 mmplayer_gst_element_t *element = NULL;
2272 int successful_add_count = 0;
2276 MMPLAYER_RETURN_VAL_IF_FAIL(element_bucket, 0);
2277 MMPLAYER_RETURN_VAL_IF_FAIL(bin, 0);
2279 for (; bucket; bucket = bucket->next) {
2280 element = (mmplayer_gst_element_t *)bucket->data;
2282 if (element && element->gst) {
2283 if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
2284 LOGD("_mmplayer_gst_element_link_bucket : Adding element [%s] to bin [%s] failed",
2285 GST_ELEMENT_NAME(GST_ELEMENT(element->gst)),
2286 GST_ELEMENT_NAME(GST_ELEMENT(bin)));
2289 successful_add_count++;
2295 return successful_add_count;
2299 __mmplayer_gst_caps_notify_cb(GstPad *pad, GParamSpec *unused, gpointer data)
2301 mmplayer_t *player = (mmplayer_t *)data;
2302 GstCaps *caps = NULL;
2303 GstStructure *str = NULL;
2305 gboolean caps_ret = TRUE;
2309 MMPLAYER_RETURN_IF_FAIL(pad);
2310 MMPLAYER_RETURN_IF_FAIL(unused);
2311 MMPLAYER_RETURN_IF_FAIL(data);
2313 MMPLAYER_GST_GET_CAPS_INFO_FROM_PAD(pad, caps, str, name, caps_ret);
2317 LOGD("name = %s", name);
2319 if (strstr(name, "audio")) {
2320 _mmplayer_update_content_attrs(player, ATTR_AUDIO);
2322 if (player->audio_stream_changed_cb) {
2323 LOGE("call the audio stream changed cb");
2324 player->audio_stream_changed_cb(player->audio_stream_changed_cb_user_param);
2326 } else if (strstr(name, "video")) {
2327 if ((name = gst_structure_get_string(str, "format")))
2328 player->set_mode.video_zc = name[0] == 'S';
2330 _mmplayer_update_content_attrs(player, ATTR_VIDEO);
2331 MMPLAYER_POST_MSG(player, MM_MESSAGE_VIDEO_STREAM_CHANGED, NULL);
2333 LOGW("invalid caps info");
2338 gst_caps_unref(caps);
2346 _mmplayer_audio_stream_clear_buffer(mmplayer_t *player, gboolean send_all)
2351 MMPLAYER_RETURN_IF_FAIL(player);
2353 if (player->audio_stream_buff_list) {
2354 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2355 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2358 LOGD("[%"G_GUINT64_FORMAT"] send remained data.", tmp->channel_mask);
2359 __mmplayer_audio_stream_send_data(player, tmp);
2361 MMPLAYER_FREEIF(tmp->pcm_data);
2362 MMPLAYER_FREEIF(tmp);
2365 g_list_free(player->audio_stream_buff_list);
2366 player->audio_stream_buff_list = NULL;
2373 __mmplayer_audio_stream_send_data(mmplayer_t *player, mmplayer_audio_stream_buff_t *a_buffer)
2375 mmplayer_audio_decoded_data_info_t audio_stream = { 0, };
2378 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2380 audio_stream.bitrate = a_buffer->bitrate;
2381 audio_stream.channel = a_buffer->channel;
2382 audio_stream.channel_mask = a_buffer->channel_mask;
2383 audio_stream.data_size = a_buffer->data_size;
2384 audio_stream.data = a_buffer->pcm_data;
2385 audio_stream.pcm_format = a_buffer->pcm_format;
2387 LOGD("[%"G_GUINT64_FORMAT"] send data size:%d, %p", audio_stream.channel_mask, audio_stream.data_size, player->audio_decoded_cb_user_param);
2389 player->audio_decoded_cb(&audio_stream, player->audio_decoded_cb_user_param);
2395 __mmplayer_audio_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
2397 mmplayer_t *player = (mmplayer_t *)data;
2398 const gchar *pcm_format = NULL;
2401 guint64 channel_mask = 0;
2402 void *a_data = NULL;
2404 mmplayer_audio_stream_buff_t *a_buffer = NULL;
2405 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
2409 MMPLAYER_RETURN_IF_FAIL(player && player->audio_decoded_cb);
2411 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
2412 a_data = mapinfo.data;
2413 a_size = mapinfo.size;
2415 GstCaps *caps = gst_pad_get_current_caps(pad);
2416 GstStructure *structure = gst_caps_get_structure(caps, 0);
2418 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
2420 pcm_format = gst_structure_get_string(structure, "format");
2421 gst_structure_get_int(structure, "rate", &rate);
2422 gst_structure_get_int(structure, "channels", &channel);
2423 gst_structure_get(structure, "channel-mask", GST_TYPE_BITMASK, &channel_mask, NULL);
2424 gst_caps_unref(GST_CAPS(caps));
2426 /* In case of the sync is false, use buffer list. *
2427 * The num of buffer list depends on the num of audio channels */
2428 if (player->audio_stream_buff_list) {
2429 for (l = g_list_first(player->audio_stream_buff_list); l; l = g_list_next(l)) {
2430 mmplayer_audio_stream_buff_t *tmp = (mmplayer_audio_stream_buff_t *)l->data;
2432 if (channel_mask == tmp->channel_mask) {
2434 LOGD("[%"G_GUINT64_FORMAT"] total: %d, data: %d, buffer: %d", channel_mask, tmp->data_size, a_size, tmp->buff_size);
2436 if (tmp->data_size + a_size < tmp->buff_size) {
2437 memcpy(tmp->pcm_data + tmp->data_size, a_data, a_size);
2438 tmp->data_size += a_size;
2440 /* send data to client */
2441 __mmplayer_audio_stream_send_data(player, tmp);
2443 if (a_size > tmp->buff_size) {
2444 LOGD("[%"G_GUINT64_FORMAT"] adj buffer size %d -> %d", channel_mask, tmp->buff_size, a_size);
2445 tmp->pcm_data = g_realloc(tmp->pcm_data, a_size);
2446 if (tmp->pcm_data == NULL) {
2447 LOGE("failed to realloc data.");
2450 tmp->buff_size = a_size;
2452 memset(tmp->pcm_data, 0x00, tmp->buff_size);
2453 memcpy(tmp->pcm_data, a_data, a_size);
2454 tmp->data_size = a_size;
2459 LOGE("data is empty in list.");
2465 /* create new audio stream data for newly found audio channel */
2466 a_buffer = (mmplayer_audio_stream_buff_t *)g_try_malloc0(sizeof(mmplayer_audio_stream_buff_t));
2467 if (a_buffer == NULL) {
2468 LOGE("failed to alloc data.");
2471 a_buffer->bitrate = rate;
2472 a_buffer->channel = channel;
2473 a_buffer->channel_mask = channel_mask;
2474 a_buffer->data_size = a_size;
2475 a_buffer->pcm_format = _mmplayer_convert_audio_pcm_str_to_media_format_mime(pcm_format);
2477 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK) {
2478 /* If sync is FALSE, use buffer list to reduce the IPC. */
2479 a_buffer->buff_size = (a_size > player->ini.pcm_buffer_size) ? (a_size) : (player->ini.pcm_buffer_size);
2480 a_buffer->pcm_data = g_try_malloc(a_buffer->buff_size);
2481 if (a_buffer->pcm_data == NULL) {
2482 LOGE("failed to alloc data.");
2483 MMPLAYER_FREEIF(a_buffer);
2486 memcpy(a_buffer->pcm_data, a_data, a_size);
2488 LOGD("new [%"G_GUINT64_FORMAT"] total:%d buff:%d", channel_mask, a_buffer->data_size, a_buffer->buff_size);
2490 player->audio_stream_buff_list = g_list_append(player->audio_stream_buff_list, a_buffer);
2492 /* If sync is TRUE, send data directly. */
2493 a_buffer->pcm_data = a_data;
2494 __mmplayer_audio_stream_send_data(player, a_buffer);
2495 MMPLAYER_FREEIF(a_buffer);
2499 gst_buffer_unmap(buffer, &mapinfo);
2504 __mmplayer_gst_audio_deinterleave_pad_added(GstElement *elem, GstPad *pad, gpointer data)
2506 mmplayer_t *player = (mmplayer_t *)data;
2507 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
2508 GstPad *sinkpad = NULL;
2509 GstElement *queue = NULL, *sink = NULL;
2512 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2514 queue = gst_element_factory_make("queue", NULL);
2515 if (queue == NULL) {
2516 LOGD("fail make queue");
2520 sink = gst_element_factory_make("fakesink", NULL);
2522 LOGD("fail make fakesink");
2526 gst_bin_add_many(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), queue, sink, NULL);
2528 if (!gst_element_link_pads_full(queue, "src", sink, "sink", GST_PAD_LINK_CHECK_NOTHING)) {
2529 LOGW("failed to link queue & sink");
2533 sinkpad = gst_element_get_static_pad(queue, "sink");
2535 if (GST_PAD_LINK_OK != gst_pad_link(pad, sinkpad)) {
2536 LOGW("failed to link [%s:%s] to queue", GST_DEBUG_PAD_NAME(pad));
2540 LOGE("audio_extract_opt : 0x%X", player->audio_extract_opt);
2542 gst_object_unref(sinkpad);
2543 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
2544 g_object_set(sink, "sync", TRUE, NULL);
2545 g_object_set(sink, "signal-handoffs", TRUE, NULL);
2547 /* keep the first sink reference only */
2548 if (!audiobin[MMPLAYER_A_SINK].gst) {
2549 audiobin[MMPLAYER_A_SINK].id = MMPLAYER_A_SINK;
2550 audiobin[MMPLAYER_A_SINK].gst = sink;
2554 _mmplayer_add_signal_connection(player,
2556 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2558 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
2561 __mmplayer_add_sink(player, sink, FALSE);
2563 if (gst_element_sync_state_with_parent(queue) == GST_STATE_CHANGE_FAILURE) {
2564 LOGE("failed to sync state");
2568 if (gst_element_sync_state_with_parent(sink) == GST_STATE_CHANGE_FAILURE) {
2569 LOGE("failed to sync state");
2577 LOGE("__mmplayer_gst_audio_deinterleave_pad_added ERROR");
2579 gst_object_unref(GST_OBJECT(queue));
2583 gst_object_unref(GST_OBJECT(sink));
2587 gst_object_unref(GST_OBJECT(sinkpad));
2595 __mmplayer_gst_audio_deinterleave_no_more_pads(GstElement* object, gpointer data)
2597 mmplayer_t *player = (mmplayer_t *)data;
2600 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->mainbin);
2602 player->no_more_pad = TRUE;
2603 _mmplayer_pipeline_complete(NULL, player);
2610 __mmplayer_gst_set_pulsesink_property(mmplayer_t *player)
2612 #define MAX_PROPS_LEN 128
2613 mmplayer_gst_element_t *audiobin = NULL;
2614 gint latency_mode = 0;
2615 gchar *stream_type = NULL;
2616 gchar *latency = NULL;
2618 gchar stream_props[MAX_PROPS_LEN] = {0,};
2619 GstStructure *props = NULL;
2622 * It should be set after player creation through attribute.
2623 * But, it can not be changed during playing.
2626 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->audiobin);
2628 audiobin = player->pipeline->audiobin;
2630 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "volume", player->sound.volume, NULL);
2631 if (player->sound.mute) {
2632 LOGD("mute enabled");
2633 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "mute", player->sound.mute, NULL);
2636 mm_attrs_get_int_by_name(player->attrs, "sound_stream_index", &stream_id);
2637 mm_attrs_get_string_by_name(player->attrs, "sound_stream_type", &stream_type);
2640 snprintf(stream_props, sizeof(stream_props) - 1,
2641 "props,application.process.id.origin=%d", player->client_pid);
2643 snprintf(stream_props, sizeof(stream_props) - 1,
2644 "props,media.role=%s, media.parent_id=%d, application.process.id.origin=%d",
2645 stream_type, stream_id, player->client_pid);
2647 props = gst_structure_from_string(stream_props, NULL);
2648 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "stream-properties", props, NULL);
2649 LOGI("props result[%s].", stream_props);
2650 gst_structure_free(props);
2652 mm_attrs_get_int_by_name(player->attrs, "sound_latency_mode", &latency_mode);
2654 switch (latency_mode) {
2655 case AUDIO_LATENCY_MODE_LOW:
2656 latency = g_strdup("low");
2658 case AUDIO_LATENCY_MODE_MID:
2659 latency = g_strdup("mid");
2661 case AUDIO_LATENCY_MODE_HIGH:
2662 latency = g_strdup("high");
2665 latency = g_strdup("mid");
2669 g_object_set(audiobin[MMPLAYER_A_SINK].gst, "latency", latency, NULL);
2671 LOGD("audiosink property - latency=%s", latency);
2673 MMPLAYER_FREEIF(latency);
2679 __mmplayer_gst_set_openalsink_property(mmplayer_t *player)
2681 mmplayer_gst_element_t *audiobin = NULL;
2684 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2685 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2687 audiobin = player->pipeline->audiobin;
2689 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "source-ambisonics-type", 1, NULL);
2690 if (sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &stream_info)) {
2691 LOGE("failed to create media stream info");
2692 return MM_ERROR_PLAYER_INTERNAL;
2695 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "stream-info", stream_info, NULL);
2697 if (player->video360_yaw_radians <= M_PI &&
2698 player->video360_yaw_radians >= -M_PI &&
2699 player->video360_pitch_radians <= M_PI_2 &&
2700 player->video360_pitch_radians >= -M_PI_2) {
2701 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2702 "source-orientation-y", (int)(player->video360_yaw_radians * 180.0 / M_PI),
2703 "source-orientation-x", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
2704 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
2705 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst),
2706 "source-orientation-y", player->video360_metadata.init_view_heading,
2707 "source-orientation-x", player->video360_metadata.init_view_pitch, NULL);
2711 return MM_ERROR_NONE;
2715 __mmplayer_gst_make_audio_playback_sink(mmplayer_t *player, GList **bucket)
2717 mmplayer_gst_element_t *audiobin = NULL;
2718 GstPad *sink_pad = NULL;
2719 GstCaps *acaps = NULL;
2721 int pitch_control = 0;
2722 double pitch_value = 1.0;
2725 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2726 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2728 audiobin = player->pipeline->audiobin;
2730 LOGD("make element for normal audio playback");
2732 /* audio bin structure for playback. {} means optional.
2733 optional : pitch, audioeq, custom audioeq, openalsink for 360 audio content
2735 * src - ... - {aconv - pitch} - aconv - rgvolume - resample - volume -
2736 {audioeq} - {custom audioeq} - pulsesink or {aconv - capsfilter - openalsink}
2739 /* for pitch control */
2740 mm_attrs_multiple_get(player->attrs, NULL,
2741 MM_PLAYER_PITCH_CONTROL, &pitch_control,
2742 MM_PLAYER_PITCH_VALUE, &pitch_value,
2745 LOGD("pitch %d / %1.3f", pitch_control, pitch_value);
2746 if (pitch_control && (player->videodec_linked == 0)) {
2747 GstElementFactory *factory;
2749 factory = gst_element_factory_find("pitch");
2751 gst_object_unref(factory);
2754 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_PITCH, "audioconvert", "audio convert pitch", *bucket, player);
2757 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_PITCH, "pitch", "audio pitch", *bucket, player);
2758 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_PITCH].gst), "pitch", (gdouble)pitch_value, NULL);
2760 LOGW("there is no pitch element");
2765 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV, "audioconvert", "audio converter", *bucket, player);
2767 /* replaygain volume */
2768 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RGVOL, "rgvolume", "audio rgvolume", *bucket, player);
2769 if (player->sound.rg_enable)
2770 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", TRUE, NULL);
2772 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_RGVOL].gst), "enable-rgvolume", FALSE, NULL);
2775 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_RESAMPLER, player->ini.audioresampler_element, "audio resampler", *bucket, player);
2777 if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2778 /* currently, only openalsink uses volume element */
2779 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_VOL, "volume", "volume", *bucket, player);
2780 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "volume", player->sound.volume, NULL);
2782 if (player->sound.mute) {
2783 LOGD("mute enabled");
2784 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_VOL].gst), "mute", player->sound.mute, NULL);
2788 mm_attrs_get_int_by_name(player->attrs, "content_audio_channels", &channels);
2790 /* audio effect element. if audio effect is enabled */
2791 if ((strcmp(player->ini.audioeffect_element, ""))
2793 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2794 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER, player->ini.audioeffect_element, "audio effect filter", *bucket, player);
2796 LOGD("audio effect config. bypass = %d, effect type = %d", player->bypass_audio_effect, player->audio_effect_info.effect_type);
2798 if ((!player->bypass_audio_effect)
2799 && (player->ini.use_audio_effect_preset || player->ini.use_audio_effect_custom)) {
2800 if (player->audio_effect_info.effect_type == MM_AUDIO_EFFECT_TYPE_CUSTOM) {
2801 if (!_mmplayer_audio_effect_custom_apply(player))
2802 LOGI("apply audio effect(custom) setting success");
2806 if ((strcmp(player->ini.audioeffect_element_custom, ""))
2807 && (player->set_mode.rich_audio)) {
2808 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_FILTER_SEC, player->ini.audioeffect_element_custom, "audio effect filter custom", *bucket, player);
2812 /* create audio sink */
2813 LOGD("spherical %d, channels %d, ambisonic type %d, format %d, order %d",
2814 player->is_content_spherical, channels, player->video360_metadata.ambisonic_type,
2815 player->video360_metadata.ambisonic_format, player->video360_metadata.ambisonic_order);
2817 /* Note: qtdemux converts audio metadata defaults to openalsink defaults. */
2818 if (player->is_360_feature_enabled &&
2819 player->is_content_spherical &&
2821 player->video360_metadata.ambisonic_type == MMFILE_AMBISONIC_TYPE_PERIPHONIC &&
2822 player->video360_metadata.ambisonic_format == MMFILE_AMBISONIC_FORMAT_AMB &&
2823 player->video360_metadata.ambisonic_order == MMFILE_AMBISONIC_ORDER_FOA) {
2825 strncpy(player->ini.audiosink_element, "openalsink", PLAYER_INI_MAX_STRLEN - 1);
2827 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CONV_BFORMAT, "audioconvert", "audio-converter-bformat", *bucket, player);
2829 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_CAPS_360, "capsfilter", "audio-caps-filter", *bucket, player);
2830 acaps = gst_caps_from_string(SPATIAL_AUDIO_CAPS);
2831 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_CAPS_360].gst), "caps", acaps, NULL);
2832 gst_caps_unref(acaps);
2834 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, "openalsink", "audiosink", *bucket, player);
2836 player->is_openal_plugin_used = TRUE;
2838 if (player->is_360_feature_enabled && player->is_content_spherical)
2839 LOGW("Audio track isn't of the ambisonic type and can't be played back as a spatial sound.");
2840 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audiosink_element, "audiosink", *bucket, player);
2843 if ((MMPLAYER_IS_RTSP_STREAMING(player)) ||
2844 (player->videodec_linked && player->ini.use_system_clock)) {
2845 LOGD("system clock will be used.");
2846 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "provide-clock", FALSE, NULL);
2849 if (g_strrstr(player->ini.audiosink_element, "pulsesink")) {
2850 __mmplayer_gst_set_pulsesink_property(player);
2851 } else if (g_strrstr(player->ini.audiosink_element, "openalsink")) {
2852 if (__mmplayer_gst_set_openalsink_property(player) != MM_ERROR_NONE)
2857 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "qos", TRUE, NULL); /* qos on */
2858 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "slave-method", GST_AUDIO_BASE_SINK_SLAVE_NONE, NULL);
2860 sink_pad = gst_element_get_static_pad(audiobin[MMPLAYER_A_SINK].gst, "sink");
2861 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
2862 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
2863 gst_object_unref(GST_OBJECT(sink_pad));
2865 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
2868 return MM_ERROR_NONE;
2870 ERROR: /* MMPLAYER_CREATE_ELEMENT */
2872 return MM_ERROR_PLAYER_INTERNAL;
2876 __mmplayer_gst_make_audio_extract_sink(mmplayer_t *player, GList **bucket)
2878 mmplayer_gst_element_t *audiobin = NULL;
2879 enum audio_element_id extract_sink_id = MMPLAYER_A_SINK;
2881 gchar *dst_format = NULL;
2883 int dst_samplerate = 0;
2884 int dst_channels = 0;
2885 GstCaps *caps = NULL;
2886 char *caps_str = NULL;
2889 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
2890 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
2892 audiobin = player->pipeline->audiobin;
2894 LOGD("make element for audio extract, option = 0x%X", player->audio_extract_opt);
2896 /* audio bin structure according to the mmplayer_audio_extract_opt_e.
2898 [case 1] extract interleave audio pcm without playback
2899 : MM_PLAYER_AUDIO_EXTRACT_DEFAULT (sync)
2900 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK (non sync)
2902 * src - ... - aconv - resample - capsfilter - fakesink (sync or not)
2904 [case 2] deinterleave for each channel without playback
2905 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE (sync)
2906 MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_AND_DEINTERLEAVE (non sync)
2908 * src - ... - aconv - resample - capsfilter - deinterleave - fakesink (sync or not)
2909 - fakesink (sync or not)
2912 [case 3] [case 1(sync only)] + playback
2913 : MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK
2915 * src - ... - tee - queue1 - playback path
2916 - queue2 - [case1 pipeline with sync]
2918 [case 4] [case 2(sync only)] + playback
2919 : MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE_WITH_PLAYBACK
2921 * src - ... - tee - queue1 - playback path
2922 - queue2 - [case2 pipeline with sync]
2926 /* 1. create tee and playback path
2927 'tee' should be added at first to copy the decoded stream
2929 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_WITH_PLAYBACK) {
2930 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE, "tee", "audio-tee", *bucket, player);
2931 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_TEE].gst), "num-src-pads", 2, NULL);
2933 /* tee - path 1 : for playback path */
2934 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q1, "queue", "audio-tee-queue1", *bucket, player);
2935 __mmplayer_gst_make_audio_playback_sink(player, bucket);
2937 /* tee - path 2 : for extract path */
2938 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_TEE_Q2, "queue", "audio-tee-queue2", *bucket, player);
2939 extract_sink_id = MMPLAYER_A_EXTRACT_SINK; /* there is another playback sink */
2942 /* if there is tee, 'tee - path 2' is linked here */
2944 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CONV, "audioconvert", "audio-ext-conv", *bucket, player);
2947 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_RESAMPLER, player->ini.audioresampler_element, "audio-ext-resampler", *bucket, player);
2949 /* 2. decide the extract pcm format */
2950 mm_attrs_multiple_get(player->attrs, NULL,
2951 MM_PLAYER_PCM_EXT_FORMAT, &dst_format, &dst_len,
2952 MM_PLAYER_PCM_EXT_SAMPLERATE, &dst_samplerate,
2953 MM_PLAYER_PCM_EXT_CHANNELS, &dst_channels,
2956 LOGD("required extract pcm format - format: %s(%d), samplerate : %d, channel: %d",
2957 dst_format, dst_len, dst_samplerate, dst_channels);
2959 if (dst_format == NULL || dst_len == 0 || dst_samplerate == 0 || dst_channels == 0) {
2960 mm_attrs_multiple_get(player->attrs, NULL,
2961 "content_audio_format", &dst_format, &dst_len, /* get string and len */
2962 "content_audio_samplerate", &dst_samplerate,
2963 "content_audio_channels", &dst_channels,
2966 LOGD("apply the decoded pcm format - format: %s(%d), samplerate : %d, channel: %d",
2967 dst_format, dst_len, dst_samplerate, dst_channels);
2969 /* If there is no enough information, set it to platform default value. */
2970 if (dst_format == NULL || _mmplayer_convert_audio_pcm_str_to_media_format_mime(dst_format) == MEDIA_FORMAT_MAX) {
2971 LOGD("set platform default format");
2972 dst_format = DEFAULT_PCM_OUT_FORMAT;
2974 if (dst_samplerate <= 0) dst_samplerate = DEFAULT_PCM_OUT_SAMPLERATE;
2975 if (dst_channels <= 0) dst_channels = DEFAULT_PCM_OUT_CHANNEL;
2978 /* 3. create capsfilter */
2979 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_CAPS, "capsfilter", "audio-ext-caps", *bucket, player);
2980 caps = gst_caps_new_simple("audio/x-raw",
2981 "format", G_TYPE_STRING, dst_format,
2982 "rate", G_TYPE_INT, dst_samplerate,
2983 "channels", G_TYPE_INT, dst_channels,
2986 caps_str = gst_caps_to_string(caps);
2987 LOGD("new caps : %s", caps_str);
2989 g_object_set(GST_ELEMENT(audiobin[MMPLAYER_A_EXTRACT_CAPS].gst), "caps", caps, NULL);
2992 gst_caps_unref(caps);
2993 MMPLAYER_FREEIF(caps_str);
2995 /* 4-1. create deinterleave to extract pcm for each channel */
2996 if (player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_DEINTERLEAVE) {
2997 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_EXTRACT_DEINTERLEAVE, "deinterleave", "deinterleave", *bucket, player);
2998 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst), "keep-positions", TRUE, NULL);
3000 /* audiosink will be added after getting signal for each channel */
3001 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3002 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added", G_CALLBACK(__mmplayer_gst_audio_deinterleave_pad_added), (gpointer)player);
3003 _mmplayer_add_signal_connection(player, G_OBJECT(audiobin[MMPLAYER_A_EXTRACT_DEINTERLEAVE].gst),
3004 MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads", G_CALLBACK(__mmplayer_gst_audio_deinterleave_no_more_pads), (gpointer)player);
3005 player->no_more_pad = FALSE;
3007 /* 4-2. create fakesink to extract interlevaed pcm */
3008 LOGD("add audio fakesink for interleaved audio");
3009 MMPLAYER_CREATE_ELEMENT(audiobin, extract_sink_id, "fakesink", "fakeaudiosink", *bucket, player);
3010 if (!(player->audio_extract_opt & MM_PLAYER_AUDIO_EXTRACT_NO_SYNC_WITH_CLOCK))
3011 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "sync", TRUE, NULL);
3012 g_object_set(G_OBJECT(audiobin[extract_sink_id].gst), "signal-handoffs", TRUE, NULL);
3014 _mmplayer_add_signal_connection(player,
3015 G_OBJECT(audiobin[extract_sink_id].gst),
3016 MM_PLAYER_SIGNAL_TYPE_AUDIOBIN,
3018 G_CALLBACK(__mmplayer_audio_stream_decoded_render_cb),
3021 __mmplayer_add_sink(player, audiobin[extract_sink_id].gst, FALSE);
3025 return MM_ERROR_NONE;
3027 ERROR: /* MMPLAYER_CREATE_ELEMENT */
3029 return MM_ERROR_PLAYER_INTERNAL;
3033 __mmplayer_gst_make_audio_bin_element(mmplayer_t *player, GList **bucket)
3035 int ret = MM_ERROR_NONE;
3036 mmplayer_gst_element_t *audiobin = NULL;
3037 GList *element_bucket = NULL;
3040 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline &&
3041 player->pipeline->audiobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3043 audiobin = player->pipeline->audiobin;
3045 if (player->build_audio_offload) { /* skip all the audio filters */
3046 LOGD("create audio offload sink : %s", player->ini.audio_offload_sink_element);
3048 MMPLAYER_CREATE_ELEMENT(audiobin, MMPLAYER_A_SINK, player->ini.audio_offload_sink_element, "audiosink", element_bucket, player);
3049 g_object_set(G_OBJECT(audiobin[MMPLAYER_A_SINK].gst), "sync", TRUE,
3050 "volume", player->sound.volume, "mute", player->sound.mute, NULL);
3052 __mmplayer_add_sink(player, audiobin[MMPLAYER_A_SINK].gst, FALSE);
3056 /* FIXME: need to mention the supportable condition at API reference */
3057 if (player->audio_decoded_cb && (!MMPLAYER_IS_RTSP_STREAMING(player)))
3058 ret = __mmplayer_gst_make_audio_extract_sink(player, &element_bucket);
3060 ret = __mmplayer_gst_make_audio_playback_sink(player, &element_bucket);
3062 if (ret != MM_ERROR_NONE)
3065 LOGD("success to make audio bin element");
3066 *bucket = element_bucket;
3069 return MM_ERROR_NONE;
3072 LOGE("failed to make audio bin element");
3073 g_list_free(element_bucket);
3077 return MM_ERROR_PLAYER_INTERNAL;
3081 __mmplayer_gst_create_audio_sink_bin(mmplayer_t *player)
3083 mmplayer_gst_element_t *first_element = NULL;
3084 mmplayer_gst_element_t *audiobin = NULL;
3086 GstPad *ghostpad = NULL;
3087 GList *element_bucket = NULL;
3091 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3094 audiobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_A_NUM);
3096 LOGE("failed to allocate memory for audiobin");
3097 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3101 audiobin[MMPLAYER_A_BIN].id = MMPLAYER_A_BIN;
3102 audiobin[MMPLAYER_A_BIN].gst = gst_bin_new("audiobin");
3103 if (!audiobin[MMPLAYER_A_BIN].gst) {
3104 LOGE("failed to create audiobin");
3109 player->pipeline->audiobin = audiobin;
3111 /* create audio filters and audiosink */
3112 if (__mmplayer_gst_make_audio_bin_element(player, &element_bucket) != MM_ERROR_NONE)
3115 /* adding created elements to bin */
3116 LOGD("adding created elements to bin");
3117 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(audiobin[MMPLAYER_A_BIN].gst), element_bucket))
3120 /* linking elements in the bucket by added order. */
3121 LOGD("Linking elements in the bucket by added order.");
3122 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1)
3125 /* get first element's sinkpad for creating ghostpad */
3126 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3127 if (!first_element) {
3128 LOGE("failed to get first elem");
3132 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3134 LOGE("failed to get pad from first element of audiobin");
3138 ghostpad = gst_ghost_pad_new("sink", pad);
3140 LOGE("failed to create ghostpad");
3144 if (!gst_element_add_pad(audiobin[MMPLAYER_A_BIN].gst, ghostpad)) {
3145 LOGE("failed to add ghostpad to audiobin");
3149 gst_object_unref(pad);
3151 g_list_free(element_bucket);
3154 return MM_ERROR_NONE;
3157 LOGD("ERROR : releasing audiobin");
3160 gst_object_unref(GST_OBJECT(pad));
3163 gst_object_unref(GST_OBJECT(ghostpad));
3166 g_list_free(element_bucket);
3168 /* release element which are not added to bin */
3169 for (i = 1; i < MMPLAYER_A_NUM; i++) {
3170 /* NOTE : skip bin */
3171 if (audiobin[i].gst) {
3172 GstObject *parent = NULL;
3173 parent = gst_element_get_parent(audiobin[i].gst);
3176 gst_object_unref(GST_OBJECT(audiobin[i].gst));
3177 audiobin[i].gst = NULL;
3179 gst_object_unref(GST_OBJECT(parent));
3183 /* release audiobin with it's children */
3184 if (audiobin[MMPLAYER_A_BIN].gst)
3185 gst_object_unref(GST_OBJECT(audiobin[MMPLAYER_A_BIN].gst));
3187 MMPLAYER_FREEIF(audiobin);
3189 player->pipeline->audiobin = NULL;
3191 return MM_ERROR_PLAYER_INTERNAL;
3195 _mmplayer_convert_fourcc_string_to_value(const gchar *format_name)
3197 return format_name[0] | (format_name[1] << 8) | (format_name[2] << 16) | (format_name[3] << 24);
3201 _mmplayer_video_stream_release_bo(mmplayer_t *player, void *bo)
3203 int ret = MM_ERROR_NONE;
3205 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
3206 MMPLAYER_RETURN_VAL_IF_FAIL(bo, MM_ERROR_INVALID_ARGUMENT);
3208 MMPLAYER_VIDEO_BO_LOCK(player);
3210 if (player->video_bo_list) {
3211 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3212 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3213 if (tmp && tmp->bo == bo) {
3215 LOGD("release bo %p", bo);
3216 tbm_bo_unref(tmp->bo);
3217 MMPLAYER_VIDEO_BO_UNLOCK(player);
3218 MMPLAYER_VIDEO_BO_SIGNAL(player);
3223 /* hw codec is running or the list was reset for DRC. */
3224 LOGW("there is no bo list.");
3226 MMPLAYER_VIDEO_BO_UNLOCK(player);
3228 LOGW("failed to find bo %p", bo);
3232 __mmplayer_video_stream_bo_list_free(mmplayer_video_bo_info_t *tmp)
3238 tbm_bo_unref(tmp->bo);
3243 __mmplayer_video_stream_destroy_bo_list(mmplayer_t *player)
3246 MMPLAYER_RETURN_IF_FAIL(player);
3248 MMPLAYER_VIDEO_BO_LOCK(player);
3249 if (player->video_bo_list) {
3250 LOGD("destroy video_bo_list : %d", g_list_length(player->video_bo_list));
3251 g_list_free_full(player->video_bo_list, (GDestroyNotify)__mmplayer_video_stream_bo_list_free);
3252 player->video_bo_list = NULL;
3254 player->video_bo_size = 0;
3255 MMPLAYER_VIDEO_BO_UNLOCK(player);
3262 __mmplayer_video_stream_get_bo(mmplayer_t *player, int size)
3265 MMPLAYER_RETURN_VAL_IF_FAIL(player, NULL);
3266 gboolean ret = TRUE;
3268 /* check DRC, if it is, destroy the prev bo list to create again */
3269 if (player->video_bo_size != size) {
3270 LOGD("video size is changed: %d -> %d", player->video_bo_size, size);
3271 __mmplayer_video_stream_destroy_bo_list(player);
3272 player->video_bo_size = size;
3275 MMPLAYER_VIDEO_BO_LOCK(player);
3277 if ((!player->video_bo_list) ||
3278 (g_list_length(player->video_bo_list) < player->ini.num_of_video_bo)) {
3280 /* create bo list */
3282 LOGD("Create bo list for decoded video stream(num:%d)", player->ini.num_of_video_bo);
3284 if (player->video_bo_list) {
3285 /* if bo list did not created all, try it again. */
3286 idx = g_list_length(player->video_bo_list);
3287 LOGD("bo list exist(len: %d)", idx);
3290 for (; idx < player->ini.num_of_video_bo; idx++) {
3291 mmplayer_video_bo_info_t *bo_info = g_new(mmplayer_video_bo_info_t, 1);
3293 LOGE("Fail to alloc bo_info.");
3296 bo_info->bo = tbm_bo_alloc(player->bufmgr, size, TBM_BO_DEFAULT);
3298 LOGE("Fail to tbm_bo_alloc.");
3299 MMPLAYER_FREEIF(bo_info);
3302 bo_info->used = FALSE;
3303 player->video_bo_list = g_list_append(player->video_bo_list, bo_info);
3306 /* update video num buffers */
3307 LOGD("video_num_buffers : %d", idx);
3308 mm_player_set_attribute((MMHandleType)player, NULL,
3309 MM_PLAYER_VIDEO_BUFFER_TOTAL_SIZE, idx,
3310 MM_PLAYER_VIDEO_BUFFER_EXTRA_SIZE, MAX(DEFAULT_NUM_OF_V_OUT_BUFFER, (idx / 2)),
3314 MMPLAYER_VIDEO_BO_UNLOCK(player);
3320 /* get bo from list*/
3321 for (l = g_list_first(player->video_bo_list); l; l = g_list_next(l)) {
3322 mmplayer_video_bo_info_t *tmp = (mmplayer_video_bo_info_t *)l->data;
3323 if (tmp && (tmp->used == FALSE)) {
3324 LOGD("found bo %p to use", tmp->bo);
3326 MMPLAYER_VIDEO_BO_UNLOCK(player);
3327 return tbm_bo_ref(tmp->bo);
3331 LOGE("failed to get bo in %d timeout", player->ini.video_bo_timeout);
3332 MMPLAYER_VIDEO_BO_UNLOCK(player);
3336 if (player->ini.video_bo_timeout <= 0) {
3337 MMPLAYER_VIDEO_BO_WAIT(player);
3339 gint64 timeout = g_get_monotonic_time() + player->ini.video_bo_timeout * G_TIME_SPAN_SECOND;
3340 ret = MMPLAYER_VIDEO_BO_WAIT_UNTIL(player, timeout);
3347 __mmplayer_video_stream_decoded_preroll_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3349 mmplayer_t *player = (mmplayer_t *)data;
3351 MMPLAYER_RETURN_IF_FAIL(player && player->video_decoded_cb);
3353 /* send prerolled pkt */
3354 player->video_stream_prerolled = false;
3356 __mmplayer_video_stream_decoded_render_cb(object, buffer, pad, data);
3358 /* not to send prerolled pkt again */
3359 player->video_stream_prerolled = true;
3363 __mmplayer_video_stream_decoded_render_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
3365 mmplayer_t *player = (mmplayer_t *)data;
3366 mmplayer_video_decoded_data_info_t *stream = NULL;
3367 GstMemory *mem = NULL;
3370 MMPLAYER_RETURN_IF_FAIL(player);
3371 MMPLAYER_RETURN_IF_FAIL(player->video_decoded_cb);
3373 if (player->video_stream_prerolled) {
3374 player->video_stream_prerolled = false;
3375 LOGD("skip the prerolled pkt not to send it again");
3379 /* clear stream data structure */
3380 stream = __mmplayer_create_stream_from_pad(pad);
3382 LOGE("failed to alloc stream");
3386 _mmplayer_get_video_angle(player, NULL, &stream->orientation);
3388 /* set size and timestamp */
3389 mem = gst_buffer_peek_memory(buffer, 0);
3390 stream->length_total = gst_memory_get_sizes(mem, NULL, NULL);
3391 stream->timestamp = (unsigned int)(GST_TIME_AS_MSECONDS(GST_BUFFER_PTS(buffer))); /* nano sec -> milli sec */
3393 /* check zero-copy */
3394 if (player->set_mode.video_zc &&
3395 player->set_mode.video_export &&
3396 gst_is_tizen_memory(mem)) {
3397 __mmplayer_zerocopy_set_stride_elevation_bo(stream, mem);
3398 stream->internal_buffer = gst_buffer_ref(buffer);
3399 } else { /* sw codec */
3400 if (!__mmplayer_swcodec_set_stride_elevation(stream))
3403 if (!__mmplayer_swcodec_set_bo(player, stream, mem))
3407 if (!player->video_decoded_cb(stream, player->video_decoded_cb_user_param)) {
3408 LOGE("failed to send video decoded data.");
3415 LOGE("release video stream resource.");
3416 if (gst_is_tizen_memory(mem)) {
3418 for (i = 0 ; i < MM_VIDEO_BUFFER_PLANE_MAX ; i++) {
3420 tbm_bo_unref(stream->bo[i]);
3423 /* unref gst buffer */
3424 if (stream->internal_buffer)
3425 gst_buffer_unref(stream->internal_buffer);
3428 _mmplayer_video_stream_release_bo(player, stream->bo[0]);
3430 MMPLAYER_FREEIF(stream);
3435 __mmplayer_gst_set_video360_property(mmplayer_t *player)
3437 mmplayer_gst_element_t *videobin = NULL;
3440 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline && player->pipeline->videobin);
3442 videobin = player->pipeline->videobin;
3444 /* Set spatial media metadata and/or user settings to the element.
3446 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3447 "projection-type", player->video360_metadata.projection_type, NULL);
3449 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3450 "stereo-mode", player->video360_metadata.stereo_mode, NULL);
3452 if (player->video360_metadata.full_pano_width_pixels &&
3453 player->video360_metadata.full_pano_height_pixels &&
3454 player->video360_metadata.cropped_area_image_width &&
3455 player->video360_metadata.cropped_area_image_height) {
3456 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3457 "projection-bounds-top", player->video360_metadata.cropped_area_top,
3458 "projection-bounds-bottom", player->video360_metadata.full_pano_height_pixels -
3459 player->video360_metadata.cropped_area_top - player->video360_metadata.cropped_area_image_height,
3460 "projection-bounds-left", player->video360_metadata.cropped_area_left,
3461 "projection-bounds-right", player->video360_metadata.full_pano_width_pixels -
3462 player->video360_metadata.cropped_area_left - player->video360_metadata.cropped_area_image_width,
3466 if (player->video360_horizontal_fov && player->video360_vertical_fov) {
3467 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3468 "horizontal-fov", player->video360_horizontal_fov,
3469 "vertical-fov", player->video360_vertical_fov, NULL);
3472 if (player->video360_zoom <= VIDEO360_MAX_ZOOM && player->video360_zoom > 1.0f) {
3473 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3474 "zoom", 1.0f / player->video360_zoom, NULL);
3477 if (player->video360_yaw_radians <= M_PI &&
3478 player->video360_yaw_radians >= -M_PI &&
3479 player->video360_pitch_radians <= M_PI_2 &&
3480 player->video360_pitch_radians >= -M_PI_2) {
3481 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3482 "pose-yaw", (int)(player->video360_yaw_radians * 180.0 / M_PI),
3483 "pose-pitch", (int)(player->video360_pitch_radians * 180.0 / M_PI), NULL);
3484 } else if (player->video360_metadata.init_view_heading || player->video360_metadata.init_view_pitch) {
3485 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3486 "pose-yaw", player->video360_metadata.init_view_heading,
3487 "pose-pitch", player->video360_metadata.init_view_pitch, NULL);
3490 g_object_set(G_OBJECT(videobin[MMPLAYER_V_360].gst),
3491 "passthrough", !player->is_video360_enabled, NULL);
3498 __mmplayer_gst_create_video_filters(mmplayer_t *player, MMDisplaySurfaceType surface_type, GList **bucket)
3500 gchar *video_csc = "videoconvert"; /* default colorspace converter */
3501 GList *element_bucket = NULL;
3504 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3506 /* create video360 filter */
3507 if (player->is_360_feature_enabled && player->is_content_spherical) {
3508 LOGD("create video360 element");
3509 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_360, "video360", "video-360", element_bucket, player);
3510 __mmplayer_gst_set_video360_property(player);
3514 if (surface_type != MM_DISPLAY_SURFACE_OVERLAY || player->set_mode.video_zc) {
3515 LOGD("skip creating the videoconv and rotator");
3516 return MM_ERROR_NONE;
3519 /* in case of sw codec & overlay surface type, except 360 playback.
3520 * if libav video decoder is selected, videoconvert is required to render the shm wl-buffer which support RGB only via tizenwlsink. */
3521 LOGD("create video converter: %s", video_csc);
3522 MMPLAYER_CREATE_ELEMENT(player->pipeline->videobin, MMPLAYER_V_CONV, video_csc, "video converter", element_bucket, player);
3525 *bucket = element_bucket;
3527 return MM_ERROR_NONE;
3529 ERROR: /* refer MMPLAYER_CREATE_ELEMENT */
3530 g_list_free(element_bucket);
3534 return MM_ERROR_PLAYER_INTERNAL;
3538 __mmplayer_get_videosink_factory_name(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3540 gchar *factory_name = NULL;
3542 switch (surface_type) {
3543 case MM_DISPLAY_SURFACE_OVERLAY:
3544 if (strlen(player->ini.videosink_element_overlay) > 0)
3545 factory_name = player->ini.videosink_element_overlay;
3547 case MM_DISPLAY_SURFACE_REMOTE:
3548 case MM_DISPLAY_SURFACE_NULL:
3549 if (strlen(player->ini.videosink_element_fake) > 0)
3550 factory_name = player->ini.videosink_element_fake;
3553 LOGE("unidentified surface type");
3557 LOGD("surface_type %d, videosink is %s", surface_type, factory_name);
3558 return factory_name;
3562 __mmplayer_gst_set_videosink_property(mmplayer_t *player, MMDisplaySurfaceType surface_type)
3564 gchar *factory_name = NULL;
3565 mmplayer_gst_element_t *videobin = NULL;
3570 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->videobin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3572 videobin = player->pipeline->videobin;
3573 factory_name = GST_OBJECT_NAME(gst_element_get_factory(videobin[MMPLAYER_V_SINK].gst));
3575 attrs = MMPLAYER_GET_ATTRS(player);
3577 LOGE("cannot get content attribute");
3578 return MM_ERROR_PLAYER_INTERNAL;
3581 if (surface_type == MM_DISPLAY_SURFACE_OVERLAY) {
3582 bool use_tbm = (player->set_mode.video_zc || (player->is_360_feature_enabled && player->is_content_spherical));
3583 if (strncmp(factory_name, "tizenwlsink", strlen(factory_name)) == 0) {
3584 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst,
3585 "use-tbm", use_tbm, NULL);
3588 if (_mmplayer_update_video_overlay_param(player, "update_all_param") != MM_ERROR_NONE)
3589 return MM_ERROR_PLAYER_INTERNAL;
3591 LOGI("videosink factory name is %s use-tbm : %d", factory_name, use_tbm);
3594 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3595 "sync", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3598 mm_attrs_get_int_by_name(attrs, MM_PLAYER_GAPLESS_MODE, &gapless);
3600 LOGD("disable last-sample");
3601 g_object_set(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "enable-last-sample", FALSE, NULL);
3604 if (player->set_mode.video_export) {
3606 mm_attrs_get_int_by_name(player->attrs, "enable_video_decoded_cb", &enable);
3607 if (enable || (surface_type == MM_DISPLAY_SURFACE_REMOTE) || (surface_type == MM_DISPLAY_SURFACE_NULL))
3608 g_object_set(G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst), "signal-handoffs", TRUE, NULL);
3610 _mmplayer_add_signal_connection(player,
3611 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3612 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3614 G_CALLBACK(__mmplayer_video_stream_decoded_render_cb),
3617 _mmplayer_add_signal_connection(player,
3618 G_OBJECT(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
3619 MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3621 G_CALLBACK(__mmplayer_video_stream_decoded_preroll_cb),
3625 if (videobin[MMPLAYER_V_SINK].gst) {
3626 GstPad *sink_pad = NULL;
3627 sink_pad = gst_element_get_static_pad(videobin[MMPLAYER_V_SINK].gst, "sink");
3629 _mmplayer_add_signal_connection(player, G_OBJECT(sink_pad), MM_PLAYER_SIGNAL_TYPE_VIDEOBIN,
3630 "notify::caps", G_CALLBACK(__mmplayer_gst_caps_notify_cb), (gpointer)player);
3631 gst_object_unref(GST_OBJECT(sink_pad));
3633 LOGE("failed to get sink pad from videosink");
3637 return MM_ERROR_NONE;
3642 * - video overlay surface(arm/x86) : tizenwlsink
3645 __mmplayer_gst_create_video_sink_bin(mmplayer_t *player, GstCaps *caps, MMDisplaySurfaceType surface_type)
3648 GList *element_bucket = NULL;
3649 mmplayer_gst_element_t *first_element = NULL;
3650 mmplayer_gst_element_t *videobin = NULL;
3651 gchar *videosink_factory_name = NULL;
3654 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3657 videobin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_V_NUM);
3659 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3661 player->pipeline->videobin = videobin;
3664 videobin[MMPLAYER_V_BIN].id = MMPLAYER_V_BIN;
3665 videobin[MMPLAYER_V_BIN].gst = gst_bin_new("videobin");
3666 if (!videobin[MMPLAYER_V_BIN].gst) {
3667 LOGE("failed to create videobin");
3671 if (__mmplayer_gst_create_video_filters(player, surface_type, &element_bucket) != MM_ERROR_NONE)
3674 videosink_factory_name = __mmplayer_get_videosink_factory_name(player, surface_type);
3675 MMPLAYER_CREATE_ELEMENT(videobin, MMPLAYER_V_SINK, videosink_factory_name, "videosink", element_bucket, player);
3677 /* additional setting for sink plug-in */
3678 if (__mmplayer_gst_set_videosink_property(player, surface_type) != MM_ERROR_NONE) {
3679 LOGE("failed to set video property");
3683 /* store it as it's sink element */
3684 __mmplayer_add_sink(player, videobin[MMPLAYER_V_SINK].gst, TRUE);
3686 /* adding created elements to bin */
3687 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(videobin[MMPLAYER_V_BIN].gst), element_bucket)) {
3688 LOGE("failed to add elements");
3692 /* Linking elements in the bucket by added order */
3693 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3694 LOGE("failed to link elements");
3698 /* get first element's sinkpad for creating ghostpad */
3699 first_element = (mmplayer_gst_element_t *)element_bucket->data;
3700 if (!first_element) {
3701 LOGE("failed to get first element from bucket");
3705 pad = gst_element_get_static_pad(GST_ELEMENT(first_element->gst), "sink");
3707 LOGE("failed to get pad from first element");
3711 /* create ghostpad */
3712 player->ghost_pad_for_videobin = gst_ghost_pad_new("sink", pad);
3713 if (!gst_element_add_pad(videobin[MMPLAYER_V_BIN].gst, player->ghost_pad_for_videobin)) {
3714 LOGE("failed to add ghostpad to videobin");
3717 gst_object_unref(pad);
3719 /* done. free allocated variables */
3720 g_list_free(element_bucket);
3724 return MM_ERROR_NONE;
3727 LOGE("ERROR : releasing videobin");
3728 g_list_free(element_bucket);
3731 gst_object_unref(GST_OBJECT(pad));
3733 /* release videobin with it's children */
3734 if (videobin[MMPLAYER_V_BIN].gst)
3735 gst_object_unref(GST_OBJECT(videobin[MMPLAYER_V_BIN].gst));
3737 MMPLAYER_FREEIF(videobin);
3738 player->pipeline->videobin = NULL;
3740 return MM_ERROR_PLAYER_INTERNAL;
3744 __mmplayer_gst_create_plain_text_elements(mmplayer_t *player)
3746 GList *element_bucket = NULL;
3747 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
3749 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_QUEUE, "queue", "text_queue", element_bucket, player);
3750 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_IDENTITY, "identity", "text_identity", element_bucket, player);
3751 g_object_set(G_OBJECT(textbin[MMPLAYER_T_IDENTITY].gst),
3752 "signal-handoffs", FALSE,
3755 MMPLAYER_CREATE_ELEMENT(textbin, MMPLAYER_T_FAKE_SINK, "fakesink", "text_fakesink", element_bucket, player);
3756 _mmplayer_add_signal_connection(player,
3757 G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst),
3758 MM_PLAYER_SIGNAL_TYPE_TEXTBIN,
3760 G_CALLBACK(__mmplayer_update_subtitle),
3763 g_object_set(G_OBJECT(textbin[MMPLAYER_T_FAKE_SINK].gst), "sync", TRUE,
3764 "signal-handoffs", TRUE, "max-lateness", FAKE_SINK_MAX_LATENESS, NULL);
3766 if (!player->play_subtitle) {
3767 LOGD("add textbin sink as sink element of whole pipeline.");
3768 __mmplayer_add_sink(player, GST_ELEMENT(textbin[MMPLAYER_T_FAKE_SINK].gst), FALSE);
3771 /* adding created elements to bin */
3772 LOGD("adding created elements to bin");
3773 if (!_mmplayer_gst_element_add_bucket_to_bin(GST_BIN(textbin[MMPLAYER_T_BIN].gst), element_bucket)) {
3774 LOGE("failed to add elements");
3775 g_list_free(element_bucket);
3779 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3780 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3781 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3783 /* linking elements in the bucket by added order. */
3784 LOGD("Linking elements in the bucket by added order.");
3785 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3786 LOGE("failed to link elements");
3787 g_list_free(element_bucket);
3791 /* done. free allocated variables */
3792 g_list_free(element_bucket);
3794 if (textbin[MMPLAYER_T_QUEUE].gst) {
3796 GstPad *ghostpad = NULL;
3798 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3800 LOGE("failed to get sink pad of text queue");
3804 ghostpad = gst_ghost_pad_new("text_sink", pad);
3805 gst_object_unref(pad);
3808 LOGE("failed to create ghostpad of textbin");
3812 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3813 LOGE("failed to add ghostpad to textbin");
3814 gst_object_unref(ghostpad);
3819 return MM_ERROR_NONE;
3823 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3824 LOGE("remove textbin sink from sink list");
3825 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3828 /* release element at __mmplayer_gst_create_text_sink_bin */
3829 return MM_ERROR_PLAYER_INTERNAL;
3833 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3835 mmplayer_gst_element_t *textbin = NULL;
3836 GList *element_bucket = NULL;
3837 int surface_type = 0;
3842 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3845 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3847 LOGE("failed to allocate memory for textbin");
3848 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3852 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3853 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3854 if (!textbin[MMPLAYER_T_BIN].gst) {
3855 LOGE("failed to create textbin");
3860 player->pipeline->textbin = textbin;
3863 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3864 LOGD("surface type for subtitle : %d", surface_type);
3865 switch (surface_type) {
3866 case MM_DISPLAY_SURFACE_OVERLAY:
3867 case MM_DISPLAY_SURFACE_NULL:
3868 case MM_DISPLAY_SURFACE_REMOTE:
3869 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3870 LOGE("failed to make plain text elements");
3881 return MM_ERROR_NONE;
3885 LOGD("ERROR : releasing textbin");
3887 g_list_free(element_bucket);
3889 /* release signal */
3890 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3892 /* release element which are not added to bin */
3893 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3894 /* NOTE : skip bin */
3895 if (textbin[i].gst) {
3896 GstObject *parent = NULL;
3897 parent = gst_element_get_parent(textbin[i].gst);
3900 gst_object_unref(GST_OBJECT(textbin[i].gst));
3901 textbin[i].gst = NULL;
3903 gst_object_unref(GST_OBJECT(parent));
3908 /* release textbin with it's children */
3909 if (textbin[MMPLAYER_T_BIN].gst)
3910 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3912 MMPLAYER_FREEIF(textbin);
3913 player->pipeline->textbin = NULL;
3916 return MM_ERROR_PLAYER_INTERNAL;
3920 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3922 mmplayer_gst_element_t *mainbin = NULL;
3923 mmplayer_gst_element_t *textbin = NULL;
3924 MMHandleType attrs = 0;
3925 GstElement *subsrc = NULL;
3926 GstElement *subparse = NULL;
3927 gchar *subtitle_uri = NULL;
3928 const gchar *charset = NULL;
3934 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3936 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3938 mainbin = player->pipeline->mainbin;
3940 attrs = MMPLAYER_GET_ATTRS(player);
3942 LOGE("cannot get content attribute");
3943 return MM_ERROR_PLAYER_INTERNAL;
3946 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3947 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3948 LOGE("subtitle uri is not proper filepath.");
3949 return MM_ERROR_PLAYER_INVALID_URI;
3952 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3953 LOGE("failed to get storage info of subtitle path");
3954 return MM_ERROR_PLAYER_INVALID_URI;
3957 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3959 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3960 player->subtitle_language_list = NULL;
3961 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3963 /* create the subtitle source */
3964 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3966 LOGE("failed to create filesrc element");
3969 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3971 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3972 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3974 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3975 LOGW("failed to add queue");
3976 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3977 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3978 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3983 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3985 LOGE("failed to create subparse element");
3989 charset = _mmplayer_get_charset(subtitle_uri);
3991 LOGD("detected charset is %s", charset);
3992 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3995 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3996 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3998 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3999 LOGW("failed to add subparse");
4000 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4001 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4002 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4006 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4007 LOGW("failed to link subsrc and subparse");
4011 player->play_subtitle = TRUE;
4012 player->adjust_subtitle_pos = 0;
4014 LOGD("play subtitle using subtitle file");
4016 if (player->pipeline->textbin == NULL) {
4017 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4018 LOGE("failed to create text sink bin. continuing without text");
4022 textbin = player->pipeline->textbin;
4024 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4025 LOGW("failed to add textbin");
4027 /* release signal */
4028 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4030 /* release textbin with it's children */
4031 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4032 MMPLAYER_FREEIF(player->pipeline->textbin);
4033 player->pipeline->textbin = textbin = NULL;
4037 LOGD("link text input selector and textbin ghost pad");
4039 player->textsink_linked = 1;
4040 player->external_text_idx = 0;
4041 LOGI("textsink is linked");
4043 textbin = player->pipeline->textbin;
4044 LOGD("text bin has been created. reuse it.");
4045 player->external_text_idx = 1;
4048 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4049 LOGW("failed to link subparse and textbin");
4053 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4055 LOGE("failed to get sink pad from textsink to probe data");
4059 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4060 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4062 gst_object_unref(pad);
4065 /* create dot. for debugging */
4066 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4069 return MM_ERROR_NONE;
4072 /* release text pipeline resource */
4073 player->textsink_linked = 0;
4075 /* release signal */
4076 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4078 if (player->pipeline->textbin) {
4079 LOGE("remove textbin");
4081 /* release textbin with it's children */
4082 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4083 MMPLAYER_FREEIF(player->pipeline->textbin);
4084 player->pipeline->textbin = NULL;
4088 /* release subtitle elem */
4089 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4090 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4092 return MM_ERROR_PLAYER_INTERNAL;
4096 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4098 mmplayer_t *player = (mmplayer_t *)data;
4099 MMMessageParamType msg = {0, };
4100 GstClockTime duration = 0;
4101 gpointer text = NULL;
4102 guint text_size = 0;
4103 gboolean ret = TRUE;
4104 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4108 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4109 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4111 if (player->is_subtitle_force_drop) {
4112 LOGW("subtitle is dropped forcedly.");
4116 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4117 text = mapinfo.data;
4118 text_size = mapinfo.size;
4120 if (player->set_mode.subtitle_off) {
4121 LOGD("subtitle is OFF.");
4125 if (!text || (text_size == 0)) {
4126 LOGD("There is no subtitle to be displayed.");
4130 msg.data = (void *)text;
4132 duration = GST_BUFFER_DURATION(buffer);
4134 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4135 if (player->duration > GST_BUFFER_PTS(buffer))
4136 duration = player->duration - GST_BUFFER_PTS(buffer);
4139 LOGI("subtitle duration is invalid, subtitle duration change "
4140 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4142 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4144 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4146 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4147 gst_buffer_unmap(buffer, &mapinfo);
4154 static GstPadProbeReturn
4155 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4157 mmplayer_t *player = (mmplayer_t *)u_data;
4158 GstClockTime cur_timestamp = 0;
4159 gint64 adjusted_timestamp = 0;
4160 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4162 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4164 if (player->set_mode.subtitle_off) {
4165 LOGD("subtitle is OFF.");
4169 if (player->adjust_subtitle_pos == 0) {
4170 LOGD("nothing to do");
4174 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4175 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4177 if (adjusted_timestamp < 0) {
4178 LOGD("adjusted_timestamp under zero");
4183 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4184 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4185 GST_TIME_ARGS(cur_timestamp),
4186 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4188 return GST_PAD_PROBE_OK;
4192 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4196 /* check player and subtitlebin are created */
4197 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4198 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4200 if (position == 0) {
4201 LOGD("nothing to do");
4203 return MM_ERROR_NONE;
4206 /* check current position */
4207 player->adjust_subtitle_pos = position;
4209 LOGD("save adjust_subtitle_pos in player");
4213 return MM_ERROR_NONE;
4217 * This function is to create audio or video pipeline for playing.
4219 * @param player [in] handle of player
4221 * @return This function returns zero on success.
4226 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4228 int ret = MM_ERROR_NONE;
4229 mmplayer_gst_element_t *mainbin = NULL;
4230 MMHandleType attrs = 0;
4233 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4235 /* get profile attribute */
4236 attrs = MMPLAYER_GET_ATTRS(player);
4238 LOGE("failed to get content attribute");
4242 /* create pipeline handles */
4243 if (player->pipeline) {
4244 LOGE("pipeline should be released before create new one");
4248 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4250 /* create mainbin */
4251 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4252 if (mainbin == NULL)
4255 /* create pipeline */
4256 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4257 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4258 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4259 LOGE("failed to create pipeline");
4264 player->pipeline->mainbin = mainbin;
4266 /* create the source and decoder elements */
4267 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4268 ret = _mmplayer_gst_build_es_pipeline(player);
4270 if (MMPLAYER_USE_DECODEBIN(player))
4271 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4273 ret = _mmplayer_gst_build_pipeline_with_src(player);
4276 if (ret != MM_ERROR_NONE) {
4277 LOGE("failed to create some elements");
4281 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4282 if (__mmplayer_check_subtitle(player)
4283 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4284 LOGE("failed to create text pipeline");
4287 ret = _mmplayer_gst_add_bus_watch(player);
4288 if (ret != MM_ERROR_NONE) {
4289 LOGE("failed to add bus watch");
4294 return MM_ERROR_NONE;
4297 _mmplayer_bus_watcher_remove(player);
4298 __mmplayer_gst_destroy_pipeline(player);
4299 return MM_ERROR_PLAYER_INTERNAL;
4303 __mmplayer_reset_gapless_state(mmplayer_t *player)
4306 MMPLAYER_RETURN_IF_FAIL(player
4308 && player->pipeline->audiobin
4309 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4311 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4318 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4321 int ret = MM_ERROR_NONE;
4325 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4327 /* cleanup stuffs */
4328 MMPLAYER_FREEIF(player->type);
4329 player->no_more_pad = FALSE;
4330 player->num_dynamic_pad = 0;
4332 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4333 player->subtitle_language_list = NULL;
4334 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4336 MMPLAYER_RECONFIGURE_LOCK(player);
4337 __mmplayer_reset_gapless_state(player);
4338 MMPLAYER_RECONFIGURE_UNLOCK(player);
4340 if (player->streamer) {
4341 _mm_player_streaming_initialize(player->streamer, FALSE);
4342 _mm_player_streaming_destroy(player->streamer);
4343 player->streamer = NULL;
4346 /* cleanup unlinked mime type */
4347 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4348 MMPLAYER_FREEIF(player->unlinked_video_mime);
4349 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4351 /* cleanup running stuffs */
4352 _mmplayer_cancel_eos_timer(player);
4354 /* cleanup gst stuffs */
4355 if (player->pipeline) {
4356 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4357 GstTagList *tag_list = player->pipeline->tag_list;
4359 /* first we need to disconnect all signal hander */
4360 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4363 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4364 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4365 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4366 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4367 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4368 gst_object_unref(bus);
4370 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4371 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4372 if (ret != MM_ERROR_NONE) {
4373 LOGE("fail to change state to NULL");
4374 return MM_ERROR_PLAYER_INTERNAL;
4377 LOGW("succeeded in changing state to NULL");
4379 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4382 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4383 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4385 MMPLAYER_FREEIF(audiobin);
4386 MMPLAYER_FREEIF(videobin);
4387 MMPLAYER_FREEIF(textbin);
4388 MMPLAYER_FREEIF(mainbin);
4392 gst_tag_list_unref(tag_list);
4394 MMPLAYER_FREEIF(player->pipeline);
4396 MMPLAYER_FREEIF(player->album_art);
4398 if (player->type_caps) {
4399 gst_caps_unref(player->type_caps);
4400 player->type_caps = NULL;
4403 if (player->v_stream_caps) {
4404 gst_caps_unref(player->v_stream_caps);
4405 player->v_stream_caps = NULL;
4408 if (player->a_stream_caps) {
4409 gst_caps_unref(player->a_stream_caps);
4410 player->a_stream_caps = NULL;
4413 if (player->s_stream_caps) {
4414 gst_caps_unref(player->s_stream_caps);
4415 player->s_stream_caps = NULL;
4417 _mmplayer_track_destroy(player);
4419 if (player->sink_elements)
4420 g_list_free(player->sink_elements);
4421 player->sink_elements = NULL;
4423 if (player->bufmgr) {
4424 tbm_bufmgr_deinit(player->bufmgr);
4425 player->bufmgr = NULL;
4428 LOGW("finished destroy pipeline");
4436 __mmplayer_gst_realize(mmplayer_t *player)
4439 int ret = MM_ERROR_NONE;
4443 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4445 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4447 ret = __mmplayer_gst_create_pipeline(player);
4449 LOGE("failed to create pipeline");
4453 /* set pipeline state to READY */
4454 /* NOTE : state change to READY must be performed sync. */
4455 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4456 ret = _mmplayer_gst_set_state(player,
4457 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4459 if (ret != MM_ERROR_NONE) {
4460 /* return error if failed to set state */
4461 LOGE("failed to set READY state");
4465 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4467 /* create dot before error-return. for debugging */
4468 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4476 __mmplayer_gst_unrealize(mmplayer_t *player)
4478 int ret = MM_ERROR_NONE;
4482 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4484 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4485 MMPLAYER_PRINT_STATE(player);
4487 /* release miscellaneous information */
4488 __mmplayer_release_misc(player);
4490 /* destroy pipeline */
4491 ret = __mmplayer_gst_destroy_pipeline(player);
4492 if (ret != MM_ERROR_NONE) {
4493 LOGE("failed to destroy pipeline");
4497 /* release miscellaneous information.
4498 these info needs to be released after pipeline is destroyed. */
4499 __mmplayer_release_misc_post(player);
4501 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4509 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4514 LOGW("set_message_callback is called with invalid player handle");
4515 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4518 player->msg_cb = callback;
4519 player->msg_cb_param = user_param;
4521 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4525 return MM_ERROR_NONE;
4529 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4531 int ret = MM_ERROR_NONE;
4536 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4537 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4538 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4540 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4542 if (strstr(uri, "es_buff://")) {
4543 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4544 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4545 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4546 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4548 tmp = g_ascii_strdown(uri, strlen(uri));
4549 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4550 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4552 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4554 } else if (strstr(uri, "mms://")) {
4555 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4556 } else if ((path = strstr(uri, "mem://"))) {
4557 ret = __mmplayer_set_mem_uri(data, path, param);
4559 ret = __mmplayer_set_file_uri(data, uri);
4562 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4563 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4564 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4565 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4567 /* dump parse result */
4568 SECURE_LOGW("incoming uri : %s", uri);
4569 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4570 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4578 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4581 mmplayer_t *player = NULL;
4582 MMMessageParamType msg = {0, };
4584 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4589 LOGE("user_data is null");
4593 player = (mmplayer_t *)user_data;
4595 if (!player->pipeline || !player->attrs) {
4596 LOGW("not initialized");
4600 LOGD("cmd lock player, cmd state : %d", player->cmd);
4601 MMPLAYER_CMD_LOCK(player);
4602 LOGD("cmd locked player");
4604 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4605 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4606 LOGW("player already destroyed");
4607 MMPLAYER_CMD_UNLOCK(player);
4611 player->interrupted_by_resource = TRUE;
4613 /* get last play position */
4614 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4615 msg.union_type = MM_MSG_UNION_TIME;
4616 msg.time.elapsed = pos;
4617 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4619 LOGW("failed to get play position.");
4622 LOGD("video resource conflict so, resource will be freed by unrealizing");
4623 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4624 LOGE("failed to unrealize");
4626 MMPLAYER_CMD_UNLOCK(player);
4628 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4629 player->hw_resource[res_idx] = NULL;
4633 return TRUE; /* release all the resources */
4637 __mmplayer_initialize_video_roi(mmplayer_t *player)
4639 player->video_roi.scale_x = 0.0;
4640 player->video_roi.scale_y = 0.0;
4641 player->video_roi.scale_width = 1.0;
4642 player->video_roi.scale_height = 1.0;
4646 _mmplayer_create_player(MMHandleType handle)
4648 int ret = MM_ERROR_PLAYER_INTERNAL;
4649 bool enabled = false;
4651 mmplayer_t *player = MM_PLAYER_CAST(handle);
4655 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4657 /* initialize player state */
4658 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4659 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4660 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4661 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4663 /* check current state */
4664 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4666 /* construct attributes */
4667 player->attrs = _mmplayer_construct_attribute(handle);
4669 if (!player->attrs) {
4670 LOGE("Failed to construct attributes");
4674 /* initialize gstreamer with configured parameter */
4675 if (!__mmplayer_init_gstreamer(player)) {
4676 LOGE("Initializing gstreamer failed");
4677 _mmplayer_deconstruct_attribute(handle);
4681 /* create lock. note that g_tread_init() has already called in gst_init() */
4682 g_mutex_init(&player->fsink_lock);
4684 /* create update tag lock */
4685 g_mutex_init(&player->update_tag_lock);
4687 /* create gapless play mutex */
4688 g_mutex_init(&player->gapless_play_thread_mutex);
4690 /* create gapless play cond */
4691 g_cond_init(&player->gapless_play_thread_cond);
4693 /* create gapless play thread */
4694 player->gapless_play_thread =
4695 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4696 if (!player->gapless_play_thread) {
4697 LOGE("failed to create gapless play thread");
4698 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4699 g_mutex_clear(&player->gapless_play_thread_mutex);
4700 g_cond_clear(&player->gapless_play_thread_cond);
4704 player->bus_msg_q = g_queue_new();
4705 if (!player->bus_msg_q) {
4706 LOGE("failed to create queue for bus_msg");
4707 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4711 ret = _mmplayer_initialize_video_capture(player);
4712 if (ret != MM_ERROR_NONE) {
4713 LOGE("failed to initialize video capture");
4717 /* initialize resource manager */
4718 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4719 __resource_release_cb, player, &player->resource_manager)
4720 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4721 LOGE("failed to create resource manager");
4722 ret = MM_ERROR_PLAYER_INTERNAL;
4726 /* create video bo lock and cond */
4727 g_mutex_init(&player->video_bo_mutex);
4728 g_cond_init(&player->video_bo_cond);
4730 /* create subtitle info lock and cond */
4731 g_mutex_init(&player->subtitle_info_mutex);
4732 g_cond_init(&player->subtitle_info_cond);
4734 player->streaming_type = STREAMING_SERVICE_NONE;
4736 /* give default value of audio effect setting */
4737 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4738 player->sound.rg_enable = false;
4739 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4741 player->play_subtitle = FALSE;
4742 player->has_closed_caption = FALSE;
4743 player->pending_resume = FALSE;
4744 if (player->ini.dump_element_keyword[0][0] == '\0')
4745 player->ini.set_dump_element_flag = FALSE;
4747 player->ini.set_dump_element_flag = TRUE;
4749 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4750 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4751 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4753 /* Set video360 settings to their defaults for just-created player.
4756 player->is_360_feature_enabled = FALSE;
4757 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4758 LOGI("spherical feature info: %d", enabled);
4760 player->is_360_feature_enabled = TRUE;
4762 LOGE("failed to get spherical feature info");
4765 player->is_content_spherical = FALSE;
4766 player->is_video360_enabled = TRUE;
4767 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4768 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4769 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4770 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4771 player->video360_zoom = 1.0f;
4772 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4773 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4775 __mmplayer_initialize_video_roi(player);
4777 /* set player state to null */
4778 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4779 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4783 return MM_ERROR_NONE;
4787 g_mutex_clear(&player->fsink_lock);
4788 /* free update tag lock */
4789 g_mutex_clear(&player->update_tag_lock);
4790 g_queue_free(player->bus_msg_q);
4791 player->bus_msg_q = NULL;
4792 /* free gapless play thread */
4793 if (player->gapless_play_thread) {
4794 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4795 player->gapless_play_thread_exit = TRUE;
4796 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4797 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4799 g_thread_join(player->gapless_play_thread);
4800 player->gapless_play_thread = NULL;
4802 g_mutex_clear(&player->gapless_play_thread_mutex);
4803 g_cond_clear(&player->gapless_play_thread_cond);
4806 /* release attributes */
4807 _mmplayer_deconstruct_attribute(handle);
4815 __mmplayer_init_gstreamer(mmplayer_t *player)
4817 static gboolean initialized = FALSE;
4818 static const int max_argc = 50;
4820 gchar **argv = NULL;
4821 gchar **argv2 = NULL;
4827 LOGD("gstreamer already initialized.");
4832 argc = malloc(sizeof(int));
4833 argv = malloc(sizeof(gchar *) * max_argc);
4834 argv2 = malloc(sizeof(gchar *) * max_argc);
4836 if (!argc || !argv || !argv2)
4839 memset(argv, 0, sizeof(gchar *) * max_argc);
4840 memset(argv2, 0, sizeof(gchar *) * max_argc);
4844 argv[0] = g_strdup("mmplayer");
4847 for (i = 0; i < 5; i++) {
4848 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4849 if (strlen(player->ini.gst_param[i]) > 0) {
4850 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4855 /* we would not do fork for scanning plugins */
4856 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4859 /* check disable registry scan */
4860 if (player->ini.skip_rescan) {
4861 argv[*argc] = g_strdup("--gst-disable-registry-update");
4865 /* check disable segtrap */
4866 if (player->ini.disable_segtrap) {
4867 argv[*argc] = g_strdup("--gst-disable-segtrap");
4871 LOGD("initializing gstreamer with following parameter");
4872 LOGD("argc : %d", *argc);
4875 for (i = 0; i < arg_count; i++) {
4877 LOGD("argv[%d] : %s", i, argv2[i]);
4880 /* initializing gstreamer */
4881 if (!gst_init_check(argc, &argv, &err)) {
4882 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4889 for (i = 0; i < arg_count; i++) {
4891 LOGD("release - argv[%d] : %s", i, argv2[i]);
4893 MMPLAYER_FREEIF(argv2[i]);
4896 MMPLAYER_FREEIF(argv);
4897 MMPLAYER_FREEIF(argv2);
4898 MMPLAYER_FREEIF(argc);
4908 for (i = 0; i < arg_count; i++) {
4909 LOGD("free[%d] : %s", i, argv2[i]);
4910 MMPLAYER_FREEIF(argv2[i]);
4913 MMPLAYER_FREEIF(argv);
4914 MMPLAYER_FREEIF(argv2);
4915 MMPLAYER_FREEIF(argc);
4921 __mmplayer_check_async_state_transition(mmplayer_t *player)
4923 GstState element_state = GST_STATE_VOID_PENDING;
4924 GstState element_pending_state = GST_STATE_VOID_PENDING;
4925 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4926 GstElement *element = NULL;
4927 gboolean async = FALSE;
4929 /* check player handle */
4930 MMPLAYER_RETURN_IF_FAIL(player &&
4932 player->pipeline->mainbin &&
4933 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4936 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4938 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4939 LOGD("don't need to check the pipeline state");
4943 MMPLAYER_PRINT_STATE(player);
4945 /* wait for state transition */
4946 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4947 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4949 if (ret == GST_STATE_CHANGE_FAILURE) {
4950 LOGE(" [%s] state : %s pending : %s",
4951 GST_ELEMENT_NAME(element),
4952 gst_element_state_get_name(element_state),
4953 gst_element_state_get_name(element_pending_state));
4955 /* dump state of all element */
4956 _mmplayer_dump_pipeline_state(player);
4961 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4966 _mmplayer_destroy(MMHandleType handle)
4968 mmplayer_t *player = MM_PLAYER_CAST(handle);
4972 /* check player handle */
4973 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4975 /* destroy can called at anytime */
4976 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4978 /* check async state transition */
4979 __mmplayer_check_async_state_transition(player);
4981 /* release gapless play thread */
4982 if (player->gapless_play_thread) {
4983 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4984 player->gapless_play_thread_exit = TRUE;
4985 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4986 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4988 LOGD("waiting for gapless play thread exit");
4989 g_thread_join(player->gapless_play_thread);
4990 g_mutex_clear(&player->gapless_play_thread_mutex);
4991 g_cond_clear(&player->gapless_play_thread_cond);
4992 LOGD("gapless play thread released");
4995 _mmplayer_release_video_capture(player);
4997 /* release miscellaneous information */
4998 __mmplayer_release_misc(player);
5000 /* release pipeline */
5001 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5002 LOGE("failed to destroy pipeline");
5003 return MM_ERROR_PLAYER_INTERNAL;
5006 __mmplayer_destroy_hw_resource(player);
5008 g_queue_free(player->bus_msg_q);
5010 /* release subtitle info lock and cond */
5011 g_mutex_clear(&player->subtitle_info_mutex);
5012 g_cond_clear(&player->subtitle_info_cond);
5014 __mmplayer_release_dump_list(player->dump_list);
5016 /* release miscellaneous information.
5017 these info needs to be released after pipeline is destroyed. */
5018 __mmplayer_release_misc_post(player);
5020 /* release attributes */
5021 _mmplayer_deconstruct_attribute(handle);
5023 if (player->uri_info.uri_list) {
5024 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5025 player->uri_info.uri_list = NULL;
5029 g_mutex_clear(&player->fsink_lock);
5032 g_mutex_clear(&player->update_tag_lock);
5034 /* release video bo lock and cond */
5035 g_mutex_clear(&player->video_bo_mutex);
5036 g_cond_clear(&player->video_bo_cond);
5040 return MM_ERROR_NONE;
5044 _mmplayer_realize(MMHandleType hplayer)
5046 mmplayer_t *player = (mmplayer_t *)hplayer;
5047 int ret = MM_ERROR_NONE;
5050 MMHandleType attrs = 0;
5054 /* check player handle */
5055 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5057 /* check current state */
5058 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5060 attrs = MMPLAYER_GET_ATTRS(player);
5062 LOGE("fail to get attributes.");
5063 return MM_ERROR_PLAYER_INTERNAL;
5065 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5066 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5068 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5069 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5071 if (ret != MM_ERROR_NONE) {
5072 LOGE("failed to parse profile");
5077 if (uri && (strstr(uri, "es_buff://"))) {
5078 if (strstr(uri, "es_buff://push_mode"))
5079 player->es_player_push_mode = TRUE;
5081 player->es_player_push_mode = FALSE;
5084 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5085 LOGW("mms protocol is not supported format.");
5086 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5089 if (MMPLAYER_IS_STREAMING(player))
5090 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5092 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5094 player->smooth_streaming = FALSE;
5095 player->videodec_linked = 0;
5096 player->audiodec_linked = 0;
5097 player->textsink_linked = 0;
5098 player->is_external_subtitle_present = FALSE;
5099 player->is_external_subtitle_added_now = FALSE;
5100 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5101 player->video360_metadata.is_spherical = -1;
5102 player->is_openal_plugin_used = FALSE;
5103 player->subtitle_language_list = NULL;
5104 player->is_subtitle_force_drop = FALSE;
5106 _mmplayer_track_initialize(player);
5107 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5109 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5110 gint prebuffer_ms = 0, rebuffer_ms = 0;
5112 player->streamer = _mm_player_streaming_create();
5113 _mm_player_streaming_initialize(player->streamer, TRUE);
5115 mm_attrs_multiple_get(player->attrs, NULL,
5116 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5117 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5119 if (prebuffer_ms > 0) {
5120 prebuffer_ms = MAX(prebuffer_ms, 1000);
5121 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5124 if (rebuffer_ms > 0) {
5125 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5126 rebuffer_ms = MAX(rebuffer_ms, 1000);
5127 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5130 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5131 player->streamer->buffering_req.rebuffer_time);
5134 /* realize pipeline */
5135 ret = __mmplayer_gst_realize(player);
5136 if (ret != MM_ERROR_NONE)
5137 LOGE("fail to realize the player.");
5139 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5147 _mmplayer_unrealize(MMHandleType hplayer)
5149 mmplayer_t *player = (mmplayer_t *)hplayer;
5150 int ret = MM_ERROR_NONE;
5151 int rm_ret = MM_ERROR_NONE;
5152 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5156 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5158 MMPLAYER_CMD_UNLOCK(player);
5159 _mmplayer_bus_watcher_remove(player);
5160 /* destroy the gst bus msg thread which is created during realize.
5161 this funct have to be called before getting cmd lock. */
5162 _mmplayer_bus_msg_thread_destroy(player);
5163 MMPLAYER_CMD_LOCK(player);
5165 /* check current state */
5166 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5168 /* check async state transition */
5169 __mmplayer_check_async_state_transition(player);
5171 /* unrealize pipeline */
5172 ret = __mmplayer_gst_unrealize(player);
5174 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5175 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5176 if (rm_ret != MM_ERROR_NONE)
5177 LOGE("failed to release [%d] resources", res_idx);
5180 player->interrupted_by_resource = FALSE;
5187 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5189 mmplayer_t *player = (mmplayer_t *)hplayer;
5191 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5193 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5197 _mmplayer_get_state(MMHandleType hplayer, int *state)
5199 mmplayer_t *player = (mmplayer_t *)hplayer;
5201 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5203 *state = MMPLAYER_CURRENT_STATE(player);
5205 return MM_ERROR_NONE;
5209 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5211 GstElement *vol_element = NULL;
5212 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5215 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5216 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5218 /* check pipeline handle */
5219 if (!player->pipeline || !player->pipeline->audiobin) {
5220 LOGD("'%s' will be applied when audiobin is created", prop_name);
5222 /* NOTE : stored value will be used in create_audiobin
5223 * returning MM_ERROR_NONE here makes application to able to
5224 * set audio volume or mute at anytime.
5226 return MM_ERROR_NONE;
5229 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5230 volume_elem_id = MMPLAYER_A_SINK;
5232 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5234 LOGE("failed to get vol element %d", volume_elem_id);
5235 return MM_ERROR_PLAYER_INTERNAL;
5238 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5240 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5241 LOGE("there is no '%s' property", prop_name);
5242 return MM_ERROR_PLAYER_INTERNAL;
5245 if (!strcmp(prop_name, "volume")) {
5246 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5247 } else if (!strcmp(prop_name, "mute")) {
5248 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5250 LOGE("invalid property %s", prop_name);
5251 return MM_ERROR_PLAYER_INTERNAL;
5254 return MM_ERROR_NONE;
5258 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5260 int ret = MM_ERROR_NONE;
5261 mmplayer_t *player = (mmplayer_t *)hplayer;
5264 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5266 LOGD("volume = %f", volume);
5268 /* invalid factor range or not */
5269 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5270 LOGE("Invalid volume value");
5271 return MM_ERROR_INVALID_ARGUMENT;
5274 player->sound.volume = volume;
5276 ret = __mmplayer_gst_set_volume_property(player, "volume");
5283 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5285 mmplayer_t *player = (mmplayer_t *)hplayer;
5289 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5290 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5292 *volume = player->sound.volume;
5294 LOGD("current vol = %f", *volume);
5297 return MM_ERROR_NONE;
5301 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5303 int ret = MM_ERROR_NONE;
5304 mmplayer_t *player = (mmplayer_t *)hplayer;
5307 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5309 LOGD("mute = %d", mute);
5311 player->sound.mute = mute;
5313 ret = __mmplayer_gst_set_volume_property(player, "mute");
5320 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5322 mmplayer_t *player = (mmplayer_t *)hplayer;
5326 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5327 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5329 *mute = player->sound.mute;
5331 LOGD("current mute = %d", *mute);
5335 return MM_ERROR_NONE;
5339 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5341 mmplayer_t *player = (mmplayer_t *)hplayer;
5345 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5347 player->audio_stream_changed_cb = callback;
5348 player->audio_stream_changed_cb_user_param = user_param;
5349 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5353 return MM_ERROR_NONE;
5357 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5359 mmplayer_t *player = (mmplayer_t *)hplayer;
5363 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5365 player->audio_decoded_cb = callback;
5366 player->audio_decoded_cb_user_param = user_param;
5367 player->audio_extract_opt = opt;
5368 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5372 return MM_ERROR_NONE;
5376 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_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 if (callback && !player->bufmgr)
5385 player->bufmgr = tbm_bufmgr_init(-1);
5387 player->set_mode.video_export = (callback) ? true : false;
5388 player->video_decoded_cb = callback;
5389 player->video_decoded_cb_user_param = user_param;
5391 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5395 return MM_ERROR_NONE;
5399 _mmplayer_start(MMHandleType hplayer)
5401 mmplayer_t *player = (mmplayer_t *)hplayer;
5402 gint ret = MM_ERROR_NONE;
5406 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5408 /* check current state */
5409 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5411 /* start pipeline */
5412 ret = _mmplayer_gst_start(player);
5413 if (ret != MM_ERROR_NONE)
5414 LOGE("failed to start player.");
5416 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5417 LOGD("force playing start even during buffering");
5418 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5426 /* NOTE: post "not supported codec message" to application
5427 * when one codec is not found during AUTOPLUGGING in MSL.
5428 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5429 * And, if any codec is not found, don't send message here.
5430 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5433 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5435 MMMessageParamType msg_param;
5436 memset(&msg_param, 0, sizeof(MMMessageParamType));
5437 gboolean post_msg_direct = FALSE;
5441 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5443 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5444 player->not_supported_codec, player->can_support_codec);
5446 if (player->not_found_demuxer) {
5447 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5448 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5450 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5451 MMPLAYER_FREEIF(msg_param.data);
5453 return MM_ERROR_NONE;
5456 if (player->not_supported_codec) {
5457 if (player->can_support_codec) {
5458 // There is one codec to play
5459 post_msg_direct = TRUE;
5461 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5462 post_msg_direct = TRUE;
5465 if (post_msg_direct) {
5466 MMMessageParamType msg_param;
5467 memset(&msg_param, 0, sizeof(MMMessageParamType));
5469 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5470 LOGW("not found AUDIO codec, posting error code to application.");
5472 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5473 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5474 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5475 LOGW("not found VIDEO codec, posting error code to application.");
5477 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5478 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5481 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5483 MMPLAYER_FREEIF(msg_param.data);
5485 return MM_ERROR_NONE;
5487 // no any supported codec case
5488 LOGW("not found any codec, posting error code to application.");
5490 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5491 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5492 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5494 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5495 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5498 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5500 MMPLAYER_FREEIF(msg_param.data);
5506 return MM_ERROR_NONE;
5509 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5511 GstState element_state = GST_STATE_VOID_PENDING;
5512 GstState element_pending_state = GST_STATE_VOID_PENDING;
5513 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5514 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5516 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5518 MMPLAYER_RECONFIGURE_LOCK(player);
5519 if (!player->gapless.reconfigure) {
5520 MMPLAYER_RECONFIGURE_UNLOCK(player);
5524 LOGI("reconfigure is under process");
5525 MMPLAYER_RECONFIGURE_WAIT(player);
5526 MMPLAYER_RECONFIGURE_UNLOCK(player);
5527 LOGI("reconfigure is completed.");
5529 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5530 &element_state, &element_pending_state, timeout * GST_SECOND);
5531 if (result == GST_STATE_CHANGE_FAILURE)
5532 LOGW("failed to get pipeline state in %d sec", timeout);
5537 /* NOTE : it should be able to call 'stop' anytime*/
5539 _mmplayer_stop(MMHandleType hplayer)
5541 mmplayer_t *player = (mmplayer_t *)hplayer;
5542 int ret = MM_ERROR_NONE;
5546 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5548 /* check current state */
5549 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5551 /* need to wait till the rebuilding pipeline is completed */
5552 __mmplayer_check_pipeline_reconfigure_state(player);
5553 MMPLAYER_RECONFIGURE_LOCK(player);
5554 __mmplayer_reset_gapless_state(player);
5555 MMPLAYER_RECONFIGURE_UNLOCK(player);
5557 /* NOTE : application should not wait for EOS after calling STOP */
5558 _mmplayer_cancel_eos_timer(player);
5561 player->seek_state = MMPLAYER_SEEK_NONE;
5564 ret = _mmplayer_gst_stop(player);
5566 if (ret != MM_ERROR_NONE)
5567 LOGE("failed to stop player.");
5575 _mmplayer_pause(MMHandleType hplayer)
5577 mmplayer_t *player = (mmplayer_t *)hplayer;
5578 gint64 pos_nsec = 0;
5579 gboolean async = FALSE;
5580 gint ret = MM_ERROR_NONE;
5584 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5586 /* check current state */
5587 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5589 /* check pipeline reconfigure state */
5590 __mmplayer_check_pipeline_reconfigure_state(player);
5592 switch (MMPLAYER_CURRENT_STATE(player)) {
5593 case MM_PLAYER_STATE_READY:
5595 /* check prepare async or not.
5596 * In the case of streaming playback, it's recommended to avoid blocking wait.
5598 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5599 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5601 /* Changing back sync of rtspsrc to async */
5602 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5603 LOGD("async prepare working mode for rtsp");
5609 case MM_PLAYER_STATE_PLAYING:
5611 /* NOTE : store current point to overcome some bad operation
5612 *(returning zero when getting current position in paused state) of some
5615 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5616 LOGW("getting current position failed in paused");
5618 player->last_position = pos_nsec;
5620 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5621 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5622 This causes problem is position calculation during normal pause resume scenarios also.
5623 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5624 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5625 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5626 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5632 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5633 LOGD("doing async pause in case of ms buff src");
5637 /* pause pipeline */
5638 ret = _mmplayer_gst_pause(player, async);
5639 if (ret != MM_ERROR_NONE) {
5640 LOGE("failed to pause player. ret : 0x%x", ret);
5641 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5645 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5646 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5647 LOGE("failed to update display_rotation");
5651 return MM_ERROR_NONE;
5654 /* in case of streaming, pause could take long time.*/
5656 _mmplayer_abort_pause(MMHandleType hplayer)
5658 mmplayer_t *player = (mmplayer_t *)hplayer;
5659 int ret = MM_ERROR_NONE;
5663 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5665 player->pipeline->mainbin,
5666 MM_ERROR_PLAYER_NOT_INITIALIZED);
5668 LOGD("set the pipeline state to READY");
5670 /* set state to READY */
5671 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5672 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5673 if (ret != MM_ERROR_NONE) {
5674 LOGE("fail to change state to READY");
5675 return MM_ERROR_PLAYER_INTERNAL;
5678 LOGD("succeeded in changing state to READY");
5683 _mmplayer_resume(MMHandleType hplayer)
5685 mmplayer_t *player = (mmplayer_t *)hplayer;
5686 int ret = MM_ERROR_NONE;
5687 gboolean async = FALSE;
5691 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5693 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5694 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5695 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5699 /* Changing back sync mode rtspsrc to async */
5700 LOGD("async resume for rtsp case");
5704 /* check current state */
5705 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5707 ret = _mmplayer_gst_resume(player, async);
5708 if (ret != MM_ERROR_NONE)
5709 LOGE("failed to resume player.");
5711 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5712 LOGD("force resume even during buffering");
5713 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5722 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5724 mmplayer_t *player = (mmplayer_t *)hplayer;
5725 gint64 pos_nsec = 0;
5726 int ret = MM_ERROR_NONE;
5728 signed long long start = 0, stop = 0;
5729 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5732 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5733 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5735 /* The sound of video is not supported under 0.0 and over 2.0. */
5736 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5737 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5740 _mmplayer_set_mute(hplayer, mute);
5742 if (player->playback_rate == rate)
5743 return MM_ERROR_NONE;
5745 /* If the position is reached at start potion during fast backward, EOS is posted.
5746 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5748 player->playback_rate = rate;
5750 current_state = MMPLAYER_CURRENT_STATE(player);
5752 if (current_state != MM_PLAYER_STATE_PAUSED)
5753 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5755 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5757 if ((current_state == MM_PLAYER_STATE_PAUSED)
5758 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5759 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5760 pos_nsec = player->last_position;
5765 stop = GST_CLOCK_TIME_NONE;
5767 start = GST_CLOCK_TIME_NONE;
5771 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5772 player->playback_rate,
5774 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5775 GST_SEEK_TYPE_SET, start,
5776 GST_SEEK_TYPE_SET, stop)) {
5777 LOGE("failed to set speed playback");
5778 return MM_ERROR_PLAYER_SEEK;
5781 LOGD("succeeded to set speed playback as %0.1f", rate);
5785 return MM_ERROR_NONE;;
5789 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5791 mmplayer_t *player = (mmplayer_t *)hplayer;
5792 int ret = MM_ERROR_NONE;
5796 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5798 /* check pipeline reconfigure state */
5799 __mmplayer_check_pipeline_reconfigure_state(player);
5801 ret = _mmplayer_gst_set_position(player, position, FALSE);
5809 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5811 mmplayer_t *player = (mmplayer_t *)hplayer;
5812 int ret = MM_ERROR_NONE;
5814 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5815 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5817 if (g_strrstr(player->type, "video/mpegts"))
5818 __mmplayer_update_duration_value(player);
5820 *duration = player->duration;
5825 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5827 mmplayer_t *player = (mmplayer_t *)hplayer;
5828 int ret = MM_ERROR_NONE;
5830 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5832 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5838 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5840 mmplayer_t *player = (mmplayer_t *)hplayer;
5841 int ret = MM_ERROR_NONE;
5845 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5847 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5855 __mmplayer_is_midi_type(gchar *str_caps)
5857 if ((g_strrstr(str_caps, "audio/midi")) ||
5858 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5859 (g_strrstr(str_caps, "application/x-smaf")) ||
5860 (g_strrstr(str_caps, "audio/x-imelody")) ||
5861 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5862 (g_strrstr(str_caps, "audio/xmf")) ||
5863 (g_strrstr(str_caps, "audio/mxmf"))) {
5872 __mmplayer_is_only_mp3_type(gchar *str_caps)
5874 if (g_strrstr(str_caps, "application/x-id3") ||
5875 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5881 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5883 GstStructure *caps_structure = NULL;
5884 gint samplerate = 0;
5888 MMPLAYER_RETURN_IF_FAIL(player && caps);
5890 caps_structure = gst_caps_get_structure(caps, 0);
5892 /* set stream information */
5893 gst_structure_get_int(caps_structure, "rate", &samplerate);
5894 gst_structure_get_int(caps_structure, "channels", &channels);
5896 mm_player_set_attribute((MMHandleType)player, NULL,
5897 "content_audio_samplerate", samplerate,
5898 "content_audio_channels", channels, NULL);
5900 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5904 __mmplayer_update_content_type_info(mmplayer_t *player)
5907 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5909 if (__mmplayer_is_midi_type(player->type)) {
5910 player->bypass_audio_effect = TRUE;
5914 if (!player->streamer) {
5915 LOGD("no need to check streaming type");
5919 if (g_strrstr(player->type, "application/x-hls")) {
5920 /* If it can't know exact type when it parses uri because of redirection case,
5921 * it will be fixed by typefinder or when doing autoplugging.
5923 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5924 player->streamer->is_adaptive_streaming = TRUE;
5925 } else if (g_strrstr(player->type, "application/dash+xml")) {
5926 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5927 player->streamer->is_adaptive_streaming = TRUE;
5930 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5931 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5932 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5934 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5935 if (player->streamer->is_adaptive_streaming)
5936 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5938 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5942 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5947 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5948 GstCaps *caps, gpointer data)
5950 mmplayer_t *player = (mmplayer_t *)data;
5954 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5956 /* store type string */
5957 if (player->type_caps) {
5958 gst_caps_unref(player->type_caps);
5959 player->type_caps = NULL;
5962 player->type_caps = gst_caps_copy(caps);
5963 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5965 MMPLAYER_FREEIF(player->type);
5966 player->type = gst_caps_to_string(caps);
5968 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5969 player, player->type, probability, gst_caps_get_size(caps));
5971 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5972 (g_strrstr(player->type, "audio/x-raw-int"))) {
5973 LOGE("not support media format");
5975 if (player->msg_posted == FALSE) {
5976 MMMessageParamType msg_param;
5977 memset(&msg_param, 0, sizeof(MMMessageParamType));
5979 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5980 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5982 /* don't post more if one was sent already */
5983 player->msg_posted = TRUE;
5988 __mmplayer_update_content_type_info(player);
5990 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5993 pad = gst_element_get_static_pad(tf, "src");
5995 LOGE("fail to get typefind src pad.");
5999 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
6000 gboolean async = FALSE;
6001 LOGE("failed to autoplug %s", player->type);
6003 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6005 if (async && player->msg_posted == FALSE)
6006 __mmplayer_handle_missed_plugin(player);
6008 gst_object_unref(GST_OBJECT(pad));
6015 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6017 GstElement *decodebin = NULL;
6021 /* create decodebin */
6022 decodebin = gst_element_factory_make("decodebin", NULL);
6025 LOGE("fail to create decodebin");
6029 /* raw pad handling signal */
6030 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6031 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6033 /* no-more-pad pad handling signal */
6034 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6035 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6037 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6038 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6040 /* This signal is emitted when a pad for which there is no further possible
6041 decoding is added to the decodebin.*/
6042 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6043 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6045 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6046 before looking for any elements that can handle that stream.*/
6047 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6048 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6050 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6051 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6052 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6054 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6055 before looking for any elements that can handle that stream.*/
6056 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6057 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6059 /* This signal is emitted once decodebin has finished decoding all the data.*/
6060 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6061 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6063 /* This signal is emitted when a element is added to the bin.*/
6064 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6065 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6072 __mmplayer_gst_make_queue2(mmplayer_t *player)
6074 GstElement *queue2 = NULL;
6075 gint64 dur_bytes = 0L;
6076 mmplayer_gst_element_t *mainbin = NULL;
6077 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6080 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6082 mainbin = player->pipeline->mainbin;
6084 queue2 = gst_element_factory_make("queue2", "queue2");
6086 LOGE("failed to create buffering queue element");
6090 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6091 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6093 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6095 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6096 * skip the pull mode(file or ring buffering) setting. */
6097 if (dur_bytes > 0) {
6098 if (!g_strrstr(player->type, "video/mpegts")) {
6099 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6100 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6106 _mm_player_streaming_set_queue2(player->streamer,
6110 (guint64)dur_bytes); /* no meaning at the moment */
6116 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6118 mmplayer_gst_element_t *mainbin = NULL;
6119 GstElement *decodebin = NULL;
6120 GstElement *queue2 = NULL;
6121 GstPad *sinkpad = NULL;
6122 GstPad *qsrcpad = NULL;
6125 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6127 mainbin = player->pipeline->mainbin;
6129 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6131 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6132 LOGW("need to check: muxed buffer is not null");
6135 queue2 = __mmplayer_gst_make_queue2(player);
6137 LOGE("failed to make queue2");
6141 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6142 LOGE("failed to add buffering queue");
6146 sinkpad = gst_element_get_static_pad(queue2, "sink");
6147 qsrcpad = gst_element_get_static_pad(queue2, "src");
6149 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6150 LOGE("failed to link [%s:%s]-[%s:%s]",
6151 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6155 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6156 LOGE("failed to sync queue2 state with parent");
6160 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6161 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6165 gst_object_unref(GST_OBJECT(sinkpad));
6169 /* create decodebin */
6170 decodebin = _mmplayer_gst_make_decodebin(player);
6172 LOGE("failed to make decodebin");
6176 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6177 LOGE("failed to add decodebin");
6181 /* to force caps on the decodebin element and avoid reparsing stuff by
6182 * typefind. It also avoids a deadlock in the way typefind activates pads in
6183 * the state change */
6184 g_object_set(decodebin, "sink-caps", caps, NULL);
6186 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6188 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6189 LOGE("failed to link [%s:%s]-[%s:%s]",
6190 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6194 gst_object_unref(GST_OBJECT(sinkpad));
6196 gst_object_unref(GST_OBJECT(qsrcpad));
6199 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6200 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6202 /* set decodebin property about buffer in streaming playback. *
6203 * in case of HLS/DASH, it does not need to have big buffer *
6204 * because it is kind of adaptive streaming. */
6205 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6206 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6207 gint high_percent = 0;
6209 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6210 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6212 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6214 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6216 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6217 "high-percent", high_percent,
6218 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6219 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6220 "max-size-buffers", 0, NULL); // disable or automatic
6223 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6224 LOGE("failed to sync decodebin state with parent");
6235 gst_object_unref(GST_OBJECT(sinkpad));
6238 gst_object_unref(GST_OBJECT(qsrcpad));
6241 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6242 * You need to explicitly set elements to the NULL state before
6243 * dropping the final reference, to allow them to clean up.
6245 gst_element_set_state(queue2, GST_STATE_NULL);
6247 /* And, it still has a parent "player".
6248 * You need to let the parent manage the object instead of unreffing the object directly.
6250 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6251 gst_object_unref(queue2);
6256 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6257 * You need to explicitly set elements to the NULL state before
6258 * dropping the final reference, to allow them to clean up.
6260 gst_element_set_state(decodebin, GST_STATE_NULL);
6262 /* And, it still has a parent "player".
6263 * You need to let the parent manage the object instead of unreffing the object directly.
6266 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6267 gst_object_unref(decodebin);
6275 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6279 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6280 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6282 LOGD("class : %s, mime : %s", factory_class, mime);
6284 /* add missing plugin */
6285 /* NOTE : msl should check missing plugin for image mime type.
6286 * Some motion jpeg clips can have playable audio track.
6287 * So, msl have to play audio after displaying popup written video format not supported.
6289 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6290 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6291 LOGD("not found demuxer");
6292 player->not_found_demuxer = TRUE;
6293 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6299 if (!g_strrstr(factory_class, "Demuxer")) {
6300 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6301 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6302 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6304 /* check that clip have multi tracks or not */
6305 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6306 LOGD("video plugin is already linked");
6308 LOGW("add VIDEO to missing plugin");
6309 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6310 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6312 } else if (g_str_has_prefix(mime, "audio")) {
6313 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6314 LOGD("audio plugin is already linked");
6316 LOGW("add AUDIO to missing plugin");
6317 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6318 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6326 return MM_ERROR_NONE;
6330 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6332 mmplayer_t *player = (mmplayer_t *)data;
6336 MMPLAYER_RETURN_IF_FAIL(player);
6338 /* remove fakesink. */
6339 if (!_mmplayer_gst_remove_fakesink(player,
6340 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6341 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6342 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6343 * source element are not same. To overcome this situation, this function will called
6344 * several places and several times. Therefore, this is not an error case.
6349 LOGD("[handle: %p] pipeline has completely constructed", player);
6351 if ((player->msg_posted == FALSE) &&
6352 (player->cmd >= MMPLAYER_COMMAND_START))
6353 __mmplayer_handle_missed_plugin(player);
6355 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6359 __mmplayer_check_profile(void)
6362 static int profile_tv = -1;
6364 if (__builtin_expect(profile_tv != -1, 1))
6367 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6368 switch (*profileName) {
6383 __mmplayer_get_next_uri(mmplayer_t *player)
6385 mmplayer_parse_profile_t profile;
6387 guint num_of_list = 0;
6390 num_of_list = g_list_length(player->uri_info.uri_list);
6391 uri_idx = player->uri_info.uri_idx;
6393 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6394 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6395 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6397 LOGW("next uri does not exist");
6401 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6402 LOGE("failed to parse profile");
6406 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6407 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6408 LOGW("uri type is not supported(%d)", profile.uri_type);
6412 LOGD("success to find next uri %d", uri_idx);
6416 if (!uri || uri_idx == num_of_list) {
6417 LOGE("failed to find next uri");
6421 player->uri_info.uri_idx = uri_idx;
6422 if (mm_player_set_attribute((MMHandleType)player, NULL,
6423 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6424 LOGE("failed to set attribute");
6428 SECURE_LOGD("next playback uri: %s", uri);
6433 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6435 #define REPEAT_COUNT_INFINITE -1
6436 #define REPEAT_COUNT_MIN 2
6437 #define ORIGINAL_URI_ONLY 1
6439 MMHandleType attrs = 0;
6443 guint num_of_uri = 0;
6444 int profile_tv = -1;
6448 LOGD("checking for gapless play option");
6450 if (player->build_audio_offload) {
6451 LOGE("offload path is not supportable.");
6455 if (player->pipeline->textbin) {
6456 LOGE("subtitle path is enabled. gapless play is not supported.");
6460 attrs = MMPLAYER_GET_ATTRS(player);
6462 LOGE("fail to get attributes.");
6466 mm_attrs_multiple_get(player->attrs, NULL,
6467 "content_video_found", &video,
6468 "profile_play_count", &count,
6469 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6471 /* gapless playback is not supported in case of video at TV profile. */
6472 profile_tv = __mmplayer_check_profile();
6473 if (profile_tv && video) {
6474 LOGW("not support video gapless playback");
6478 /* check repeat count in case of audio */
6480 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6481 LOGW("gapless is disabled");
6485 num_of_uri = g_list_length(player->uri_info.uri_list);
6487 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6489 if (num_of_uri == ORIGINAL_URI_ONLY) {
6490 /* audio looping path */
6491 if (count >= REPEAT_COUNT_MIN) {
6492 /* decrease play count */
6493 /* we succeeded to rewind. update play count and then wait for next EOS */
6495 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6496 } else if (count != REPEAT_COUNT_INFINITE) {
6497 LOGD("there is no next uri and no repeat");
6500 LOGD("looping cnt %d", count);
6502 /* gapless playback path */
6503 if (!__mmplayer_get_next_uri(player)) {
6504 LOGE("failed to get next uri");
6511 LOGE("unable to play gapless path. EOS will be posted soon");
6516 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6518 GstPad *sinkpad = g_value_get_object (item);
6519 GstElement *element = GST_ELEMENT(user_data);
6520 if (!sinkpad || !element) {
6521 LOGE("invalid parameter");
6525 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6526 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6530 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6532 mmplayer_gst_element_t *sinkbin = NULL;
6533 main_element_id_e concatId = MMPLAYER_M_NUM;
6534 main_element_id_e sinkId = MMPLAYER_M_NUM;
6535 gboolean send_notice = FALSE;
6536 GstElement *element;
6540 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6542 LOGD("type %d", type);
6545 case MM_PLAYER_TRACK_TYPE_AUDIO:
6546 concatId = MMPLAYER_M_A_CONCAT;
6547 sinkId = MMPLAYER_A_BIN;
6548 sinkbin = player->pipeline->audiobin;
6550 case MM_PLAYER_TRACK_TYPE_VIDEO:
6551 concatId = MMPLAYER_M_V_CONCAT;
6552 sinkId = MMPLAYER_V_BIN;
6553 sinkbin = player->pipeline->videobin;
6556 case MM_PLAYER_TRACK_TYPE_TEXT:
6557 concatId = MMPLAYER_M_T_CONCAT;
6558 sinkId = MMPLAYER_T_BIN;
6559 sinkbin = player->pipeline->textbin;
6562 LOGE("requested type is not supportable");
6567 element = player->pipeline->mainbin[concatId].gst;
6571 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6572 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6573 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6574 if (srcpad && sinkpad) {
6575 /* after getting drained signal there is no data flows, so no need to do pad_block */
6576 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6577 gst_pad_unlink(srcpad, sinkpad);
6579 /* send custom event to sink pad to handle it at video sink */
6581 LOGD("send custom event to sinkpad");
6582 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6583 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6584 gst_pad_send_event(sinkpad, event);
6587 gst_object_unref(srcpad);
6588 gst_object_unref(sinkpad);
6591 LOGD("release concat request pad");
6592 /* release and unref requests pad from the selector */
6593 iter = gst_element_iterate_sink_pads(element);
6594 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6595 gst_iterator_resync(iter);
6596 gst_iterator_free(iter);
6602 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6604 mmplayer_track_t *selector = &player->track[type];
6605 mmplayer_gst_element_t *sinkbin = NULL;
6606 main_element_id_e selectorId = MMPLAYER_M_NUM;
6607 main_element_id_e sinkId = MMPLAYER_M_NUM;
6608 GstPad *srcpad = NULL;
6609 GstPad *sinkpad = NULL;
6610 gboolean send_notice = FALSE;
6613 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6615 LOGD("type %d", type);
6618 case MM_PLAYER_TRACK_TYPE_AUDIO:
6619 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6620 sinkId = MMPLAYER_A_BIN;
6621 sinkbin = player->pipeline->audiobin;
6623 case MM_PLAYER_TRACK_TYPE_VIDEO:
6624 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6625 sinkId = MMPLAYER_V_BIN;
6626 sinkbin = player->pipeline->videobin;
6629 case MM_PLAYER_TRACK_TYPE_TEXT:
6630 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6631 sinkId = MMPLAYER_T_BIN;
6632 sinkbin = player->pipeline->textbin;
6635 LOGE("requested type is not supportable");
6640 if (player->pipeline->mainbin[selectorId].gst) {
6643 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6645 if (selector->event_probe_id != 0)
6646 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6647 selector->event_probe_id = 0;
6649 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6650 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6652 if (srcpad && sinkpad) {
6653 /* after getting drained signal there is no data flows, so no need to do pad_block */
6654 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6655 gst_pad_unlink(srcpad, sinkpad);
6657 /* send custom event to sink pad to handle it at video sink */
6659 LOGD("send custom event to sinkpad");
6660 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6661 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6662 gst_pad_send_event(sinkpad, event);
6666 gst_object_unref(sinkpad);
6669 gst_object_unref(srcpad);
6672 LOGD("selector release");
6674 /* release and unref requests pad from the selector */
6675 for (n = 0; n < selector->streams->len; n++) {
6676 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6677 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6680 g_ptr_array_set_size(selector->streams, 0);
6682 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6683 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6685 player->pipeline->mainbin[selectorId].gst = NULL;
6693 __mmplayer_deactivate_old_path(mmplayer_t *player)
6696 MMPLAYER_RETURN_IF_FAIL(player);
6698 if (MMPLAYER_USE_DECODEBIN(player)) {
6699 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6700 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6701 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6702 LOGE("deactivate selector error");
6706 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6707 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6708 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6709 LOGE("deactivate concat error");
6714 _mmplayer_track_destroy(player);
6715 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6717 if (player->streamer) {
6718 _mm_player_streaming_initialize(player->streamer, FALSE);
6719 _mm_player_streaming_destroy(player->streamer);
6720 player->streamer = NULL;
6723 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6729 if (!player->msg_posted) {
6730 MMMessageParamType msg = {0,};
6733 msg.code = MM_ERROR_PLAYER_INTERNAL;
6734 LOGE("gapless_uri_play> deactivate error");
6736 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6737 player->msg_posted = TRUE;
6743 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6745 int result = MM_ERROR_NONE;
6746 mmplayer_t *player = (mmplayer_t *)hplayer;
6749 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6750 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6752 if (mm_player_set_attribute(hplayer, NULL,
6753 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6754 LOGE("failed to set attribute");
6755 result = MM_ERROR_PLAYER_INTERNAL;
6757 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6758 LOGE("failed to add the original uri in the uri list.");
6766 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6768 mmplayer_t *player = (mmplayer_t *)hplayer;
6769 guint num_of_list = 0;
6773 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6774 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6776 if (player->pipeline && player->pipeline->textbin) {
6777 LOGE("subtitle path is enabled.");
6778 return MM_ERROR_PLAYER_INVALID_STATE;
6781 num_of_list = g_list_length(player->uri_info.uri_list);
6783 if (is_first_path) {
6784 if (num_of_list == 0) {
6785 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6786 SECURE_LOGD("add original path : %s", uri);
6788 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6789 player->uri_info.uri_list = g_list_prepend(
6790 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6791 SECURE_LOGD("change original path : %s", uri);
6794 MMHandleType attrs = 0;
6795 attrs = MMPLAYER_GET_ATTRS(player);
6797 if (num_of_list == 0) {
6798 char *original_uri = NULL;
6801 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6803 if (!original_uri) {
6804 LOGE("there is no original uri.");
6805 return MM_ERROR_PLAYER_INVALID_STATE;
6808 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6809 player->uri_info.uri_idx = 0;
6811 SECURE_LOGD("add original path at first : %s", original_uri);
6815 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6816 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6820 return MM_ERROR_NONE;
6824 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6826 mmplayer_t *player = (mmplayer_t *)hplayer;
6827 char *next_uri = NULL;
6828 guint num_of_list = 0;
6831 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6833 num_of_list = g_list_length(player->uri_info.uri_list);
6835 if (num_of_list > 0) {
6836 gint uri_idx = player->uri_info.uri_idx;
6838 if (uri_idx < num_of_list - 1)
6843 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6844 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6846 *uri = g_strdup(next_uri);
6850 return MM_ERROR_NONE;
6854 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6855 GstCaps *caps, gpointer data)
6857 mmplayer_t *player = (mmplayer_t *)data;
6858 const gchar *klass = NULL;
6859 const gchar *mime = NULL;
6860 gchar *caps_str = NULL;
6862 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6863 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6864 caps_str = gst_caps_to_string(caps);
6866 LOGW("unknown type of caps : %s from %s",
6867 caps_str, GST_ELEMENT_NAME(elem));
6869 MMPLAYER_FREEIF(caps_str);
6871 /* There is no available codec. */
6872 __mmplayer_check_not_supported_codec(player, klass, mime);
6876 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6877 GstCaps *caps, gpointer data)
6879 mmplayer_t *player = (mmplayer_t *)data;
6880 const char *mime = NULL;
6881 gboolean ret = TRUE;
6883 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6884 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6886 if (g_str_has_prefix(mime, "audio")) {
6887 GstStructure *caps_structure = NULL;
6888 gint samplerate = 0;
6890 gchar *caps_str = NULL;
6892 caps_structure = gst_caps_get_structure(caps, 0);
6893 gst_structure_get_int(caps_structure, "rate", &samplerate);
6894 gst_structure_get_int(caps_structure, "channels", &channels);
6896 if ((channels > 0 && samplerate == 0)) {
6897 LOGD("exclude audio...");
6901 caps_str = gst_caps_to_string(caps);
6902 /* set it directly because not sent by TAG */
6903 if (g_strrstr(caps_str, "mobile-xmf"))
6904 mm_player_set_attribute((MMHandleType)player, NULL,
6905 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6907 MMPLAYER_FREEIF(caps_str);
6908 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6909 LOGD("already video linked");
6912 LOGD("found new stream");
6919 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6921 gboolean ret = FALSE;
6922 GDBusConnection *conn = NULL;
6924 GVariant *result = NULL;
6925 const gchar *dbus_device_type = NULL;
6926 const gchar *dbus_ret = NULL;
6929 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6931 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6936 result = g_dbus_connection_call_sync(conn,
6937 "org.pulseaudio.Server",
6938 "/org/pulseaudio/StreamManager",
6939 "org.pulseaudio.StreamManager",
6940 "GetCurrentMediaRoutingPath",
6941 g_variant_new("(s)", "out"),
6942 G_VARIANT_TYPE("(ss)"),
6943 G_DBUS_CALL_FLAGS_NONE,
6947 if (!result || err) {
6948 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6953 /* device type is listed in stream-map.json at mmfw-sysconf */
6954 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6956 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6957 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6960 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6961 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6962 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6963 LOGD("audio offload is supportable");
6969 LOGD("audio offload is not supportable");
6972 g_variant_unref(result);
6974 g_object_unref(conn);
6979 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6981 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6982 gint64 position = 0;
6984 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6985 player->pipeline && player->pipeline->mainbin);
6987 MMPLAYER_CMD_LOCK(player);
6988 current_state = MMPLAYER_CURRENT_STATE(player);
6990 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6991 LOGW("getting current position failed in paused");
6993 _mmplayer_unrealize((MMHandleType)player);
6994 _mmplayer_realize((MMHandleType)player);
6996 _mmplayer_set_position((MMHandleType)player, position);
6998 /* async not to be blocked in streaming case */
6999 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7001 _mmplayer_pause((MMHandleType)player);
7003 if (current_state == MM_PLAYER_STATE_PLAYING)
7004 _mmplayer_start((MMHandleType)player);
7005 MMPLAYER_CMD_UNLOCK(player);
7007 LOGD("rebuilding audio pipeline is completed.");
7010 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7012 mmplayer_t *player = (mmplayer_t *)user_data;
7013 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7014 gboolean is_supportable = FALSE;
7016 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7017 LOGW("failed to get device type");
7019 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7021 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7022 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7023 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7024 LOGD("ignore this dev connected info");
7028 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7029 if (player->build_audio_offload == is_supportable) {
7030 LOGD("keep current pipeline without re-building");
7034 /* rebuild pipeline */
7035 LOGD("re-build pipeline - offload: %d", is_supportable);
7036 player->build_audio_offload = FALSE;
7037 __mmplayer_rebuild_audio_pipeline(player);
7043 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7045 unsigned int id = 0;
7047 if (player->audio_device_cb_id != 0) {
7048 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7052 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7053 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7054 LOGD("added device connected cb (%u)", id);
7055 player->audio_device_cb_id = id;
7057 LOGW("failed to add device connected cb");
7064 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7066 mmplayer_t *player = (mmplayer_t *)hplayer;
7069 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7070 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7072 *activated = player->build_audio_offload;
7074 LOGD("offload activated : %d", (int)*activated);
7077 return MM_ERROR_NONE;
7081 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7084 this function need to be updated according to the supported media format
7085 @see player->ini.audio_offload_media_format */
7087 if (__mmplayer_is_only_mp3_type(player->type)) {
7088 LOGD("offload supportable media format type");
7096 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7098 gboolean ret = FALSE;
7099 GstElementFactory *factory = NULL;
7102 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7104 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7105 if (!__mmplayer_is_offload_supported_type(player))
7108 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7109 LOGD("there is no audio offload sink");
7113 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7114 LOGW("there is no audio device type to support offload");
7118 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7120 LOGW("there is no installed audio offload sink element");
7123 gst_object_unref(factory);
7125 if (_mmplayer_acquire_hw_resource(player,
7126 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7127 LOGE("failed to acquire audio offload decoder resource");
7131 if (!__mmplayer_add_audio_device_connected_cb(player))
7134 if (!__mmplayer_is_audio_offload_device_type(player))
7137 LOGD("audio offload can be built");
7142 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7148 static GstAutoplugSelectResult
7149 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7151 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7152 int audio_offload = 0;
7154 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7155 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7157 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7158 LOGD("expose audio path to build offload output path");
7159 player->build_audio_offload = TRUE;
7160 /* update codec info */
7161 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7162 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7163 player->audiodec_linked = 1;
7165 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7169 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7170 And need to consider the multi-track audio content.
7171 There is no HW audio decoder in public. */
7173 /* set stream information */
7174 if (!player->audiodec_linked)
7175 _mmplayer_set_audio_attrs(player, caps);
7177 /* update codec info */
7178 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7179 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7180 player->audiodec_linked = 1;
7182 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7184 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7185 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7187 /* mark video decoder for acquire */
7188 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7189 LOGW("video decoder resource is already acquired, skip it.");
7190 ret = GST_AUTOPLUG_SELECT_SKIP;
7194 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7195 LOGE("failed to acquire video decoder resource");
7196 ret = GST_AUTOPLUG_SELECT_SKIP;
7199 player->interrupted_by_resource = FALSE;
7202 /* update codec info */
7203 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7204 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7205 player->videodec_linked = 1;
7213 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7214 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7216 #define DEFAULT_IDX 0xFFFF
7217 #define MIN_FACTORY_NUM 2
7218 mmplayer_t *player = (mmplayer_t *)data;
7219 GValueArray *new_factories = NULL;
7220 GValue val = { 0, };
7221 GstElementFactory *factory = NULL;
7222 const gchar *klass = NULL;
7223 gchar *factory_name = NULL;
7224 guint hw_dec_idx = DEFAULT_IDX;
7225 guint first_sw_dec_idx = DEFAULT_IDX;
7226 guint last_sw_dec_idx = DEFAULT_IDX;
7227 guint new_pos = DEFAULT_IDX;
7228 guint rm_pos = DEFAULT_IDX;
7229 int audio_codec_type;
7230 int video_codec_type;
7231 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7233 if (factories->n_values < MIN_FACTORY_NUM)
7236 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7237 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7240 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7242 for (int i = 0 ; i < factories->n_values ; i++) {
7243 gchar *hw_dec_info = NULL;
7244 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7246 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7248 LOGW("failed to get factory object");
7251 klass = gst_element_factory_get_klass(factory);
7252 factory_name = GST_OBJECT_NAME(factory);
7255 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7257 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7258 if (!player->need_audio_dec_sorting) {
7259 LOGD("sorting is not required");
7262 codec_type = audio_codec_type;
7263 hw_dec_info = player->ini.audiocodec_element_hw;
7264 sw_dec_info = player->ini.audiocodec_element_sw;
7265 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7266 if (!player->need_video_dec_sorting) {
7267 LOGD("sorting is not required");
7270 codec_type = video_codec_type;
7271 hw_dec_info = player->ini.videocodec_element_hw;
7272 sw_dec_info = player->ini.videocodec_element_sw;
7277 if (g_strrstr(factory_name, hw_dec_info)) {
7280 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7281 if (strstr(factory_name, sw_dec_info[j])) {
7282 last_sw_dec_idx = i;
7283 if (first_sw_dec_idx == DEFAULT_IDX) {
7284 first_sw_dec_idx = i;
7289 if (first_sw_dec_idx == DEFAULT_IDX)
7290 LOGW("unknown codec %s", factory_name);
7294 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7297 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7298 if (hw_dec_idx < first_sw_dec_idx)
7300 new_pos = first_sw_dec_idx;
7301 rm_pos = hw_dec_idx + 1;
7302 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7303 if (last_sw_dec_idx < hw_dec_idx)
7305 new_pos = last_sw_dec_idx + 1;
7306 rm_pos = hw_dec_idx;
7311 /* change position - insert H/W decoder according to the new position */
7312 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7314 LOGW("failed to get factory object");
7317 new_factories = g_value_array_copy(factories);
7318 g_value_init (&val, G_TYPE_OBJECT);
7319 g_value_set_object (&val, factory);
7320 g_value_array_insert(new_factories, new_pos, &val);
7321 g_value_unset (&val);
7322 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7324 for (int i = 0 ; i < new_factories->n_values ; i++) {
7325 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7327 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7328 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7330 LOGE("[Re-arranged] failed to get factory object");
7333 return new_factories;
7337 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7338 GstCaps *caps, GstElementFactory *factory, gpointer data)
7340 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7341 mmplayer_t *player = (mmplayer_t *)data;
7343 gchar *factory_name = NULL;
7344 gchar *caps_str = NULL;
7345 const gchar *klass = NULL;
7348 factory_name = GST_OBJECT_NAME(factory);
7349 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7350 caps_str = gst_caps_to_string(caps);
7352 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7354 /* store type string */
7355 if (player->type == NULL) {
7356 player->type = gst_caps_to_string(caps);
7357 __mmplayer_update_content_type_info(player);
7360 /* filtering exclude keyword */
7361 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7362 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7363 LOGW("skipping [%s] by exclude keyword [%s]",
7364 factory_name, player->ini.exclude_element_keyword[idx]);
7366 result = GST_AUTOPLUG_SELECT_SKIP;
7371 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7372 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7373 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7374 factory_name, player->ini.unsupported_codec_keyword[idx]);
7375 result = GST_AUTOPLUG_SELECT_SKIP;
7380 /* exclude webm format */
7381 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7382 * because webm format is not supportable.
7383 * If webm is disabled in "autoplug-continue", there is no state change
7384 * failure or error because the decodebin will expose the pad directly.
7385 * It make MSL invoke _prepare_async_callback.
7386 * So, we need to disable webm format in "autoplug-select" */
7387 if (caps_str && strstr(caps_str, "webm")) {
7388 LOGW("webm is not supported");
7389 result = GST_AUTOPLUG_SELECT_SKIP;
7393 /* check factory class for filtering */
7394 /* NOTE : msl don't need to use image plugins.
7395 * So, those plugins should be skipped for error handling.
7397 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7398 LOGD("skipping [%s] by not required", factory_name);
7399 result = GST_AUTOPLUG_SELECT_SKIP;
7403 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7404 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7405 // TO CHECK : subtitle if needed, add subparse exception.
7406 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7407 result = GST_AUTOPLUG_SELECT_SKIP;
7411 if (g_strrstr(factory_name, "mpegpsdemux")) {
7412 LOGD("skipping PS container - not support");
7413 result = GST_AUTOPLUG_SELECT_SKIP;
7417 if (g_strrstr(factory_name, "mssdemux"))
7418 player->smooth_streaming = TRUE;
7420 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7421 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7424 GstStructure *str = NULL;
7425 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7427 /* don't make video because of not required */
7428 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7429 (!player->set_mode.video_export)) {
7430 LOGD("no need video decoding, expose pad");
7431 result = GST_AUTOPLUG_SELECT_EXPOSE;
7435 /* get w/h for omx state-tune */
7436 /* FIXME: deprecated? */
7437 str = gst_caps_get_structure(caps, 0);
7438 gst_structure_get_int(str, "width", &width);
7441 if (player->v_stream_caps) {
7442 gst_caps_unref(player->v_stream_caps);
7443 player->v_stream_caps = NULL;
7446 player->v_stream_caps = gst_caps_copy(caps);
7447 LOGD("take caps for video state tune");
7448 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7452 if (g_strrstr(klass, "Codec/Decoder")) {
7453 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7454 if (result != GST_AUTOPLUG_SELECT_TRY) {
7455 LOGW("skip add decoder");
7461 MMPLAYER_FREEIF(caps_str);
7467 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7470 //mmplayer_t *player = (mmplayer_t *)data;
7471 GstCaps *caps = NULL;
7473 LOGD("[Decodebin2] pad-removed signal");
7475 caps = gst_pad_query_caps(new_pad, NULL);
7477 LOGW("query caps is NULL");
7481 gchar *caps_str = NULL;
7482 caps_str = gst_caps_to_string(caps);
7484 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7486 MMPLAYER_FREEIF(caps_str);
7487 gst_caps_unref(caps);
7491 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7493 mmplayer_t *player = (mmplayer_t *)data;
7496 MMPLAYER_RETURN_IF_FAIL(player);
7498 LOGD("got about to finish signal");
7500 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7501 LOGW("Fail to get cmd lock");
7505 if (!__mmplayer_verify_gapless_play_path(player)) {
7506 LOGD("decoding is finished.");
7507 MMPLAYER_CMD_UNLOCK(player);
7511 _mmplayer_set_reconfigure_state(player, TRUE);
7512 MMPLAYER_CMD_UNLOCK(player);
7514 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL);
7515 __mmplayer_deactivate_old_path(player);
7521 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7523 mmplayer_t *player = (mmplayer_t *)data;
7524 GstIterator *iter = NULL;
7525 GValue item = { 0, };
7527 gboolean done = FALSE;
7528 gboolean is_all_drained = TRUE;
7531 MMPLAYER_RETURN_IF_FAIL(player);
7533 LOGD("got drained signal");
7535 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7536 LOGW("Fail to get cmd lock");
7540 if (!__mmplayer_verify_gapless_play_path(player)) {
7541 LOGD("decoding is finished.");
7542 MMPLAYER_CMD_UNLOCK(player);
7546 _mmplayer_set_reconfigure_state(player, TRUE);
7547 MMPLAYER_CMD_UNLOCK(player);
7549 /* check decodebin src pads whether they received EOS or not */
7550 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7553 switch (gst_iterator_next(iter, &item)) {
7554 case GST_ITERATOR_OK:
7555 pad = g_value_get_object(&item);
7556 if (pad && !GST_PAD_IS_EOS(pad)) {
7557 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7558 is_all_drained = FALSE;
7561 g_value_reset(&item);
7563 case GST_ITERATOR_RESYNC:
7564 gst_iterator_resync(iter);
7566 case GST_ITERATOR_ERROR:
7567 case GST_ITERATOR_DONE:
7572 g_value_unset(&item);
7573 gst_iterator_free(iter);
7575 if (!is_all_drained) {
7576 LOGD("Wait util the all pads get EOS.");
7581 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7582 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7584 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7585 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7586 __mmplayer_deactivate_old_path(player);
7592 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7594 mmplayer_t *player = (mmplayer_t *)data;
7595 const gchar *klass = NULL;
7596 gchar *factory_name = NULL;
7598 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7599 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7601 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7603 if (__mmplayer_add_dump_buffer_probe(player, element))
7604 LOGD("add buffer probe");
7606 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7607 gchar *selected = NULL;
7608 selected = g_strdup(GST_ELEMENT_NAME(element));
7609 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7611 /* update codec info */
7612 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7613 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7614 player->audiodec_linked = 1;
7615 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7616 /* update codec info */
7617 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7618 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7619 player->videodec_linked = 1;
7622 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7623 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7624 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7626 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7627 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7629 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7630 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7631 "max-video-width", player->adaptive_info.limit.width,
7632 "max-video-height", player->adaptive_info.limit.height, NULL);
7634 } else if (g_strrstr(klass, "Demuxer")) {
7636 LOGD("plugged element is demuxer. take it");
7638 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7639 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7642 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7643 int surface_type = 0;
7645 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7648 // to support trust-zone only
7649 if (g_strrstr(factory_name, "asfdemux")) {
7650 LOGD("set file-location %s", player->profile.uri);
7651 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7652 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7653 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7654 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7655 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7656 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7657 (__mmplayer_is_only_mp3_type(player->type))) {
7658 LOGD("[mpegaudioparse] set streaming pull mode.");
7659 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7661 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7662 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7665 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7666 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7667 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7669 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7670 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7672 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7673 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7674 (MMPLAYER_IS_DASH_STREAMING(player))) {
7675 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7676 _mm_player_streaming_set_multiqueue(player->streamer, element);
7677 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7686 __mmplayer_release_misc(mmplayer_t *player)
7689 bool cur_mode = player->set_mode.rich_audio;
7692 MMPLAYER_RETURN_IF_FAIL(player);
7694 player->sent_bos = FALSE;
7695 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7697 player->seek_state = MMPLAYER_SEEK_NONE;
7699 player->total_bitrate = 0;
7700 player->total_maximum_bitrate = 0;
7702 player->not_found_demuxer = 0;
7704 player->last_position = 0;
7705 player->duration = 0;
7706 player->http_content_size = 0;
7707 player->not_supported_codec = MISSING_PLUGIN_NONE;
7708 player->can_support_codec = FOUND_PLUGIN_NONE;
7709 player->pending_seek.is_pending = false;
7710 player->pending_seek.pos = 0;
7711 player->msg_posted = FALSE;
7712 player->has_many_types = FALSE;
7713 player->is_subtitle_force_drop = FALSE;
7714 player->play_subtitle = FALSE;
7715 player->adjust_subtitle_pos = 0;
7716 player->has_closed_caption = FALSE;
7717 player->set_mode.video_export = false;
7718 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7719 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7721 player->set_mode.rich_audio = cur_mode;
7723 if (player->audio_device_cb_id > 0 &&
7724 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7725 LOGW("failed to remove audio device_connected_callback");
7726 player->audio_device_cb_id = 0;
7728 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7729 player->bitrate[i] = 0;
7730 player->maximum_bitrate[i] = 0;
7733 /* free memory related to audio effect */
7734 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7736 if (player->adaptive_info.var_list) {
7737 g_list_free_full(player->adaptive_info.var_list, g_free);
7738 player->adaptive_info.var_list = NULL;
7741 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7742 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7743 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7745 /* Reset video360 settings to their defaults in case if the pipeline is to be
7748 player->video360_metadata.is_spherical = -1;
7749 player->is_openal_plugin_used = FALSE;
7751 player->is_content_spherical = FALSE;
7752 player->is_video360_enabled = TRUE;
7753 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7754 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7755 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7756 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7757 player->video360_zoom = 1.0f;
7758 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7759 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7761 player->sound.rg_enable = false;
7763 __mmplayer_initialize_video_roi(player);
7768 __mmplayer_release_misc_post(mmplayer_t *player)
7770 gchar *original_uri = NULL;
7773 /* player->pipeline is already released before. */
7774 MMPLAYER_RETURN_IF_FAIL(player);
7776 player->video_decoded_cb = NULL;
7777 player->video_decoded_cb_user_param = NULL;
7778 player->video_stream_prerolled = false;
7780 player->audio_decoded_cb = NULL;
7781 player->audio_decoded_cb_user_param = NULL;
7782 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7784 player->audio_stream_changed_cb = NULL;
7785 player->audio_stream_changed_cb_user_param = NULL;
7787 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7789 /* clean found audio decoders */
7790 if (player->audio_decoders) {
7791 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7792 player->audio_decoders = NULL;
7795 /* clean the uri list except original uri */
7796 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7798 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7799 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7800 g_list_free_full(tmp, (GDestroyNotify)g_free);
7803 LOGW("failed to get original uri info");
7805 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7806 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7807 MMPLAYER_FREEIF(original_uri);
7810 /* clear the audio stream buffer list */
7811 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7813 /* clear the video stream bo list */
7814 __mmplayer_video_stream_destroy_bo_list(player);
7815 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7817 if (player->profile.input_mem.buf) {
7818 free(player->profile.input_mem.buf);
7819 player->profile.input_mem.buf = NULL;
7821 player->profile.input_mem.len = 0;
7822 player->profile.input_mem.offset = 0;
7824 player->uri_info.uri_idx = 0;
7829 __mmplayer_check_subtitle(mmplayer_t *player)
7831 MMHandleType attrs = 0;
7832 char *subtitle_uri = NULL;
7836 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7838 /* get subtitle attribute */
7839 attrs = MMPLAYER_GET_ATTRS(player);
7843 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7844 if (!subtitle_uri || !strlen(subtitle_uri))
7847 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7848 player->is_external_subtitle_present = TRUE;
7856 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7858 MMPLAYER_RETURN_IF_FAIL(player);
7860 if (player->eos_timer) {
7861 LOGD("cancel eos timer");
7862 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7863 player->eos_timer = 0;
7870 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7874 MMPLAYER_RETURN_IF_FAIL(player);
7875 MMPLAYER_RETURN_IF_FAIL(sink);
7878 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7880 player->sink_elements = g_list_append(player->sink_elements, sink);
7886 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7890 MMPLAYER_RETURN_IF_FAIL(player);
7891 MMPLAYER_RETURN_IF_FAIL(sink);
7893 player->sink_elements = g_list_remove(player->sink_elements, sink);
7899 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7900 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7902 mmplayer_signal_item_t *item = NULL;
7905 MMPLAYER_RETURN_IF_FAIL(player);
7907 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7908 LOGE("invalid signal type [%d]", type);
7912 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7914 LOGE("cannot connect signal [%s]", signal);
7919 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7920 player->signals[type] = g_list_append(player->signals[type], item);
7926 /* NOTE : be careful with calling this api. please refer to below glib comment
7927 * glib comment : Note that there is a bug in GObject that makes this function much
7928 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7929 * will no longer be called, but, the signal handler is not currently disconnected.
7930 * If the instance is itself being freed at the same time than this doesn't matter,
7931 * since the signal will automatically be removed, but if instance persists,
7932 * then the signal handler will leak. You should not remove the signal yourself
7933 * because in a future versions of GObject, the handler will automatically be
7936 * It's possible to work around this problem in a way that will continue to work
7937 * with future versions of GObject by checking that the signal handler is still
7938 * connected before disconnected it:
7940 * if (g_signal_handler_is_connected(instance, id))
7941 * g_signal_handler_disconnect(instance, id);
7944 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7946 GList *sig_list = NULL;
7947 mmplayer_signal_item_t *item = NULL;
7951 MMPLAYER_RETURN_IF_FAIL(player);
7953 LOGD("release signals type : %d", type);
7955 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7956 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7957 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7958 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7959 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7960 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7964 sig_list = player->signals[type];
7966 for (; sig_list; sig_list = sig_list->next) {
7967 item = sig_list->data;
7969 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7970 if (g_signal_handler_is_connected(item->obj, item->sig))
7971 g_signal_handler_disconnect(item->obj, item->sig);
7974 MMPLAYER_FREEIF(item);
7977 g_list_free(player->signals[type]);
7978 player->signals[type] = NULL;
7986 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7988 mmplayer_t *player = 0;
7989 int prev_display_surface_type = 0;
7993 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7995 player = MM_PLAYER_CAST(handle);
7997 /* check video sinkbin is created */
7998 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7999 LOGW("Videosink is already created");
8000 return MM_ERROR_NONE;
8003 LOGD("videosink element is not yet ready");
8005 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8006 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8008 return MM_ERROR_INVALID_ARGUMENT;
8011 /* load previous attributes */
8012 if (player->attrs) {
8013 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8014 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8015 if (prev_display_surface_type == surface_type) {
8016 LOGD("incoming display surface type is same as previous one, do nothing..");
8018 return MM_ERROR_NONE;
8021 LOGE("failed to load attributes");
8023 return MM_ERROR_PLAYER_INTERNAL;
8026 /* videobin is not created yet, so we just set attributes related to display surface */
8027 LOGD("store display attribute for given surface type(%d)", surface_type);
8028 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8029 "display_overlay", wl_surface_id, NULL);
8032 return MM_ERROR_NONE;
8035 /* Note : if silent is true, then subtitle would not be displayed. :*/
8037 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8039 mmplayer_t *player = (mmplayer_t *)hplayer;
8043 /* check player handle */
8044 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8046 player->set_mode.subtitle_off = silent;
8048 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8052 return MM_ERROR_NONE;
8056 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8058 mmplayer_gst_element_t *mainbin = NULL;
8059 mmplayer_gst_element_t *textbin = NULL;
8060 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8061 GstState current_state = GST_STATE_VOID_PENDING;
8062 GstState element_state = GST_STATE_VOID_PENDING;
8063 GstState element_pending_state = GST_STATE_VOID_PENDING;
8065 GstEvent *event = NULL;
8066 int result = MM_ERROR_NONE;
8068 GstClock *curr_clock = NULL;
8069 GstClockTime base_time, start_time, curr_time;
8074 /* check player handle */
8075 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8077 player->pipeline->mainbin &&
8078 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8080 mainbin = player->pipeline->mainbin;
8081 textbin = player->pipeline->textbin;
8083 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8085 // sync clock with current pipeline
8086 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8087 curr_time = gst_clock_get_time(curr_clock);
8089 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8090 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8092 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8093 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8095 if (current_state > GST_STATE_READY) {
8096 // sync state with current pipeline
8097 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8098 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8099 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8101 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8102 if (GST_STATE_CHANGE_FAILURE == ret) {
8103 LOGE("fail to state change.");
8104 result = MM_ERROR_PLAYER_INTERNAL;
8108 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8109 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8112 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8113 gst_object_unref(curr_clock);
8116 // seek to current position
8117 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8118 result = MM_ERROR_PLAYER_INVALID_STATE;
8119 LOGE("gst_element_query_position failed, invalid state");
8123 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8124 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);
8126 _mmplayer_gst_send_event_to_sink(player, event);
8128 result = MM_ERROR_PLAYER_INTERNAL;
8129 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8133 /* sync state with current pipeline */
8134 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8135 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8136 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8138 return MM_ERROR_NONE;
8141 /* release text pipeline resource */
8142 player->textsink_linked = 0;
8144 /* release signal */
8145 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8147 /* release textbin with it's children */
8148 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8149 MMPLAYER_FREEIF(player->pipeline->textbin);
8150 player->pipeline->textbin = NULL;
8152 /* release subtitle elem */
8153 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8154 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8160 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8162 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8163 GstState current_state = GST_STATE_VOID_PENDING;
8165 MMHandleType attrs = 0;
8166 mmplayer_gst_element_t *mainbin = NULL;
8167 mmplayer_gst_element_t *textbin = NULL;
8169 gchar *subtitle_uri = NULL;
8170 int result = MM_ERROR_NONE;
8171 const gchar *charset = NULL;
8175 /* check player handle */
8176 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8178 player->pipeline->mainbin &&
8179 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8180 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8182 mainbin = player->pipeline->mainbin;
8183 textbin = player->pipeline->textbin;
8185 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8186 if (current_state < GST_STATE_READY) {
8187 result = MM_ERROR_PLAYER_INVALID_STATE;
8188 LOGE("Pipeline is not in proper state");
8192 attrs = MMPLAYER_GET_ATTRS(player);
8194 LOGE("cannot get content attribute");
8195 result = MM_ERROR_PLAYER_INTERNAL;
8199 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8200 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8201 LOGE("subtitle uri is not proper filepath");
8202 result = MM_ERROR_PLAYER_INVALID_URI;
8206 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8207 LOGE("failed to get storage info of subtitle path");
8208 result = MM_ERROR_PLAYER_INVALID_URI;
8212 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8213 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8215 if (!strcmp(filepath, subtitle_uri)) {
8216 LOGD("subtitle path is not changed");
8219 if (mm_player_set_attribute((MMHandleType)player, NULL,
8220 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8221 LOGE("failed to set attribute");
8226 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8227 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8228 player->subtitle_language_list = NULL;
8229 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8231 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8232 if (ret != GST_STATE_CHANGE_SUCCESS) {
8233 LOGE("failed to change state of textbin to READY");
8234 result = MM_ERROR_PLAYER_INTERNAL;
8238 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8239 if (ret != GST_STATE_CHANGE_SUCCESS) {
8240 LOGE("failed to change state of subparse to READY");
8241 result = MM_ERROR_PLAYER_INTERNAL;
8245 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8246 if (ret != GST_STATE_CHANGE_SUCCESS) {
8247 LOGE("failed to change state of filesrc to READY");
8248 result = MM_ERROR_PLAYER_INTERNAL;
8252 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8254 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8256 charset = _mmplayer_get_charset(filepath);
8258 LOGD("detected charset is %s", charset);
8259 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8262 result = _mmplayer_sync_subtitle_pipeline(player);
8269 /* API to switch between external subtitles */
8271 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8273 int result = MM_ERROR_NONE;
8274 mmplayer_t *player = (mmplayer_t *)hplayer;
8279 /* check player handle */
8280 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8282 /* filepath can be null in idle state */
8284 /* check file path */
8285 if ((path = strstr(filepath, "file://")))
8286 result = _mmplayer_exist_file_path(path + 7);
8288 result = _mmplayer_exist_file_path(filepath);
8290 if (result != MM_ERROR_NONE) {
8291 LOGE("invalid subtitle path 0x%X", result);
8292 return result; /* file not found or permission denied */
8296 if (!player->pipeline) {
8298 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8299 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8300 LOGE("failed to set attribute");
8301 return MM_ERROR_PLAYER_INTERNAL;
8304 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8305 /* check filepath */
8306 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8308 if (!__mmplayer_check_subtitle(player)) {
8309 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8310 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8311 LOGE("failed to set attribute");
8312 return MM_ERROR_PLAYER_INTERNAL;
8315 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8316 LOGE("fail to create text pipeline");
8317 return MM_ERROR_PLAYER_INTERNAL;
8320 result = _mmplayer_sync_subtitle_pipeline(player);
8322 result = __mmplayer_change_external_subtitle_language(player, filepath);
8325 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8326 player->is_external_subtitle_added_now = TRUE;
8328 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8329 if (!player->subtitle_language_list) {
8330 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8331 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8332 LOGW("subtitle language list is not updated yet");
8334 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8342 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8344 guint active_idx = 0;
8345 GstStream *stream = NULL;
8346 GList *streams = NULL;
8347 GstEvent *ev = NULL;
8348 GstCaps *caps = NULL;
8350 LOGD("Switching Streams... type: %d, index: %d", type, index);
8352 player->track[type].active_track_index = index;
8354 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8355 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8356 if (player->track[i].total_track_num > 0) {
8357 active_idx = player->track[i].active_track_index;
8358 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8359 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8360 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8362 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8363 caps = gst_stream_get_caps(stream);
8365 _mmplayer_set_audio_attrs(player, caps);
8366 gst_caps_unref(caps);
8372 ev = gst_event_new_select_streams(streams);
8373 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8374 g_list_free(streams);
8376 return MM_ERROR_NONE;
8380 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8382 int result = MM_ERROR_NONE;
8383 gchar *change_pad_name = NULL;
8384 GstPad *sinkpad = NULL;
8385 mmplayer_gst_element_t *mainbin = NULL;
8386 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8387 GstCaps *caps = NULL;
8388 gint total_track_num = 0;
8392 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8393 MM_ERROR_PLAYER_NOT_INITIALIZED);
8395 LOGD("Change Track(%d) to %d", type, index);
8397 mainbin = player->pipeline->mainbin;
8399 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8400 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8401 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8402 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8404 /* Changing Video Track is not supported. */
8405 LOGE("Track Type Error");
8409 if (mainbin[elem_idx].gst == NULL) {
8410 result = MM_ERROR_PLAYER_NO_OP;
8411 LOGD("Req track doesn't exist");
8415 total_track_num = player->track[type].total_track_num;
8416 if (total_track_num <= 0) {
8417 result = MM_ERROR_PLAYER_NO_OP;
8418 LOGD("Language list is not available");
8422 if ((index < 0) || (index >= total_track_num)) {
8423 result = MM_ERROR_INVALID_ARGUMENT;
8424 LOGD("Not a proper index : %d", index);
8428 /*To get the new pad from the selector*/
8429 change_pad_name = g_strdup_printf("sink_%u", index);
8430 if (change_pad_name == NULL) {
8431 result = MM_ERROR_PLAYER_INTERNAL;
8432 LOGD("Pad does not exists");
8436 LOGD("new active pad name: %s", change_pad_name);
8438 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8439 if (sinkpad == NULL) {
8440 LOGD("sinkpad is NULL");
8441 result = MM_ERROR_PLAYER_INTERNAL;
8445 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8446 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8448 caps = gst_pad_get_current_caps(sinkpad);
8449 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8452 gst_object_unref(sinkpad);
8454 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8455 _mmplayer_set_audio_attrs(player, caps);
8458 gst_caps_unref(caps);
8461 MMPLAYER_FREEIF(change_pad_name);
8466 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8468 int result = MM_ERROR_NONE;
8469 mmplayer_t *player = NULL;
8470 mmplayer_gst_element_t *mainbin = NULL;
8472 gint current_active_index = 0;
8474 GstState current_state = GST_STATE_VOID_PENDING;
8479 player = (mmplayer_t *)hplayer;
8480 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8482 if (!player->pipeline) {
8483 LOGE("Track %d pre setting -> %d", type, index);
8485 player->track[type].active_track_index = index;
8489 mainbin = player->pipeline->mainbin;
8491 current_active_index = player->track[type].active_track_index;
8493 /*If index is same as running index no need to change the pad*/
8494 if (current_active_index == index)
8497 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8498 result = MM_ERROR_PLAYER_INVALID_STATE;
8502 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8503 if (current_state < GST_STATE_PAUSED) {
8504 result = MM_ERROR_PLAYER_INVALID_STATE;
8505 LOGW("Pipeline not in proper state");
8509 if (MMPLAYER_USE_DECODEBIN(player))
8510 result = __mmplayer_change_selector_pad(player, type, index);
8512 result = __mmplayer_switch_stream(player, type, index);
8514 if (result != MM_ERROR_NONE) {
8515 LOGE("failed to change track");
8519 player->track[type].active_track_index = index;
8521 if (MMPLAYER_USE_DECODEBIN(player)) {
8522 GstEvent *event = NULL;
8523 if (current_state == GST_STATE_PLAYING) {
8524 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8525 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8526 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8528 _mmplayer_gst_send_event_to_sink(player, event);
8530 result = MM_ERROR_PLAYER_INTERNAL;
8541 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8543 mmplayer_t *player = (mmplayer_t *)hplayer;
8547 /* check player handle */
8548 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8550 *silent = player->set_mode.subtitle_off;
8552 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8556 return MM_ERROR_NONE;
8560 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8562 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8563 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8565 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8566 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8570 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8571 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8572 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8573 mmplayer_dump_t *dump_s;
8574 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8575 if (dump_s == NULL) {
8576 LOGE("malloc fail");
8580 dump_s->dump_element_file = NULL;
8581 dump_s->dump_pad = NULL;
8582 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8584 if (dump_s->dump_pad) {
8585 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8586 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]);
8587 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8588 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);
8589 /* add list for removed buffer probe and close FILE */
8590 player->dump_list = g_list_append(player->dump_list, dump_s);
8591 LOGD("%s sink pad added buffer probe for dump", factory_name);
8594 MMPLAYER_FREEIF(dump_s);
8595 LOGE("failed to get %s sink pad added", factory_name);
8602 static GstPadProbeReturn
8603 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8605 FILE *dump_data = (FILE *)u_data;
8607 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8608 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8610 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8612 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8614 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8616 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8618 gst_buffer_unmap(buffer, &probe_info);
8620 return GST_PAD_PROBE_OK;
8624 __mmplayer_release_dump_list(GList *dump_list)
8626 GList *d_list = dump_list;
8631 for (; d_list; d_list = g_list_next(d_list)) {
8632 mmplayer_dump_t *dump_s = d_list->data;
8633 if (dump_s->dump_pad) {
8634 if (dump_s->probe_handle_id)
8635 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8636 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8638 if (dump_s->dump_element_file) {
8639 fclose(dump_s->dump_element_file);
8640 dump_s->dump_element_file = NULL;
8642 MMPLAYER_FREEIF(dump_s);
8644 g_list_free(dump_list);
8649 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8651 mmplayer_t *player = (mmplayer_t *)hplayer;
8655 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8656 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8658 *exist = (bool)player->has_closed_caption;
8662 return MM_ERROR_NONE;
8666 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8671 LOGD("unref internal gst buffer %p", buffer);
8673 gst_buffer_unref((GstBuffer *)buffer);
8680 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8682 mmplayer_t *player = (mmplayer_t *)hplayer;
8686 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8687 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8689 if (MMPLAYER_IS_STREAMING(player))
8690 *timeout = (int)player->ini.live_state_change_timeout;
8692 *timeout = (int)player->ini.localplayback_state_change_timeout;
8694 LOGD("timeout = %d", *timeout);
8697 return MM_ERROR_NONE;
8701 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8705 MMPLAYER_RETURN_IF_FAIL(player);
8707 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8709 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8710 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8711 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8712 player->storage_info[i].id = -1;
8713 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8715 if (path_type != MMPLAYER_PATH_MAX)
8724 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8726 int ret = MM_ERROR_NONE;
8727 mmplayer_t *player = (mmplayer_t *)hplayer;
8728 MMMessageParamType msg_param = {0, };
8731 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8733 LOGW("state changed storage %d:%d", id, state);
8735 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8736 return MM_ERROR_NONE;
8738 /* FIXME: text path should be handled separately. */
8739 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8740 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8741 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8742 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8743 LOGW("external storage is removed");
8745 if (player->msg_posted == FALSE) {
8746 memset(&msg_param, 0, sizeof(MMMessageParamType));
8747 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8748 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8749 player->msg_posted = TRUE;
8752 /* unrealize the player */
8753 ret = _mmplayer_unrealize(hplayer);
8754 if (ret != MM_ERROR_NONE)
8755 LOGE("failed to unrealize");
8763 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8765 int ret = MM_ERROR_NONE;
8766 mmplayer_t *player = (mmplayer_t *)hplayer;
8767 int idx = 0, total = 0;
8768 gchar *result = NULL, *tmp = NULL;
8771 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8772 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8774 total = *num = g_list_length(player->adaptive_info.var_list);
8776 LOGW("There is no stream variant info.");
8780 result = g_strdup("");
8781 for (idx = 0 ; idx < total ; idx++) {
8782 stream_variant_t *v_data = NULL;
8783 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8786 gchar data[64] = {0};
8787 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8789 tmp = g_strconcat(result, data, NULL);
8793 LOGW("There is no variant data in %d", idx);
8798 *var_info = (char *)result;
8800 LOGD("variant info %d:%s", *num, *var_info);
8806 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8808 int ret = MM_ERROR_NONE;
8809 mmplayer_t *player = (mmplayer_t *)hplayer;
8812 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8814 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8816 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8817 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8818 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8820 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8821 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8822 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8823 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8825 /* FIXME: seek to current position for applying new variant limitation */
8834 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8836 int ret = MM_ERROR_NONE;
8837 mmplayer_t *player = (mmplayer_t *)hplayer;
8840 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8841 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8843 *bandwidth = player->adaptive_info.limit.bandwidth;
8844 *width = player->adaptive_info.limit.width;
8845 *height = player->adaptive_info.limit.height;
8847 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8854 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8856 int ret = MM_ERROR_NONE;
8857 mmplayer_t *player = (mmplayer_t *)hplayer;
8860 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8861 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8862 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8864 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8866 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8867 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8868 else /* live case */
8869 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8871 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8878 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8880 #define IDX_FIRST_SW_CODEC 0
8881 mmplayer_t *player = (mmplayer_t *)hplayer;
8882 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8883 const char *attr_name = NULL;
8884 const char *default_type = NULL;
8885 const char *element_hw = NULL;
8886 const char *element_sw = NULL;
8889 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8891 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8893 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8894 switch (stream_type) {
8895 case MM_PLAYER_STREAM_TYPE_AUDIO:
8896 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8897 default_type = player->ini.audiocodec_default_type;
8898 element_hw = player->ini.audiocodec_element_hw;
8899 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8901 case MM_PLAYER_STREAM_TYPE_VIDEO:
8902 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8903 default_type = player->ini.videocodec_default_type;
8904 element_hw = player->ini.videocodec_element_hw;
8905 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8908 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8909 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8913 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8915 if (!strcmp(default_type, "sw"))
8916 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8918 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8920 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8921 codec_type = default_codec_type;
8923 /* to support codec selection, codec info have to be added in ini file.
8924 in case of hw codec is selected, filter elements should be applied
8925 depending on the hw capabilities. */
8926 if (codec_type != default_codec_type) {
8927 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
8928 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
8929 LOGE("There is no codec for type %d", codec_type);
8930 return MM_ERROR_PLAYER_NO_OP;
8933 LOGD("sorting is required");
8934 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
8935 player->need_audio_dec_sorting = TRUE;
8937 player->need_video_dec_sorting = TRUE;
8940 LOGD("update %s codec_type to %d", attr_name, codec_type);
8941 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8944 return MM_ERROR_NONE;
8948 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8950 mmplayer_t *player = (mmplayer_t *)hplayer;
8951 GstElement *rg_vol_element = NULL;
8955 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8957 player->sound.rg_enable = enabled;
8959 /* just hold rgvolume enable value if pipeline is not ready */
8960 if (!player->pipeline || !player->pipeline->audiobin) {
8961 LOGD("pipeline is not ready. holding rgvolume enable value");
8962 return MM_ERROR_NONE;
8965 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8967 if (!rg_vol_element) {
8968 LOGD("rgvolume element is not created");
8969 return MM_ERROR_PLAYER_INTERNAL;
8973 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8975 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8979 return MM_ERROR_NONE;
8983 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8985 mmplayer_t *player = (mmplayer_t *)hplayer;
8986 GstElement *rg_vol_element = NULL;
8987 gboolean enable = FALSE;
8991 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8992 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8994 /* just hold enable_rg value if pipeline is not ready */
8995 if (!player->pipeline || !player->pipeline->audiobin) {
8996 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8997 *enabled = player->sound.rg_enable;
8998 return MM_ERROR_NONE;
9001 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9003 if (!rg_vol_element) {
9004 LOGD("rgvolume element is not created");
9005 return MM_ERROR_PLAYER_INTERNAL;
9008 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9009 *enabled = (bool)enable;
9013 return MM_ERROR_NONE;
9017 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9019 mmplayer_t *player = (mmplayer_t *)hplayer;
9020 MMHandleType attrs = 0;
9022 int ret = MM_ERROR_NONE;
9026 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9028 attrs = MMPLAYER_GET_ATTRS(player);
9029 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9031 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9033 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9034 return MM_ERROR_PLAYER_INTERNAL;
9037 player->video_roi.scale_x = scale_x;
9038 player->video_roi.scale_y = scale_y;
9039 player->video_roi.scale_width = scale_width;
9040 player->video_roi.scale_height = scale_height;
9042 /* check video sinkbin is created */
9043 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9044 return MM_ERROR_NONE;
9046 if (!gst_video_overlay_set_video_roi_area(
9047 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9048 scale_x, scale_y, scale_width, scale_height))
9049 ret = MM_ERROR_PLAYER_INTERNAL;
9051 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9052 scale_x, scale_y, scale_width, scale_height);
9060 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9062 mmplayer_t *player = (mmplayer_t *)hplayer;
9063 int ret = MM_ERROR_NONE;
9067 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9068 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9070 *scale_x = player->video_roi.scale_x;
9071 *scale_y = player->video_roi.scale_y;
9072 *scale_width = player->video_roi.scale_width;
9073 *scale_height = player->video_roi.scale_height;
9075 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9076 *scale_x, *scale_y, *scale_width, *scale_height);
9082 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9084 mmplayer_t *player = (mmplayer_t *)hplayer;
9088 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9090 player->client_pid = pid;
9092 LOGD("client pid[%d] %p", pid, player);
9096 return MM_ERROR_NONE;
9100 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9102 mmplayer_t *player = (mmplayer_t *)hplayer;
9103 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9104 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9108 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9109 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9112 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9114 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9116 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9117 return MM_ERROR_NONE;
9119 /* in case of audio codec default type is HW */
9121 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9122 if (player->ini.support_audio_effect)
9123 return MM_ERROR_NONE;
9124 elem_id = MMPLAYER_A_FILTER;
9126 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9127 if (player->ini.support_replaygain_control)
9128 return MM_ERROR_NONE;
9129 elem_id = MMPLAYER_A_RGVOL;
9131 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9132 if (player->ini.support_pitch_control)
9133 return MM_ERROR_NONE;
9134 elem_id = MMPLAYER_A_PITCH;
9136 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9137 if (player->ini.support_audio_effect)
9138 return MM_ERROR_NONE;
9140 /* default case handling is not required */
9143 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9144 LOGW("audio control option [%d] is not available", opt);
9147 /* setting pcm exporting option is allowed before READY state */
9148 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9149 return MM_ERROR_PLAYER_INVALID_STATE;
9151 /* check whether the audio filter exist or not after READY state,
9152 because the sw codec could be added during auto-plugging in some cases */
9153 if (!player->pipeline ||
9154 !player->pipeline->audiobin ||
9155 !player->pipeline->audiobin[elem_id].gst) {
9156 LOGW("there is no audio elem [%d]", elem_id);
9161 LOGD("audio control opt %d, available %d", opt, *available);
9165 return MM_ERROR_NONE;
9169 __mmplayer_update_duration_value(mmplayer_t *player)
9171 gboolean ret = FALSE;
9172 gint64 dur_nsec = 0;
9173 LOGD("try to update duration");
9175 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9176 player->duration = dur_nsec;
9177 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9181 if (player->duration < 0) {
9182 LOGW("duration is Non-Initialized !!!");
9183 player->duration = 0;
9186 /* update streaming service type */
9187 player->streaming_type = _mmplayer_get_stream_service_type(player);
9189 /* check duration is OK */
9190 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9191 /* FIXIT : find another way to get duration here. */
9192 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9198 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9200 /* update audio params
9201 NOTE : We need original audio params and it can be only obtained from src pad of audio
9202 decoder. Below code only valid when we are not using 'resampler' just before
9203 'audioconverter'. */
9204 GstCaps *caps_a = NULL;
9206 gint samplerate = 0, channels = 0;
9207 GstStructure *p = NULL;
9208 GstElement *aconv = NULL;
9210 LOGD("try to update audio attrs");
9212 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9214 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9215 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9216 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9217 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9219 LOGE("there is no audio converter");
9223 pad = gst_element_get_static_pad(aconv, "sink");
9226 LOGW("failed to get pad from audio converter");
9230 caps_a = gst_pad_get_current_caps(pad);
9232 LOGW("not ready to get audio caps");
9233 gst_object_unref(pad);
9237 p = gst_caps_get_structure(caps_a, 0);
9239 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9241 gst_structure_get_int(p, "rate", &samplerate);
9242 gst_structure_get_int(p, "channels", &channels);
9244 mm_player_set_attribute((MMHandleType)player, NULL,
9245 "content_audio_samplerate", samplerate,
9246 "content_audio_channels", channels, NULL);
9248 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9250 gst_caps_unref(caps_a);
9251 gst_object_unref(pad);
9257 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9259 LOGD("try to update video attrs");
9261 GstCaps *caps_v = NULL;
9265 GstStructure *p = NULL;
9267 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9268 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9270 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9272 LOGD("no videosink sink pad");
9276 caps_v = gst_pad_get_current_caps(pad);
9277 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9278 if (!caps_v && player->v_stream_caps) {
9279 caps_v = player->v_stream_caps;
9280 gst_caps_ref(caps_v);
9284 LOGD("no negotiated caps from videosink");
9285 gst_object_unref(pad);
9289 p = gst_caps_get_structure(caps_v, 0);
9290 gst_structure_get_int(p, "width", &width);
9291 gst_structure_get_int(p, "height", &height);
9293 mm_player_set_attribute((MMHandleType)player, NULL,
9294 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9296 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9298 SECURE_LOGD("width : %d height : %d", width, height);
9300 gst_caps_unref(caps_v);
9301 gst_object_unref(pad);
9304 mm_player_set_attribute((MMHandleType)player, NULL,
9305 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9306 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9313 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9315 gboolean ret = FALSE;
9316 guint64 data_size = 0;
9320 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9321 if (!player->duration)
9324 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9325 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9326 if (stat(path, &sb) == 0)
9327 data_size = (guint64)sb.st_size;
9329 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9330 data_size = player->http_content_size;
9333 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9336 guint64 bitrate = 0;
9337 guint64 msec_dur = 0;
9339 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9341 bitrate = data_size * 8 * 1000 / msec_dur;
9342 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9343 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9344 mm_player_set_attribute((MMHandleType)player, NULL,
9345 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9348 LOGD("player duration is less than 0");
9352 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9353 if (player->total_bitrate) {
9354 mm_player_set_attribute((MMHandleType)player, NULL,
9355 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9364 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9366 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9367 data->uri_type = uri_type;
9371 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9373 int ret = MM_ERROR_PLAYER_INVALID_URI;
9375 char *buffer = NULL;
9376 char *seperator = strchr(path, ',');
9377 char ext[100] = {0,}, size[100] = {0,};
9380 if ((buffer = strstr(path, "ext="))) {
9381 buffer += strlen("ext=");
9383 if (strlen(buffer)) {
9384 strncpy(ext, buffer, 99);
9386 if ((seperator = strchr(ext, ','))
9387 || (seperator = strchr(ext, ' '))
9388 || (seperator = strchr(ext, '\0'))) {
9389 seperator[0] = '\0';
9394 if ((buffer = strstr(path, "size="))) {
9395 buffer += strlen("size=");
9397 if (strlen(buffer) > 0) {
9398 strncpy(size, buffer, 99);
9400 if ((seperator = strchr(size, ','))
9401 || (seperator = strchr(size, ' '))
9402 || (seperator = strchr(size, '\0'))) {
9403 seperator[0] = '\0';
9406 mem_size = atoi(size);
9411 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9413 if (mem_size && param) {
9414 if (data->input_mem.buf)
9415 free(data->input_mem.buf);
9416 data->input_mem.buf = malloc(mem_size);
9418 if (data->input_mem.buf) {
9419 memcpy(data->input_mem.buf, param, mem_size);
9420 data->input_mem.len = mem_size;
9421 ret = MM_ERROR_NONE;
9423 LOGE("failed to alloc mem %d", mem_size);
9424 ret = MM_ERROR_PLAYER_INTERNAL;
9427 data->input_mem.offset = 0;
9428 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9435 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9437 gchar *location = NULL;
9440 int ret = MM_ERROR_NONE;
9442 if ((path = strstr(uri, "file://"))) {
9443 location = g_filename_from_uri(uri, NULL, &err);
9444 if (!location || (err != NULL)) {
9445 LOGE("Invalid URI '%s' for filesrc: %s", path,
9446 (err != NULL) ? err->message : "unknown error");
9450 MMPLAYER_FREEIF(location);
9452 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9453 return MM_ERROR_PLAYER_INVALID_URI;
9455 LOGD("path from uri: %s", location);
9458 path = (location != NULL) ? (location) : ((char *)uri);
9461 ret = _mmplayer_exist_file_path(path);
9463 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9464 if (ret == MM_ERROR_NONE) {
9465 if (_mmplayer_is_sdp_file(path)) {
9466 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9467 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9468 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9470 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9471 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9473 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9474 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9476 LOGE("invalid uri, could not play..");
9477 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9480 MMPLAYER_FREEIF(location);
9485 static mmplayer_video_decoded_data_info_t *
9486 __mmplayer_create_stream_from_pad(GstPad *pad)
9488 GstCaps *caps = NULL;
9489 GstStructure *structure = NULL;
9490 unsigned int fourcc = 0;
9491 const gchar *string_format = NULL;
9492 mmplayer_video_decoded_data_info_t *stream = NULL;
9494 MMPixelFormatType format;
9497 caps = gst_pad_get_current_caps(pad);
9499 LOGE("Caps is NULL.");
9504 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9506 structure = gst_caps_get_structure(caps, 0);
9507 gst_structure_get_int(structure, "width", &width);
9508 gst_structure_get_int(structure, "height", &height);
9509 string_format = gst_structure_get_string(structure, "format");
9512 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9513 format = _mmplayer_get_pixtype(fourcc);
9514 gst_video_info_from_caps(&info, caps);
9515 gst_caps_unref(caps);
9518 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9519 LOGE("Wrong condition!!");
9523 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9525 LOGE("failed to alloc mem for video data");
9529 stream->width = width;
9530 stream->height = height;
9531 stream->format = format;
9532 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9538 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9540 unsigned int pitch = 0;
9541 unsigned int size = 0;
9543 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9546 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9547 bo = gst_tizen_memory_get_bos(mem, index);
9549 stream->bo[index] = tbm_bo_ref(bo);
9551 LOGE("failed to get bo for index %d", index);
9554 for (index = 0; index < stream->plane_num; index++) {
9555 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9556 stream->stride[index] = pitch;
9558 stream->elevation[index] = size / pitch;
9560 stream->elevation[index] = stream->height;
9565 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9567 if (stream->format == MM_PIXEL_FORMAT_I420) {
9568 int ret = TBM_SURFACE_ERROR_NONE;
9569 tbm_surface_h surface;
9570 tbm_surface_info_s info;
9572 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9574 ret = tbm_surface_get_info(surface, &info);
9575 if (ret != TBM_SURFACE_ERROR_NONE) {
9576 tbm_surface_destroy(surface);
9580 tbm_surface_destroy(surface);
9581 stream->stride[0] = info.planes[0].stride;
9582 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9583 stream->stride[1] = info.planes[1].stride;
9584 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9585 stream->stride[2] = info.planes[2].stride;
9586 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9587 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9588 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9589 stream->stride[0] = stream->width * 4;
9590 stream->elevation[0] = stream->height;
9591 stream->bo_size = stream->stride[0] * stream->height;
9593 LOGE("Not support format %d", stream->format);
9601 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9603 tbm_bo_handle thandle;
9605 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9606 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9607 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9611 unsigned char *src = NULL;
9612 unsigned char *dest = NULL;
9613 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9615 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9617 LOGE("fail to gst_memory_map");
9621 if (!mapinfo.data) {
9622 LOGE("data pointer is wrong");
9626 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9627 if (!stream->bo[0]) {
9628 LOGE("Fail to tbm_bo_alloc!!");
9632 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9634 LOGE("thandle pointer is wrong");
9638 if (stream->format == MM_PIXEL_FORMAT_I420) {
9639 src_stride[0] = GST_ROUND_UP_4(stream->width);
9640 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9641 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9642 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9645 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9646 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9648 for (i = 0; i < 3; i++) {
9649 src = mapinfo.data + src_offset[i];
9650 dest = thandle.ptr + dest_offset[i];
9655 for (j = 0; j < stream->height >> k; j++) {
9656 memcpy(dest, src, stream->width>>k);
9657 src += src_stride[i];
9658 dest += stream->stride[i];
9661 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9662 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9664 LOGE("Not support format %d", stream->format);
9668 tbm_bo_unmap(stream->bo[0]);
9669 gst_memory_unmap(mem, &mapinfo);
9675 tbm_bo_unmap(stream->bo[0]);
9678 gst_memory_unmap(mem, &mapinfo);
9684 __mmplayer_set_pause_state(mmplayer_t *player)
9686 if (player->sent_bos)
9689 /* rtsp case, get content attrs by GstMessage */
9690 if (MMPLAYER_IS_RTSP_STREAMING(player))
9693 /* it's first time to update all content attrs. */
9694 _mmplayer_update_content_attrs(player, ATTR_ALL);
9698 __mmplayer_set_playing_state(mmplayer_t *player)
9700 gchar *audio_codec = NULL;
9702 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9703 /* initialize because auto resume is done well. */
9704 player->resumed_by_rewind = FALSE;
9705 player->playback_rate = 1.0;
9708 if (player->sent_bos)
9711 /* try to get content metadata */
9713 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9714 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9715 * legacy mmfw-player api
9717 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9719 if ((player->cmd == MMPLAYER_COMMAND_START)
9720 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9721 __mmplayer_handle_missed_plugin(player);
9724 /* check audio codec field is set or not
9725 * we can get it from typefinder or codec's caps.
9727 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9729 /* The codec format can't be sent for audio only case like amr, mid etc.
9730 * Because, parser don't make related TAG.
9731 * So, if it's not set yet, fill it with found data.
9734 if (g_strrstr(player->type, "audio/midi"))
9735 audio_codec = "MIDI";
9736 else if (g_strrstr(player->type, "audio/x-amr"))
9737 audio_codec = "AMR";
9738 else if (g_strrstr(player->type, "audio/mpeg")
9739 && !g_strrstr(player->type, "mpegversion=(int)1"))
9740 audio_codec = "AAC";
9742 audio_codec = "unknown";
9744 if (mm_player_set_attribute((MMHandleType)player, NULL,
9745 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9746 LOGE("failed to set attribute");
9748 LOGD("set audio codec type with caps");