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");
3778 /* unset sink flag from textbin. not to hold eos when video data is shorter than subtitle */
3779 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_BIN].gst, GST_ELEMENT_FLAG_SINK);
3780 GST_OBJECT_FLAG_UNSET(textbin[MMPLAYER_T_FAKE_SINK].gst, GST_ELEMENT_FLAG_SINK);
3782 /* linking elements in the bucket by added order. */
3783 LOGD("Linking elements in the bucket by added order.");
3784 if (_mmplayer_gst_element_link_bucket(element_bucket) == -1) {
3785 LOGE("failed to link elements");
3789 /* done. free allocated variables */
3790 g_list_free(element_bucket);
3792 if (textbin[MMPLAYER_T_QUEUE].gst) {
3794 GstPad *ghostpad = NULL;
3796 pad = gst_element_get_static_pad(GST_ELEMENT(textbin[MMPLAYER_T_QUEUE].gst), "sink");
3798 LOGE("failed to get sink pad of text queue");
3802 ghostpad = gst_ghost_pad_new("text_sink", pad);
3803 gst_object_unref(pad);
3806 LOGE("failed to create ghostpad of textbin");
3810 if (!gst_element_add_pad(textbin[MMPLAYER_T_BIN].gst, ghostpad)) {
3811 LOGE("failed to add ghostpad to textbin");
3812 gst_object_unref(ghostpad);
3817 return MM_ERROR_NONE;
3820 g_list_free(element_bucket);
3822 if (!player->play_subtitle && textbin[MMPLAYER_T_FAKE_SINK].gst) {
3823 LOGE("remove textbin sink from sink list");
3824 __mmplayer_del_sink(player, textbin[MMPLAYER_T_FAKE_SINK].gst);
3827 /* release element at __mmplayer_gst_create_text_sink_bin */
3828 return MM_ERROR_PLAYER_INTERNAL;
3832 __mmplayer_gst_create_text_sink_bin(mmplayer_t *player)
3834 mmplayer_gst_element_t *textbin = NULL;
3835 GList *element_bucket = NULL;
3836 int surface_type = 0;
3841 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
3844 textbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_T_NUM);
3846 LOGE("failed to allocate memory for textbin");
3847 return MM_ERROR_PLAYER_NO_FREE_SPACE;
3851 textbin[MMPLAYER_T_BIN].id = MMPLAYER_T_BIN;
3852 textbin[MMPLAYER_T_BIN].gst = gst_bin_new("textbin");
3853 if (!textbin[MMPLAYER_T_BIN].gst) {
3854 LOGE("failed to create textbin");
3859 player->pipeline->textbin = textbin;
3862 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
3863 LOGD("surface type for subtitle : %d", surface_type);
3864 switch (surface_type) {
3865 case MM_DISPLAY_SURFACE_OVERLAY:
3866 case MM_DISPLAY_SURFACE_NULL:
3867 case MM_DISPLAY_SURFACE_REMOTE:
3868 if (__mmplayer_gst_create_plain_text_elements(player) != MM_ERROR_NONE) {
3869 LOGE("failed to make plain text elements");
3880 return MM_ERROR_NONE;
3884 LOGD("ERROR : releasing textbin");
3886 g_list_free(element_bucket);
3888 /* release signal */
3889 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
3891 /* release element which are not added to bin */
3892 for (i = 1; i < MMPLAYER_T_NUM; i++) {
3893 /* NOTE : skip bin */
3894 if (textbin[i].gst) {
3895 GstObject *parent = NULL;
3896 parent = gst_element_get_parent(textbin[i].gst);
3899 gst_object_unref(GST_OBJECT(textbin[i].gst));
3900 textbin[i].gst = NULL;
3902 gst_object_unref(GST_OBJECT(parent));
3907 /* release textbin with it's children */
3908 if (textbin[MMPLAYER_T_BIN].gst)
3909 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
3911 MMPLAYER_FREEIF(textbin);
3912 player->pipeline->textbin = NULL;
3915 return MM_ERROR_PLAYER_INTERNAL;
3919 __mmplayer_gst_create_text_pipeline(mmplayer_t *player)
3921 mmplayer_gst_element_t *mainbin = NULL;
3922 mmplayer_gst_element_t *textbin = NULL;
3923 MMHandleType attrs = 0;
3924 GstElement *subsrc = NULL;
3925 GstElement *subparse = NULL;
3926 gchar *subtitle_uri = NULL;
3927 const gchar *charset = NULL;
3933 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
3935 player->pipeline->mainbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
3937 mainbin = player->pipeline->mainbin;
3939 attrs = MMPLAYER_GET_ATTRS(player);
3941 LOGE("cannot get content attribute");
3942 return MM_ERROR_PLAYER_INTERNAL;
3945 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
3946 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
3947 LOGE("subtitle uri is not proper filepath.");
3948 return MM_ERROR_PLAYER_INVALID_URI;
3951 if (!_mmplayer_get_storage_info(subtitle_uri, &player->storage_info[MMPLAYER_PATH_TEXT])) {
3952 LOGE("failed to get storage info of subtitle path");
3953 return MM_ERROR_PLAYER_INVALID_URI;
3956 SECURE_LOGD("subtitle file path is [%s].", subtitle_uri);
3958 MMPLAYER_SUBTITLE_INFO_LOCK(player);
3959 player->subtitle_language_list = NULL;
3960 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
3962 /* create the subtitle source */
3963 subsrc = gst_element_factory_make("filesrc", "subtitle_source");
3965 LOGE("failed to create filesrc element");
3968 g_object_set(G_OBJECT(subsrc), "location", subtitle_uri, NULL);
3970 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_SUBSRC;
3971 mainbin[MMPLAYER_M_SUBSRC].gst = subsrc;
3973 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subsrc)) {
3974 LOGW("failed to add queue");
3975 gst_object_unref(mainbin[MMPLAYER_M_SUBSRC].gst);
3976 mainbin[MMPLAYER_M_SUBSRC].gst = NULL;
3977 mainbin[MMPLAYER_M_SUBSRC].id = MMPLAYER_M_NUM;
3982 subparse = gst_element_factory_make("subparse", "subtitle_parser");
3984 LOGE("failed to create subparse element");
3988 charset = _mmplayer_get_charset(subtitle_uri);
3990 LOGD("detected charset is %s", charset);
3991 g_object_set(G_OBJECT(subparse), "subtitle-encoding", charset, NULL);
3994 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_SUBPARSE;
3995 mainbin[MMPLAYER_M_SUBPARSE].gst = subparse;
3997 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), subparse)) {
3998 LOGW("failed to add subparse");
3999 gst_object_unref(mainbin[MMPLAYER_M_SUBPARSE].gst);
4000 mainbin[MMPLAYER_M_SUBPARSE].gst = NULL;
4001 mainbin[MMPLAYER_M_SUBPARSE].id = MMPLAYER_M_NUM;
4005 if (!gst_element_link_pads(subsrc, "src", subparse, "sink")) {
4006 LOGW("failed to link subsrc and subparse");
4010 player->play_subtitle = TRUE;
4011 player->adjust_subtitle_pos = 0;
4013 LOGD("play subtitle using subtitle file");
4015 if (player->pipeline->textbin == NULL) {
4016 if (MM_ERROR_NONE != __mmplayer_gst_create_text_sink_bin(player)) {
4017 LOGE("failed to create text sink bin. continuing without text");
4021 textbin = player->pipeline->textbin;
4023 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), GST_ELEMENT(textbin[MMPLAYER_T_BIN].gst))) {
4024 LOGW("failed to add textbin");
4026 /* release signal */
4027 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4029 /* release textbin with it's children */
4030 gst_object_unref(GST_OBJECT(textbin[MMPLAYER_T_BIN].gst));
4031 MMPLAYER_FREEIF(player->pipeline->textbin);
4032 player->pipeline->textbin = textbin = NULL;
4036 LOGD("link text input selector and textbin ghost pad");
4038 player->textsink_linked = 1;
4039 player->external_text_idx = 0;
4040 LOGI("textsink is linked");
4042 textbin = player->pipeline->textbin;
4043 LOGD("text bin has been created. reuse it.");
4044 player->external_text_idx = 1;
4047 if (!gst_element_link_pads(subparse, "src", textbin[MMPLAYER_T_BIN].gst, "text_sink")) {
4048 LOGW("failed to link subparse and textbin");
4052 pad = gst_element_get_static_pad(textbin[MMPLAYER_T_FAKE_SINK].gst, "sink");
4054 LOGE("failed to get sink pad from textsink to probe data");
4058 gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
4059 __mmplayer_subtitle_adjust_position_probe, player, NULL);
4061 gst_object_unref(pad);
4064 /* create dot. for debugging */
4065 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-with-subtitle");
4068 return MM_ERROR_NONE;
4071 /* release text pipeline resource */
4072 player->textsink_linked = 0;
4074 /* release signal */
4075 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
4077 if (player->pipeline->textbin) {
4078 LOGE("remove textbin");
4080 /* release textbin with it's children */
4081 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
4082 MMPLAYER_FREEIF(player->pipeline->textbin);
4083 player->pipeline->textbin = NULL;
4087 /* release subtitle elem */
4088 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
4089 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
4091 return MM_ERROR_PLAYER_INTERNAL;
4095 __mmplayer_update_subtitle(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data)
4097 mmplayer_t *player = (mmplayer_t *)data;
4098 MMMessageParamType msg = {0, };
4099 GstClockTime duration = 0;
4100 gpointer text = NULL;
4101 guint text_size = 0;
4102 gboolean ret = TRUE;
4103 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
4107 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4108 MMPLAYER_RETURN_VAL_IF_FAIL(buffer, FALSE);
4110 if (player->is_subtitle_force_drop) {
4111 LOGW("subtitle is dropped forcedly.");
4115 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
4116 text = mapinfo.data;
4117 text_size = mapinfo.size;
4119 if (player->set_mode.subtitle_off) {
4120 LOGD("subtitle is OFF.");
4124 if (!text || (text_size == 0)) {
4125 LOGD("There is no subtitle to be displayed.");
4129 msg.data = (void *)text;
4131 duration = GST_BUFFER_DURATION(buffer);
4133 if (!GST_CLOCK_TIME_IS_VALID(duration)) {
4134 if (player->duration > GST_BUFFER_PTS(buffer))
4135 duration = player->duration - GST_BUFFER_PTS(buffer);
4138 LOGI("subtitle duration is invalid, subtitle duration change "
4139 "GST_CLOCK_TIME_NONE -> %" GST_TIME_FORMAT, GST_TIME_ARGS(duration));
4141 msg.subtitle.duration = GST_TIME_AS_MSECONDS(duration);
4143 LOGD("update subtitle : [%ld msec] %s", msg.subtitle.duration, (char *)msg.data);
4145 MMPLAYER_POST_MSG(player, MM_MESSAGE_UPDATE_SUBTITLE, &msg);
4146 gst_buffer_unmap(buffer, &mapinfo);
4153 static GstPadProbeReturn
4154 __mmplayer_subtitle_adjust_position_probe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
4156 mmplayer_t *player = (mmplayer_t *)u_data;
4157 GstClockTime cur_timestamp = 0;
4158 gint64 adjusted_timestamp = 0;
4159 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
4161 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
4163 if (player->set_mode.subtitle_off) {
4164 LOGD("subtitle is OFF.");
4168 if (player->adjust_subtitle_pos == 0) {
4169 LOGD("nothing to do");
4173 cur_timestamp = GST_BUFFER_TIMESTAMP(buffer);
4174 adjusted_timestamp = (gint64)cur_timestamp + ((gint64)player->adjust_subtitle_pos * G_GINT64_CONSTANT(1000000));
4176 if (adjusted_timestamp < 0) {
4177 LOGD("adjusted_timestamp under zero");
4182 GST_BUFFER_TIMESTAMP(buffer) = (GstClockTime) adjusted_timestamp;
4183 LOGD("buffer timestamp changed %" GST_TIME_FORMAT " -> %" GST_TIME_FORMAT "",
4184 GST_TIME_ARGS(cur_timestamp),
4185 GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
4187 return GST_PAD_PROBE_OK;
4191 __mmplayer_gst_adjust_subtitle_position(mmplayer_t *player, int position)
4195 /* check player and subtitlebin are created */
4196 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
4197 MMPLAYER_RETURN_VAL_IF_FAIL(player->play_subtitle, MM_ERROR_NOT_SUPPORT_API);
4199 if (position == 0) {
4200 LOGD("nothing to do");
4202 return MM_ERROR_NONE;
4205 /* check current position */
4206 player->adjust_subtitle_pos = position;
4208 LOGD("save adjust_subtitle_pos in player");
4212 return MM_ERROR_NONE;
4216 * This function is to create audio or video pipeline for playing.
4218 * @param player [in] handle of player
4220 * @return This function returns zero on success.
4225 __mmplayer_gst_create_pipeline(mmplayer_t *player)
4227 int ret = MM_ERROR_NONE;
4228 mmplayer_gst_element_t *mainbin = NULL;
4229 MMHandleType attrs = 0;
4232 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4234 /* get profile attribute */
4235 attrs = MMPLAYER_GET_ATTRS(player);
4237 LOGE("failed to get content attribute");
4241 /* create pipeline handles */
4242 if (player->pipeline) {
4243 LOGE("pipeline should be released before create new one");
4247 player->pipeline = (mmplayer_pipeline_info_t *)g_malloc0(sizeof(mmplayer_pipeline_info_t));
4249 /* create mainbin */
4250 mainbin = (mmplayer_gst_element_t *)g_try_malloc0(sizeof(mmplayer_gst_element_t) * MMPLAYER_M_NUM);
4251 if (mainbin == NULL)
4254 /* create pipeline */
4255 mainbin[MMPLAYER_M_PIPE].id = MMPLAYER_M_PIPE;
4256 mainbin[MMPLAYER_M_PIPE].gst = gst_pipeline_new("player");
4257 if (!mainbin[MMPLAYER_M_PIPE].gst) {
4258 LOGE("failed to create pipeline");
4263 player->pipeline->mainbin = mainbin;
4265 /* create the source and decoder elements */
4266 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
4267 ret = _mmplayer_gst_build_es_pipeline(player);
4269 if (MMPLAYER_USE_DECODEBIN(player))
4270 ret = _mmplayer_gst_build_pipeline(player); /* TEMP: previous pipeline, will be removed.*/
4272 ret = _mmplayer_gst_build_pipeline_with_src(player);
4275 if (ret != MM_ERROR_NONE) {
4276 LOGE("failed to create some elements");
4280 /* Note : check whether subtitle attribute uri is set. If uri is set, then try to play subtitle file */
4281 if (__mmplayer_check_subtitle(player)
4282 && (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE))
4283 LOGE("failed to create text pipeline");
4286 ret = _mmplayer_gst_add_bus_watch(player);
4287 if (ret != MM_ERROR_NONE) {
4288 LOGE("failed to add bus watch");
4293 return MM_ERROR_NONE;
4296 _mmplayer_bus_watcher_remove(player);
4297 __mmplayer_gst_destroy_pipeline(player);
4298 return MM_ERROR_PLAYER_INTERNAL;
4302 __mmplayer_reset_gapless_state(mmplayer_t *player)
4305 MMPLAYER_RETURN_IF_FAIL(player
4307 && player->pipeline->audiobin
4308 && player->pipeline->audiobin[MMPLAYER_A_BIN].gst);
4310 memset(&player->gapless, 0, sizeof(mmplayer_gapless_t));
4317 __mmplayer_gst_destroy_pipeline(mmplayer_t *player)
4320 int ret = MM_ERROR_NONE;
4324 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_INVALID_HANDLE);
4326 /* cleanup stuffs */
4327 MMPLAYER_FREEIF(player->type);
4328 player->no_more_pad = FALSE;
4329 player->num_dynamic_pad = 0;
4331 MMPLAYER_SUBTITLE_INFO_LOCK(player);
4332 player->subtitle_language_list = NULL;
4333 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
4335 MMPLAYER_RECONFIGURE_LOCK(player);
4336 __mmplayer_reset_gapless_state(player);
4337 MMPLAYER_RECONFIGURE_UNLOCK(player);
4339 if (player->streamer) {
4340 _mm_player_streaming_initialize(player->streamer, FALSE);
4341 _mm_player_streaming_destroy(player->streamer);
4342 player->streamer = NULL;
4345 /* cleanup unlinked mime type */
4346 MMPLAYER_FREEIF(player->unlinked_audio_mime);
4347 MMPLAYER_FREEIF(player->unlinked_video_mime);
4348 MMPLAYER_FREEIF(player->unlinked_demuxer_mime);
4350 /* cleanup running stuffs */
4351 _mmplayer_cancel_eos_timer(player);
4353 /* cleanup gst stuffs */
4354 if (player->pipeline) {
4355 mmplayer_gst_element_t *mainbin = player->pipeline->mainbin;
4356 GstTagList *tag_list = player->pipeline->tag_list;
4358 /* first we need to disconnect all signal hander */
4359 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
4362 mmplayer_gst_element_t *audiobin = player->pipeline->audiobin;
4363 mmplayer_gst_element_t *videobin = player->pipeline->videobin;
4364 mmplayer_gst_element_t *textbin = player->pipeline->textbin;
4365 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
4366 gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
4367 gst_object_unref(bus);
4369 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4370 ret = _mmplayer_gst_set_state(player, mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_NULL, FALSE, timeout);
4371 if (ret != MM_ERROR_NONE) {
4372 LOGE("fail to change state to NULL");
4373 return MM_ERROR_PLAYER_INTERNAL;
4376 LOGW("succeeded in changing state to NULL");
4378 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_PIPE].gst));
4381 if (mainbin[MMPLAYER_M_SRC_FAKESINK].gst)
4382 gst_object_unref(GST_OBJECT(mainbin[MMPLAYER_M_SRC_FAKESINK].gst));
4384 MMPLAYER_FREEIF(audiobin);
4385 MMPLAYER_FREEIF(videobin);
4386 MMPLAYER_FREEIF(textbin);
4387 MMPLAYER_FREEIF(mainbin);
4391 gst_tag_list_unref(tag_list);
4393 MMPLAYER_FREEIF(player->pipeline);
4395 MMPLAYER_FREEIF(player->album_art);
4397 if (player->type_caps) {
4398 gst_caps_unref(player->type_caps);
4399 player->type_caps = NULL;
4402 if (player->v_stream_caps) {
4403 gst_caps_unref(player->v_stream_caps);
4404 player->v_stream_caps = NULL;
4407 if (player->a_stream_caps) {
4408 gst_caps_unref(player->a_stream_caps);
4409 player->a_stream_caps = NULL;
4412 if (player->s_stream_caps) {
4413 gst_caps_unref(player->s_stream_caps);
4414 player->s_stream_caps = NULL;
4416 _mmplayer_track_destroy(player);
4418 if (player->sink_elements)
4419 g_list_free(player->sink_elements);
4420 player->sink_elements = NULL;
4422 if (player->bufmgr) {
4423 tbm_bufmgr_deinit(player->bufmgr);
4424 player->bufmgr = NULL;
4427 LOGW("finished destroy pipeline");
4435 __mmplayer_gst_realize(mmplayer_t *player)
4438 int ret = MM_ERROR_NONE;
4442 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4444 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_READY;
4446 ret = __mmplayer_gst_create_pipeline(player);
4448 LOGE("failed to create pipeline");
4452 /* set pipeline state to READY */
4453 /* NOTE : state change to READY must be performed sync. */
4454 timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
4455 ret = _mmplayer_gst_set_state(player,
4456 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_STATE_READY, FALSE, timeout);
4458 if (ret != MM_ERROR_NONE) {
4459 /* return error if failed to set state */
4460 LOGE("failed to set READY state");
4464 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_READY);
4466 /* create dot before error-return. for debugging */
4467 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-realize");
4475 __mmplayer_gst_unrealize(mmplayer_t *player)
4477 int ret = MM_ERROR_NONE;
4481 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4483 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NULL;
4484 MMPLAYER_PRINT_STATE(player);
4486 /* release miscellaneous information */
4487 __mmplayer_release_misc(player);
4489 /* destroy pipeline */
4490 ret = __mmplayer_gst_destroy_pipeline(player);
4491 if (ret != MM_ERROR_NONE) {
4492 LOGE("failed to destroy pipeline");
4496 /* release miscellaneous information.
4497 these info needs to be released after pipeline is destroyed. */
4498 __mmplayer_release_misc_post(player);
4500 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4508 __mmplayer_gst_set_message_callback(mmplayer_t *player, MMMessageCallback callback, gpointer user_param)
4513 LOGW("set_message_callback is called with invalid player handle");
4514 return MM_ERROR_PLAYER_NOT_INITIALIZED;
4517 player->msg_cb = callback;
4518 player->msg_cb_param = user_param;
4520 LOGD("msg_cb : %p msg_cb_param : %p", callback, user_param);
4524 return MM_ERROR_NONE;
4528 _mmplayer_parse_profile(const char *uri, void *param, mmplayer_parse_profile_t *data)
4530 int ret = MM_ERROR_NONE;
4535 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_PLAYER_INVALID_URI);
4536 MMPLAYER_RETURN_VAL_IF_FAIL(data, MM_ERROR_PLAYER_INTERNAL);
4537 MMPLAYER_RETURN_VAL_IF_FAIL((strlen(uri) <= MM_MAX_URL_LEN), MM_ERROR_PLAYER_INVALID_URI);
4539 memset(data, 0, sizeof(mmplayer_parse_profile_t));
4541 if (strstr(uri, "es_buff://")) {
4542 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_MS_BUFF);
4543 } else if (strstr(uri, "rtsp://") || strstr(uri, "rtsps://") || strstr(uri, "rtspu://")) {
4544 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_RTSP);
4545 } else if (strstr(uri, "http://") || strstr(uri, "https://")) {
4547 tmp = g_ascii_strdown(uri, strlen(uri));
4548 if (tmp && (g_str_has_suffix(tmp, ".ism/manifest") || g_str_has_suffix(tmp, ".isml/manifest")))
4549 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_SS);
4551 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_HTTP);
4553 } else if (strstr(uri, "mms://")) {
4554 __mmplayer_copy_uri_and_set_type(data, uri, MM_PLAYER_URI_TYPE_URL_MMS);
4555 } else if ((path = strstr(uri, "mem://"))) {
4556 ret = __mmplayer_set_mem_uri(data, path, param);
4558 ret = __mmplayer_set_file_uri(data, uri);
4561 if (data->uri_type == MM_PLAYER_URI_TYPE_NONE)
4562 ret = MM_ERROR_PLAYER_FILE_NOT_FOUND;
4563 else if (data->uri_type == MM_PLAYER_URI_TYPE_NO_PERMISSION)
4564 ret = MM_ERROR_PLAYER_PERMISSION_DENIED;
4566 /* dump parse result */
4567 SECURE_LOGW("incoming uri : %s", uri);
4568 LOGD("uri_type : %d, mem : %p, mem_size : %d, urgent : %s",
4569 data->uri_type, data->input_mem.buf, data->input_mem.len, data->urgent);
4577 __resource_release_cb(mm_resource_manager_h rm, mm_resource_manager_res_h res,
4580 mmplayer_t *player = NULL;
4581 MMMessageParamType msg = {0, };
4583 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
4588 LOGE("user_data is null");
4592 player = (mmplayer_t *)user_data;
4594 if (!player->pipeline || !player->attrs) {
4595 LOGW("not initialized");
4599 LOGD("cmd lock player, cmd state : %d", player->cmd);
4600 MMPLAYER_CMD_LOCK(player);
4601 LOGD("cmd locked player");
4603 if (MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NULL
4604 || MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_NONE) {
4605 LOGW("player already destroyed");
4606 MMPLAYER_CMD_UNLOCK(player);
4610 player->interrupted_by_resource = TRUE;
4612 /* get last play position */
4613 if (_mmplayer_gst_get_position(player, &pos) == MM_ERROR_NONE) {
4614 msg.union_type = MM_MSG_UNION_TIME;
4615 msg.time.elapsed = pos;
4616 MMPLAYER_POST_MSG(player, MM_MESSAGE_PLAY_POSITION, &msg);
4618 LOGW("failed to get play position.");
4621 LOGD("video resource conflict so, resource will be freed by unrealizing");
4622 if (_mmplayer_unrealize((MMHandleType)player) != MM_ERROR_NONE)
4623 LOGE("failed to unrealize");
4625 MMPLAYER_CMD_UNLOCK(player);
4627 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
4628 player->hw_resource[res_idx] = NULL;
4632 return TRUE; /* release all the resources */
4636 __mmplayer_initialize_video_roi(mmplayer_t *player)
4638 player->video_roi.scale_x = 0.0;
4639 player->video_roi.scale_y = 0.0;
4640 player->video_roi.scale_width = 1.0;
4641 player->video_roi.scale_height = 1.0;
4645 _mmplayer_create_player(MMHandleType handle)
4647 int ret = MM_ERROR_PLAYER_INTERNAL;
4648 bool enabled = false;
4650 mmplayer_t *player = MM_PLAYER_CAST(handle);
4654 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4656 /* initialize player state */
4657 MMPLAYER_CURRENT_STATE(player) = MM_PLAYER_STATE_NONE;
4658 MMPLAYER_PREV_STATE(player) = MM_PLAYER_STATE_NONE;
4659 MMPLAYER_PENDING_STATE(player) = MM_PLAYER_STATE_NONE;
4660 MMPLAYER_TARGET_STATE(player) = MM_PLAYER_STATE_NONE;
4662 /* check current state */
4663 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_CREATE);
4665 /* construct attributes */
4666 player->attrs = _mmplayer_construct_attribute(handle);
4668 if (!player->attrs) {
4669 LOGE("Failed to construct attributes");
4673 /* initialize gstreamer with configured parameter */
4674 if (!__mmplayer_init_gstreamer(player)) {
4675 LOGE("Initializing gstreamer failed");
4676 _mmplayer_deconstruct_attribute(handle);
4680 /* create lock. note that g_tread_init() has already called in gst_init() */
4681 g_mutex_init(&player->fsink_lock);
4683 /* create update tag lock */
4684 g_mutex_init(&player->update_tag_lock);
4686 /* create gapless play mutex */
4687 g_mutex_init(&player->gapless_play_thread_mutex);
4689 /* create gapless play cond */
4690 g_cond_init(&player->gapless_play_thread_cond);
4692 /* create gapless play thread */
4693 player->gapless_play_thread =
4694 g_thread_try_new("gapless_play_thread", __mmplayer_gapless_play_thread, (gpointer)player, NULL);
4695 if (!player->gapless_play_thread) {
4696 LOGE("failed to create gapless play thread");
4697 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4698 g_mutex_clear(&player->gapless_play_thread_mutex);
4699 g_cond_clear(&player->gapless_play_thread_cond);
4703 player->bus_msg_q = g_queue_new();
4704 if (!player->bus_msg_q) {
4705 LOGE("failed to create queue for bus_msg");
4706 ret = MM_ERROR_PLAYER_RESOURCE_LIMIT;
4710 ret = _mmplayer_initialize_video_capture(player);
4711 if (ret != MM_ERROR_NONE) {
4712 LOGE("failed to initialize video capture");
4716 /* initialize resource manager */
4717 if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
4718 __resource_release_cb, player, &player->resource_manager)
4719 != MM_RESOURCE_MANAGER_ERROR_NONE) {
4720 LOGE("failed to create resource manager");
4721 ret = MM_ERROR_PLAYER_INTERNAL;
4725 /* create video bo lock and cond */
4726 g_mutex_init(&player->video_bo_mutex);
4727 g_cond_init(&player->video_bo_cond);
4729 /* create subtitle info lock and cond */
4730 g_mutex_init(&player->subtitle_info_mutex);
4731 g_cond_init(&player->subtitle_info_cond);
4733 player->streaming_type = STREAMING_SERVICE_NONE;
4735 /* give default value of audio effect setting */
4736 player->sound.volume = MM_VOLUME_FACTOR_DEFAULT;
4737 player->sound.rg_enable = false;
4738 player->playback_rate = DEFAULT_PLAYBACK_RATE;
4740 player->play_subtitle = FALSE;
4741 player->has_closed_caption = FALSE;
4742 player->pending_resume = FALSE;
4743 if (player->ini.dump_element_keyword[0][0] == '\0')
4744 player->ini.set_dump_element_flag = FALSE;
4746 player->ini.set_dump_element_flag = TRUE;
4748 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4749 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4750 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
4752 /* Set video360 settings to their defaults for just-created player.
4755 player->is_360_feature_enabled = FALSE;
4756 if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(FEATURE_NAME_SPHERICAL_VIDEO, &enabled)) {
4757 LOGI("spherical feature info: %d", enabled);
4759 player->is_360_feature_enabled = TRUE;
4761 LOGE("failed to get spherical feature info");
4764 player->is_content_spherical = FALSE;
4765 player->is_video360_enabled = TRUE;
4766 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
4767 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
4768 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
4769 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
4770 player->video360_zoom = 1.0f;
4771 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
4772 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
4774 __mmplayer_initialize_video_roi(player);
4776 /* set player state to null */
4777 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
4778 MMPLAYER_SET_STATE(player, MM_PLAYER_STATE_NULL);
4782 return MM_ERROR_NONE;
4786 g_mutex_clear(&player->fsink_lock);
4787 /* free update tag lock */
4788 g_mutex_clear(&player->update_tag_lock);
4789 g_queue_free(player->bus_msg_q);
4790 player->bus_msg_q = NULL;
4791 /* free gapless play thread */
4792 if (player->gapless_play_thread) {
4793 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4794 player->gapless_play_thread_exit = TRUE;
4795 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4796 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4798 g_thread_join(player->gapless_play_thread);
4799 player->gapless_play_thread = NULL;
4801 g_mutex_clear(&player->gapless_play_thread_mutex);
4802 g_cond_clear(&player->gapless_play_thread_cond);
4805 /* release attributes */
4806 _mmplayer_deconstruct_attribute(handle);
4814 __mmplayer_init_gstreamer(mmplayer_t *player)
4816 static gboolean initialized = FALSE;
4817 static const int max_argc = 50;
4819 gchar **argv = NULL;
4820 gchar **argv2 = NULL;
4826 LOGD("gstreamer already initialized.");
4831 argc = malloc(sizeof(int));
4832 argv = malloc(sizeof(gchar *) * max_argc);
4833 argv2 = malloc(sizeof(gchar *) * max_argc);
4835 if (!argc || !argv || !argv2)
4838 memset(argv, 0, sizeof(gchar *) * max_argc);
4839 memset(argv2, 0, sizeof(gchar *) * max_argc);
4843 argv[0] = g_strdup("mmplayer");
4846 for (i = 0; i < 5; i++) {
4847 /* FIXIT : num of param is now fixed to 5. make it dynamic */
4848 if (strlen(player->ini.gst_param[i]) > 0) {
4849 argv[*argc] = g_strdup(player->ini.gst_param[i]);
4854 /* we would not do fork for scanning plugins */
4855 argv[*argc] = g_strdup("--gst-disable-registry-fork");
4858 /* check disable registry scan */
4859 if (player->ini.skip_rescan) {
4860 argv[*argc] = g_strdup("--gst-disable-registry-update");
4864 /* check disable segtrap */
4865 if (player->ini.disable_segtrap) {
4866 argv[*argc] = g_strdup("--gst-disable-segtrap");
4870 LOGD("initializing gstreamer with following parameter");
4871 LOGD("argc : %d", *argc);
4874 for (i = 0; i < arg_count; i++) {
4876 LOGD("argv[%d] : %s", i, argv2[i]);
4879 /* initializing gstreamer */
4880 if (!gst_init_check(argc, &argv, &err)) {
4881 LOGE("Could not initialize GStreamer: %s", err ? err->message : "unknown error occurred");
4888 for (i = 0; i < arg_count; i++) {
4890 LOGD("release - argv[%d] : %s", i, argv2[i]);
4892 MMPLAYER_FREEIF(argv2[i]);
4895 MMPLAYER_FREEIF(argv);
4896 MMPLAYER_FREEIF(argv2);
4897 MMPLAYER_FREEIF(argc);
4907 for (i = 0; i < arg_count; i++) {
4908 LOGD("free[%d] : %s", i, argv2[i]);
4909 MMPLAYER_FREEIF(argv2[i]);
4912 MMPLAYER_FREEIF(argv);
4913 MMPLAYER_FREEIF(argv2);
4914 MMPLAYER_FREEIF(argc);
4920 __mmplayer_check_async_state_transition(mmplayer_t *player)
4922 GstState element_state = GST_STATE_VOID_PENDING;
4923 GstState element_pending_state = GST_STATE_VOID_PENDING;
4924 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
4925 GstElement *element = NULL;
4926 gboolean async = FALSE;
4928 /* check player handle */
4929 MMPLAYER_RETURN_IF_FAIL(player &&
4931 player->pipeline->mainbin &&
4932 player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
4935 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
4937 if (!MMPLAYER_IS_MS_BUFF_SRC(player) && (async == FALSE)) {
4938 LOGD("don't need to check the pipeline state");
4942 MMPLAYER_PRINT_STATE(player);
4944 /* wait for state transition */
4945 element = player->pipeline->mainbin[MMPLAYER_M_PIPE].gst;
4946 ret = gst_element_get_state(element, &element_state, &element_pending_state, 1 * GST_SECOND);
4948 if (ret == GST_STATE_CHANGE_FAILURE) {
4949 LOGE(" [%s] state : %s pending : %s",
4950 GST_ELEMENT_NAME(element),
4951 gst_element_state_get_name(element_state),
4952 gst_element_state_get_name(element_pending_state));
4954 /* dump state of all element */
4955 _mmplayer_dump_pipeline_state(player);
4960 LOGD("[%s] element state has changed", GST_ELEMENT_NAME(element));
4965 _mmplayer_destroy(MMHandleType handle)
4967 mmplayer_t *player = MM_PLAYER_CAST(handle);
4971 /* check player handle */
4972 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
4974 /* destroy can called at anytime */
4975 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_DESTROY);
4977 /* check async state transition */
4978 __mmplayer_check_async_state_transition(player);
4980 /* release gapless play thread */
4981 if (player->gapless_play_thread) {
4982 MMPLAYER_GAPLESS_PLAY_THREAD_LOCK(player);
4983 player->gapless_play_thread_exit = TRUE;
4984 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
4985 MMPLAYER_GAPLESS_PLAY_THREAD_UNLOCK(player);
4987 LOGD("waiting for gapless play thread exit");
4988 g_thread_join(player->gapless_play_thread);
4989 g_mutex_clear(&player->gapless_play_thread_mutex);
4990 g_cond_clear(&player->gapless_play_thread_cond);
4991 LOGD("gapless play thread released");
4994 _mmplayer_release_video_capture(player);
4996 /* release miscellaneous information */
4997 __mmplayer_release_misc(player);
4999 /* release pipeline */
5000 if (__mmplayer_gst_destroy_pipeline(player) != MM_ERROR_NONE) {
5001 LOGE("failed to destroy pipeline");
5002 return MM_ERROR_PLAYER_INTERNAL;
5005 __mmplayer_destroy_hw_resource(player);
5007 g_queue_free(player->bus_msg_q);
5009 /* release subtitle info lock and cond */
5010 g_mutex_clear(&player->subtitle_info_mutex);
5011 g_cond_clear(&player->subtitle_info_cond);
5013 __mmplayer_release_dump_list(player->dump_list);
5015 /* release miscellaneous information.
5016 these info needs to be released after pipeline is destroyed. */
5017 __mmplayer_release_misc_post(player);
5019 /* release attributes */
5020 _mmplayer_deconstruct_attribute(handle);
5022 if (player->uri_info.uri_list) {
5023 g_list_free_full(player->uri_info.uri_list, (GDestroyNotify)g_free);
5024 player->uri_info.uri_list = NULL;
5028 g_mutex_clear(&player->fsink_lock);
5031 g_mutex_clear(&player->update_tag_lock);
5033 /* release video bo lock and cond */
5034 g_mutex_clear(&player->video_bo_mutex);
5035 g_cond_clear(&player->video_bo_cond);
5039 return MM_ERROR_NONE;
5043 _mmplayer_realize(MMHandleType hplayer)
5045 mmplayer_t *player = (mmplayer_t *)hplayer;
5046 int ret = MM_ERROR_NONE;
5049 MMHandleType attrs = 0;
5053 /* check player handle */
5054 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5056 /* check current state */
5057 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_REALIZE);
5059 attrs = MMPLAYER_GET_ATTRS(player);
5061 LOGE("fail to get attributes.");
5062 return MM_ERROR_PLAYER_INTERNAL;
5064 mm_attrs_get_string_by_name(attrs, "profile_uri", &uri);
5065 mm_attrs_get_data_by_name(attrs, "profile_user_param", ¶m);
5067 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_NONE) {
5068 ret = _mmplayer_parse_profile((const char *)uri, param, &player->profile);
5070 if (ret != MM_ERROR_NONE) {
5071 LOGE("failed to parse profile");
5076 if (uri && (strstr(uri, "es_buff://"))) {
5077 if (strstr(uri, "es_buff://push_mode"))
5078 player->es_player_push_mode = TRUE;
5080 player->es_player_push_mode = FALSE;
5083 if (player->profile.uri_type == MM_PLAYER_URI_TYPE_URL_MMS) {
5084 LOGW("mms protocol is not supported format.");
5085 return MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5088 if (MMPLAYER_IS_STREAMING(player))
5089 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.live_state_change_timeout;
5091 MMPLAYER_STATE_CHANGE_TIMEOUT(player) = player->ini.localplayback_state_change_timeout;
5093 player->smooth_streaming = FALSE;
5094 player->videodec_linked = 0;
5095 player->audiodec_linked = 0;
5096 player->textsink_linked = 0;
5097 player->is_external_subtitle_present = FALSE;
5098 player->is_external_subtitle_added_now = FALSE;
5099 player->is_subtitle_off = FALSE; /* set the subtitle ON default */
5100 player->video360_metadata.is_spherical = -1;
5101 player->is_openal_plugin_used = FALSE;
5102 player->subtitle_language_list = NULL;
5103 player->is_subtitle_force_drop = FALSE;
5105 _mmplayer_track_initialize(player);
5106 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
5108 if ((MMPLAYER_IS_STREAMING(player)) && (player->streamer == NULL)) {
5109 gint prebuffer_ms = 0, rebuffer_ms = 0;
5111 player->streamer = _mm_player_streaming_create();
5112 _mm_player_streaming_initialize(player->streamer, TRUE);
5114 mm_attrs_multiple_get(player->attrs, NULL,
5115 MM_PLAYER_PREBUFFER_MS, &prebuffer_ms,
5116 MM_PLAYER_REBUFFER_MS, &rebuffer_ms, NULL);
5118 if (prebuffer_ms > 0) {
5119 prebuffer_ms = MAX(prebuffer_ms, 1000);
5120 player->streamer->buffering_req.prebuffer_time = prebuffer_ms;
5123 if (rebuffer_ms > 0) {
5124 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5125 rebuffer_ms = MAX(rebuffer_ms, 1000);
5126 player->streamer->buffering_req.rebuffer_time = rebuffer_ms;
5129 LOGD("buffering time %d ms, %d ms", player->streamer->buffering_req.prebuffer_time,
5130 player->streamer->buffering_req.rebuffer_time);
5133 /* realize pipeline */
5134 ret = __mmplayer_gst_realize(player);
5135 if (ret != MM_ERROR_NONE)
5136 LOGE("fail to realize the player.");
5138 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
5146 _mmplayer_unrealize(MMHandleType hplayer)
5148 mmplayer_t *player = (mmplayer_t *)hplayer;
5149 int ret = MM_ERROR_NONE;
5150 int rm_ret = MM_ERROR_NONE;
5151 mmplayer_resource_type_e res_idx = MMPLAYER_RESOURCE_TYPE_MAX;
5155 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5157 MMPLAYER_CMD_UNLOCK(player);
5158 _mmplayer_bus_watcher_remove(player);
5159 /* destroy the gst bus msg thread which is created during realize.
5160 this funct have to be called before getting cmd lock. */
5161 _mmplayer_bus_msg_thread_destroy(player);
5162 MMPLAYER_CMD_LOCK(player);
5164 /* check current state */
5165 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
5167 /* check async state transition */
5168 __mmplayer_check_async_state_transition(player);
5170 /* unrealize pipeline */
5171 ret = __mmplayer_gst_unrealize(player);
5173 for (res_idx = MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER; res_idx < MMPLAYER_RESOURCE_TYPE_MAX; res_idx++) {
5174 rm_ret = __mmplayer_release_hw_resource(player, res_idx);
5175 if (rm_ret != MM_ERROR_NONE)
5176 LOGE("failed to release [%d] resources", res_idx);
5179 player->interrupted_by_resource = FALSE;
5186 _mmplayer_set_message_callback(MMHandleType hplayer, MMMessageCallback callback, gpointer user_param)
5188 mmplayer_t *player = (mmplayer_t *)hplayer;
5190 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5192 return __mmplayer_gst_set_message_callback(player, callback, user_param);
5196 _mmplayer_get_state(MMHandleType hplayer, int *state)
5198 mmplayer_t *player = (mmplayer_t *)hplayer;
5200 MMPLAYER_RETURN_VAL_IF_FAIL(state, MM_ERROR_INVALID_ARGUMENT);
5202 *state = MMPLAYER_CURRENT_STATE(player);
5204 return MM_ERROR_NONE;
5208 __mmplayer_gst_set_volume_property(mmplayer_t *player, const char *prop_name)
5210 GstElement *vol_element = NULL;
5211 enum audio_element_id volume_elem_id = MMPLAYER_A_VOL;
5214 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5215 MMPLAYER_RETURN_VAL_IF_FAIL(prop_name, MM_ERROR_INVALID_ARGUMENT);
5217 /* check pipeline handle */
5218 if (!player->pipeline || !player->pipeline->audiobin) {
5219 LOGD("'%s' will be applied when audiobin is created", prop_name);
5221 /* NOTE : stored value will be used in create_audiobin
5222 * returning MM_ERROR_NONE here makes application to able to
5223 * set audio volume or mute at anytime.
5225 return MM_ERROR_NONE;
5228 if (player->build_audio_offload || g_strrstr(player->ini.audiosink_element, "pulsesink"))
5229 volume_elem_id = MMPLAYER_A_SINK;
5231 vol_element = player->pipeline->audiobin[volume_elem_id].gst;
5233 LOGE("failed to get vol element %d", volume_elem_id);
5234 return MM_ERROR_PLAYER_INTERNAL;
5237 LOGD("set '%s' property to element[%s]", prop_name, GST_ELEMENT_NAME(vol_element));
5239 if (!g_object_class_find_property(G_OBJECT_GET_CLASS(vol_element), prop_name)) {
5240 LOGE("there is no '%s' property", prop_name);
5241 return MM_ERROR_PLAYER_INTERNAL;
5244 if (!strcmp(prop_name, "volume")) {
5245 g_object_set(vol_element, "volume", player->sound.volume, NULL);
5246 } else if (!strcmp(prop_name, "mute")) {
5247 g_object_set(vol_element, "mute", player->sound.mute, NULL);
5249 LOGE("invalid property %s", prop_name);
5250 return MM_ERROR_PLAYER_INTERNAL;
5253 return MM_ERROR_NONE;
5257 _mmplayer_set_volume(MMHandleType hplayer, float volume)
5259 int ret = MM_ERROR_NONE;
5260 mmplayer_t *player = (mmplayer_t *)hplayer;
5263 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5265 LOGD("volume = %f", volume);
5267 /* invalid factor range or not */
5268 if (volume < MM_VOLUME_FACTOR_MIN || volume > MM_VOLUME_FACTOR_MAX) {
5269 LOGE("Invalid volume value");
5270 return MM_ERROR_INVALID_ARGUMENT;
5273 player->sound.volume = volume;
5275 ret = __mmplayer_gst_set_volume_property(player, "volume");
5282 _mmplayer_get_volume(MMHandleType hplayer, float *volume)
5284 mmplayer_t *player = (mmplayer_t *)hplayer;
5288 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5289 MMPLAYER_RETURN_VAL_IF_FAIL(volume, MM_ERROR_INVALID_ARGUMENT);
5291 *volume = player->sound.volume;
5293 LOGD("current vol = %f", *volume);
5296 return MM_ERROR_NONE;
5300 _mmplayer_set_mute(MMHandleType hplayer, bool mute)
5302 int ret = MM_ERROR_NONE;
5303 mmplayer_t *player = (mmplayer_t *)hplayer;
5306 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5308 LOGD("mute = %d", mute);
5310 player->sound.mute = mute;
5312 ret = __mmplayer_gst_set_volume_property(player, "mute");
5319 _mmplayer_get_mute(MMHandleType hplayer, bool *mute)
5321 mmplayer_t *player = (mmplayer_t *)hplayer;
5325 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5326 MMPLAYER_RETURN_VAL_IF_FAIL(mute, MM_ERROR_INVALID_ARGUMENT);
5328 *mute = player->sound.mute;
5330 LOGD("current mute = %d", *mute);
5334 return MM_ERROR_NONE;
5338 _mmplayer_set_audiostream_changed_cb(MMHandleType hplayer, mm_player_stream_changed_callback callback, void *user_param)
5340 mmplayer_t *player = (mmplayer_t *)hplayer;
5344 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5346 player->audio_stream_changed_cb = callback;
5347 player->audio_stream_changed_cb_user_param = user_param;
5348 LOGD("Handle value is %p : %p", player, player->audio_stream_changed_cb);
5352 return MM_ERROR_NONE;
5356 _mmplayer_set_audio_decoded_cb(MMHandleType hplayer, mmplayer_audio_extract_opt_e opt, mm_player_audio_decoded_callback callback, void *user_param)
5358 mmplayer_t *player = (mmplayer_t *)hplayer;
5362 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5364 player->audio_decoded_cb = callback;
5365 player->audio_decoded_cb_user_param = user_param;
5366 player->audio_extract_opt = opt;
5367 LOGD("handle: %p, cb: %p, opt: 0x%X", player, player->audio_decoded_cb, player->audio_extract_opt);
5371 return MM_ERROR_NONE;
5375 _mmplayer_set_video_decoded_cb(MMHandleType hplayer, mm_player_video_decoded_callback callback, void *user_param)
5377 mmplayer_t *player = (mmplayer_t *)hplayer;
5381 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5383 if (callback && !player->bufmgr)
5384 player->bufmgr = tbm_bufmgr_init(-1);
5386 player->set_mode.video_export = (callback) ? true : false;
5387 player->video_decoded_cb = callback;
5388 player->video_decoded_cb_user_param = user_param;
5390 LOGD("Stream cb Handle value is %p : %p, enable:%d", player, player->video_decoded_cb, player->set_mode.video_export);
5394 return MM_ERROR_NONE;
5398 _mmplayer_start(MMHandleType hplayer)
5400 mmplayer_t *player = (mmplayer_t *)hplayer;
5401 gint ret = MM_ERROR_NONE;
5405 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5407 /* check current state */
5408 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_START);
5410 /* start pipeline */
5411 ret = _mmplayer_gst_start(player);
5412 if (ret != MM_ERROR_NONE)
5413 LOGE("failed to start player.");
5415 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5416 LOGD("force playing start even during buffering");
5417 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5425 /* NOTE: post "not supported codec message" to application
5426 * when one codec is not found during AUTOPLUGGING in MSL.
5427 * So, it's separated with error of __mmplayer_gst_bus_msg_callback().
5428 * And, if any codec is not found, don't send message here.
5429 * Because GST_ERROR_MESSAGE is posted by other plugin internally.
5432 __mmplayer_handle_missed_plugin(mmplayer_t *player)
5434 MMMessageParamType msg_param;
5435 memset(&msg_param, 0, sizeof(MMMessageParamType));
5436 gboolean post_msg_direct = FALSE;
5440 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5442 LOGD("not_supported_codec = 0x%02x, can_support_codec = 0x%02x",
5443 player->not_supported_codec, player->can_support_codec);
5445 if (player->not_found_demuxer) {
5446 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5447 msg_param.data = g_strdup_printf("%s", player->unlinked_demuxer_mime);
5449 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5450 MMPLAYER_FREEIF(msg_param.data);
5452 return MM_ERROR_NONE;
5455 if (player->not_supported_codec) {
5456 if (player->can_support_codec) {
5457 // There is one codec to play
5458 post_msg_direct = TRUE;
5460 if (player->pipeline->audiobin) // Some content has only PCM data in container.
5461 post_msg_direct = TRUE;
5464 if (post_msg_direct) {
5465 MMMessageParamType msg_param;
5466 memset(&msg_param, 0, sizeof(MMMessageParamType));
5468 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5469 LOGW("not found AUDIO codec, posting error code to application.");
5471 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5472 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5473 } else if (player->not_supported_codec == MISSING_PLUGIN_VIDEO) {
5474 LOGW("not found VIDEO codec, posting error code to application.");
5476 msg_param.code = MM_ERROR_PLAYER_VIDEO_CODEC_NOT_FOUND;
5477 msg_param.data = g_strdup_printf("%s", player->unlinked_video_mime);
5480 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5482 MMPLAYER_FREEIF(msg_param.data);
5484 return MM_ERROR_NONE;
5486 // no any supported codec case
5487 LOGW("not found any codec, posting error code to application.");
5489 if (player->not_supported_codec == MISSING_PLUGIN_AUDIO) {
5490 msg_param.code = MM_ERROR_PLAYER_AUDIO_CODEC_NOT_FOUND;
5491 msg_param.data = g_strdup_printf("%s", player->unlinked_audio_mime);
5493 msg_param.code = MM_ERROR_PLAYER_CODEC_NOT_FOUND;
5494 msg_param.data = g_strdup_printf("%s, %s", player->unlinked_video_mime, player->unlinked_audio_mime);
5497 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5499 MMPLAYER_FREEIF(msg_param.data);
5505 return MM_ERROR_NONE;
5508 static void __mmplayer_check_pipeline_reconfigure_state(mmplayer_t *player)
5510 GstState element_state = GST_STATE_VOID_PENDING;
5511 GstState element_pending_state = GST_STATE_VOID_PENDING;
5512 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
5513 gint timeout = MMPLAYER_STATE_CHANGE_TIMEOUT(player);
5515 MMPLAYER_RETURN_IF_FAIL(player && player->pipeline);
5517 MMPLAYER_RECONFIGURE_LOCK(player);
5518 if (!player->gapless.reconfigure) {
5519 MMPLAYER_RECONFIGURE_UNLOCK(player);
5523 LOGI("reconfigure is under process");
5524 MMPLAYER_RECONFIGURE_WAIT(player);
5525 MMPLAYER_RECONFIGURE_UNLOCK(player);
5526 LOGI("reconfigure is completed.");
5528 result = gst_element_get_state(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5529 &element_state, &element_pending_state, timeout * GST_SECOND);
5530 if (result == GST_STATE_CHANGE_FAILURE)
5531 LOGW("failed to get pipeline state in %d sec", timeout);
5536 /* NOTE : it should be able to call 'stop' anytime*/
5538 _mmplayer_stop(MMHandleType hplayer)
5540 mmplayer_t *player = (mmplayer_t *)hplayer;
5541 int ret = MM_ERROR_NONE;
5545 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5547 /* check current state */
5548 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_STOP);
5550 /* need to wait till the rebuilding pipeline is completed */
5551 __mmplayer_check_pipeline_reconfigure_state(player);
5552 MMPLAYER_RECONFIGURE_LOCK(player);
5553 __mmplayer_reset_gapless_state(player);
5554 MMPLAYER_RECONFIGURE_UNLOCK(player);
5556 /* NOTE : application should not wait for EOS after calling STOP */
5557 _mmplayer_cancel_eos_timer(player);
5560 player->seek_state = MMPLAYER_SEEK_NONE;
5563 ret = _mmplayer_gst_stop(player);
5565 if (ret != MM_ERROR_NONE)
5566 LOGE("failed to stop player.");
5574 _mmplayer_pause(MMHandleType hplayer)
5576 mmplayer_t *player = (mmplayer_t *)hplayer;
5577 gint64 pos_nsec = 0;
5578 gboolean async = FALSE;
5579 gint ret = MM_ERROR_NONE;
5583 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5585 /* check current state */
5586 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_PAUSE);
5588 /* check pipeline reconfigure state */
5589 __mmplayer_check_pipeline_reconfigure_state(player);
5591 switch (MMPLAYER_CURRENT_STATE(player)) {
5592 case MM_PLAYER_STATE_READY:
5594 /* check prepare async or not.
5595 * In the case of streaming playback, it's recommended to avoid blocking wait.
5597 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
5598 LOGD("prepare working mode : %s", (async ? "async" : "sync"));
5600 /* Changing back sync of rtspsrc to async */
5601 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
5602 LOGD("async prepare working mode for rtsp");
5608 case MM_PLAYER_STATE_PLAYING:
5610 /* NOTE : store current point to overcome some bad operation
5611 *(returning zero when getting current position in paused state) of some
5614 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec))
5615 LOGW("getting current position failed in paused");
5617 player->last_position = pos_nsec;
5619 /* For rtspsrc stack , npt-start value coming from server is used for finding the current position.
5620 But when a rtsp clip (especially from Youtube Desktop View) is paused and kept for sometime,npt-start is still increasing.
5621 This causes problem is position calculation during normal pause resume scenarios also.
5622 Currently during pause , we are sending the current position to rtspsrc module for position saving. */
5623 if ((MMPLAYER_IS_RTSP_STREAMING(player)) &&
5624 (_mmplayer_get_stream_service_type(player) == STREAMING_SERVICE_VOD)) {
5625 g_object_set(player->pipeline->mainbin[MMPLAYER_M_SRC].gst, "resume-position", player->last_position, NULL);
5631 if (MMPLAYER_IS_MS_BUFF_SRC(player)) {
5632 LOGD("doing async pause in case of ms buff src");
5636 /* pause pipeline */
5637 ret = _mmplayer_gst_pause(player, async);
5638 if (ret != MM_ERROR_NONE) {
5639 LOGE("failed to pause player. ret : 0x%x", ret);
5640 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-pause-err");
5644 if (MMPLAYER_PREV_STATE(player) == MM_PLAYER_STATE_READY && MMPLAYER_CURRENT_STATE(player) == MM_PLAYER_STATE_PAUSED) {
5645 if (_mmplayer_update_video_overlay_param(player, "display_rotation") != MM_ERROR_NONE)
5646 LOGE("failed to update display_rotation");
5650 return MM_ERROR_NONE;
5653 /* in case of streaming, pause could take long time.*/
5655 _mmplayer_abort_pause(MMHandleType hplayer)
5657 mmplayer_t *player = (mmplayer_t *)hplayer;
5658 int ret = MM_ERROR_NONE;
5662 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
5664 player->pipeline->mainbin,
5665 MM_ERROR_PLAYER_NOT_INITIALIZED);
5667 LOGD("set the pipeline state to READY");
5669 /* set state to READY */
5670 ret = _mmplayer_gst_set_state(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5671 GST_STATE_READY, FALSE, MMPLAYER_STATE_CHANGE_TIMEOUT(player));
5672 if (ret != MM_ERROR_NONE) {
5673 LOGE("fail to change state to READY");
5674 return MM_ERROR_PLAYER_INTERNAL;
5677 LOGD("succeeded in changing state to READY");
5682 _mmplayer_resume(MMHandleType hplayer)
5684 mmplayer_t *player = (mmplayer_t *)hplayer;
5685 int ret = MM_ERROR_NONE;
5686 gboolean async = FALSE;
5690 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5692 if ((MMPLAYER_IS_RTSP_STREAMING(player))) {
5693 if (player->is_external_subtitle_added_now) { /* after setting external subtitle, seeking and buffering is in progress. */
5694 player->pending_resume = TRUE; /* will be resumed after finishing the buffering. */
5698 /* Changing back sync mode rtspsrc to async */
5699 LOGD("async resume for rtsp case");
5703 /* check current state */
5704 MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_RESUME);
5706 ret = _mmplayer_gst_resume(player, async);
5707 if (ret != MM_ERROR_NONE)
5708 LOGE("failed to resume player.");
5710 if ((player->streamer) && (player->streamer->buffering_state & MM_PLAYER_BUFFERING_IN_PROGRESS)) {
5711 LOGD("force resume even during buffering");
5712 player->streamer->buffering_state = MM_PLAYER_BUFFERING_ABORT;
5721 _mmplayer_set_playspeed(MMHandleType hplayer, float rate, bool streaming)
5723 mmplayer_t *player = (mmplayer_t *)hplayer;
5724 gint64 pos_nsec = 0;
5725 int ret = MM_ERROR_NONE;
5727 signed long long start = 0, stop = 0;
5728 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
5731 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
5732 MMPLAYER_RETURN_VAL_IF_FAIL(streaming || !MMPLAYER_IS_STREAMING(player), MM_ERROR_NOT_SUPPORT_API);
5734 /* The sound of video is not supported under 0.0 and over 2.0. */
5735 if (rate >= TRICK_PLAY_MUTE_THRESHOLD_MAX || rate < TRICK_PLAY_MUTE_THRESHOLD_MIN) {
5736 if (player->can_support_codec & FOUND_PLUGIN_VIDEO)
5739 _mmplayer_set_mute(hplayer, mute);
5741 if (player->playback_rate == rate)
5742 return MM_ERROR_NONE;
5744 /* If the position is reached at start potion during fast backward, EOS is posted.
5745 * So, This EOS have to be classified with it which is posted at reaching the end of stream.
5747 player->playback_rate = rate;
5749 current_state = MMPLAYER_CURRENT_STATE(player);
5751 if (current_state != MM_PLAYER_STATE_PAUSED)
5752 ret = gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &pos_nsec);
5754 LOGD("pos_msec = %"GST_TIME_FORMAT" and ret = %d and state = %d", GST_TIME_ARGS(pos_nsec), ret, current_state);
5756 if ((current_state == MM_PLAYER_STATE_PAUSED)
5757 || (!ret) /*|| (player->last_position != 0 && pos_msec == 0)*/) {
5758 LOGW("returning last point : %"G_GINT64_FORMAT, player->last_position);
5759 pos_nsec = player->last_position;
5764 stop = GST_CLOCK_TIME_NONE;
5766 start = GST_CLOCK_TIME_NONE;
5770 if (!_mmplayer_gst_seek(player, player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
5771 player->playback_rate,
5773 (GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE),
5774 GST_SEEK_TYPE_SET, start,
5775 GST_SEEK_TYPE_SET, stop)) {
5776 LOGE("failed to set speed playback");
5777 return MM_ERROR_PLAYER_SEEK;
5780 LOGD("succeeded to set speed playback as %0.1f", rate);
5784 return MM_ERROR_NONE;;
5788 _mmplayer_set_position(MMHandleType hplayer, gint64 position)
5790 mmplayer_t *player = (mmplayer_t *)hplayer;
5791 int ret = MM_ERROR_NONE;
5795 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5797 /* check pipeline reconfigure state */
5798 __mmplayer_check_pipeline_reconfigure_state(player);
5800 ret = _mmplayer_gst_set_position(player, position, FALSE);
5808 _mmplayer_get_duration(MMHandleType hplayer, gint64 *duration)
5810 mmplayer_t *player = (mmplayer_t *)hplayer;
5811 int ret = MM_ERROR_NONE;
5813 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5814 MMPLAYER_RETURN_VAL_IF_FAIL(duration, MM_ERROR_COMMON_INVALID_ARGUMENT);
5816 if (g_strrstr(player->type, "video/mpegts"))
5817 __mmplayer_update_duration_value(player);
5819 *duration = player->duration;
5824 _mmplayer_get_buffer_position(MMHandleType hplayer, int *start_pos, int *end_pos)
5826 mmplayer_t *player = (mmplayer_t *)hplayer;
5827 int ret = MM_ERROR_NONE;
5829 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5831 ret = _mmplayer_gst_get_buffer_position(player, start_pos, end_pos);
5837 _mmplayer_adjust_subtitle_position(MMHandleType hplayer, int position)
5839 mmplayer_t *player = (mmplayer_t *)hplayer;
5840 int ret = MM_ERROR_NONE;
5844 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
5846 ret = __mmplayer_gst_adjust_subtitle_position(player, position);
5854 __mmplayer_is_midi_type(gchar *str_caps)
5856 if ((g_strrstr(str_caps, "audio/midi")) ||
5857 (g_strrstr(str_caps, "application/x-gst_ff-mmf")) ||
5858 (g_strrstr(str_caps, "application/x-smaf")) ||
5859 (g_strrstr(str_caps, "audio/x-imelody")) ||
5860 (g_strrstr(str_caps, "audio/mobile-xmf")) ||
5861 (g_strrstr(str_caps, "audio/xmf")) ||
5862 (g_strrstr(str_caps, "audio/mxmf"))) {
5871 __mmplayer_is_only_mp3_type(gchar *str_caps)
5873 if (g_strrstr(str_caps, "application/x-id3") ||
5874 (g_strrstr(str_caps, "audio/mpeg") && g_strrstr(str_caps, "mpegversion=(int)1")))
5880 _mmplayer_set_audio_attrs(mmplayer_t *player, GstCaps *caps)
5882 GstStructure *caps_structure = NULL;
5883 gint samplerate = 0;
5887 MMPLAYER_RETURN_IF_FAIL(player && caps);
5889 caps_structure = gst_caps_get_structure(caps, 0);
5891 /* set stream information */
5892 gst_structure_get_int(caps_structure, "rate", &samplerate);
5893 gst_structure_get_int(caps_structure, "channels", &channels);
5895 mm_player_set_attribute((MMHandleType)player, NULL,
5896 "content_audio_samplerate", samplerate,
5897 "content_audio_channels", channels, NULL);
5899 LOGD("audio samplerate : %d channels : %d", samplerate, channels);
5903 __mmplayer_update_content_type_info(mmplayer_t *player)
5906 MMPLAYER_RETURN_IF_FAIL(player && player->type);
5908 if (__mmplayer_is_midi_type(player->type)) {
5909 player->bypass_audio_effect = TRUE;
5913 if (!player->streamer) {
5914 LOGD("no need to check streaming type");
5918 if (g_strrstr(player->type, "application/x-hls")) {
5919 /* If it can't know exact type when it parses uri because of redirection case,
5920 * it will be fixed by typefinder or when doing autoplugging.
5922 player->profile.uri_type = MM_PLAYER_URI_TYPE_HLS;
5923 player->streamer->is_adaptive_streaming = TRUE;
5924 } else if (g_strrstr(player->type, "application/dash+xml")) {
5925 player->profile.uri_type = MM_PLAYER_URI_TYPE_DASH;
5926 player->streamer->is_adaptive_streaming = TRUE;
5929 /* in case of TS, fixed buffering mode should be used because player can not get exact duration time */
5930 if ((player->streamer->is_adaptive_streaming) || (g_strrstr(player->type, "video/mpegts"))) {
5931 player->streamer->buffering_req.mode = MM_PLAYER_BUFFERING_MODE_FIXED;
5933 if (player->streamer->buffering_req.rebuffer_time <= MIN_BUFFERING_TIME) { /* if user did not set the rebuffer value */
5934 if (player->streamer->is_adaptive_streaming)
5935 player->streamer->buffering_req.rebuffer_time = DEFAULT_ADAPTIVE_REBUFFER_TIME;
5937 player->streamer->buffering_req.rebuffer_time = DEFAULT_REBUFFERING_TIME;
5941 LOGD("uri type : %d, %d", player->profile.uri_type, player->streamer->buffering_req.rebuffer_time);
5946 _mmplayer_typefind_have_type(GstElement *tf, guint probability,
5947 GstCaps *caps, gpointer data)
5949 mmplayer_t *player = (mmplayer_t *)data;
5953 MMPLAYER_RETURN_IF_FAIL(player && tf && caps);
5955 /* store type string */
5956 if (player->type_caps) {
5957 gst_caps_unref(player->type_caps);
5958 player->type_caps = NULL;
5961 player->type_caps = gst_caps_copy(caps);
5962 MMPLAYER_LOG_GST_CAPS_TYPE(player->type_caps);
5964 MMPLAYER_FREEIF(player->type);
5965 player->type = gst_caps_to_string(caps);
5967 LOGD("[handle: %p] media type %s found, probability %d%% / %d",
5968 player, player->type, probability, gst_caps_get_size(caps));
5970 if ((!MMPLAYER_IS_RTSP_STREAMING(player)) &&
5971 (g_strrstr(player->type, "audio/x-raw-int"))) {
5972 LOGE("not support media format");
5974 if (player->msg_posted == FALSE) {
5975 MMMessageParamType msg_param;
5976 memset(&msg_param, 0, sizeof(MMMessageParamType));
5978 msg_param.code = MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT;
5979 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
5981 /* don't post more if one was sent already */
5982 player->msg_posted = TRUE;
5987 __mmplayer_update_content_type_info(player);
5989 if (!player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst) {
5992 pad = gst_element_get_static_pad(tf, "src");
5994 LOGE("fail to get typefind src pad.");
5998 if (!_mmplayer_gst_create_decoder(player, pad, caps)) {
5999 gboolean async = FALSE;
6000 LOGE("failed to autoplug %s", player->type);
6002 mm_attrs_get_int_by_name(player->attrs, "profile_prepare_async", &async);
6004 if (async && player->msg_posted == FALSE)
6005 __mmplayer_handle_missed_plugin(player);
6007 gst_object_unref(GST_OBJECT(pad));
6014 _mmplayer_gst_make_decodebin(mmplayer_t *player)
6016 GstElement *decodebin = NULL;
6020 /* create decodebin */
6021 decodebin = gst_element_factory_make("decodebin", NULL);
6024 LOGE("fail to create decodebin");
6028 /* raw pad handling signal */
6029 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-added",
6030 G_CALLBACK(_mmplayer_gst_decode_pad_added), (gpointer)player);
6032 /* no-more-pad pad handling signal */
6033 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "no-more-pads",
6034 G_CALLBACK(_mmplayer_gst_decode_no_more_pads), (gpointer)player);
6036 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "pad-removed",
6037 G_CALLBACK(_mmplayer_gst_decode_pad_removed), (gpointer)player);
6039 /* This signal is emitted when a pad for which there is no further possible
6040 decoding is added to the decodebin.*/
6041 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "unknown-type",
6042 G_CALLBACK(_mmplayer_gst_decode_unknown_type), (gpointer)player);
6044 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6045 before looking for any elements that can handle that stream.*/
6046 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-continue",
6047 G_CALLBACK(_mmplayer_gst_decode_autoplug_continue), (gpointer)player);
6049 if (player->need_video_dec_sorting || player->need_audio_dec_sorting)
6050 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-sort",
6051 G_CALLBACK(_mmplayer_gst_decode_autoplug_sort), (gpointer)player);
6053 /* This signal is emitted whenever decodebin finds a new stream. It is emitted
6054 before looking for any elements that can handle that stream.*/
6055 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "autoplug-select",
6056 G_CALLBACK(_mmplayer_gst_decode_autoplug_select), (gpointer)player);
6058 /* This signal is emitted once decodebin has finished decoding all the data.*/
6059 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "drained",
6060 G_CALLBACK(_mmplayer_gst_decode_drained), (gpointer)player);
6062 /* This signal is emitted when a element is added to the bin.*/
6063 _mmplayer_add_signal_connection(player, G_OBJECT(decodebin), MM_PLAYER_SIGNAL_TYPE_AUTOPLUG, "element-added",
6064 G_CALLBACK(_mmplayer_gst_element_added), (gpointer)player);
6071 __mmplayer_gst_make_queue2(mmplayer_t *player)
6073 GstElement *queue2 = NULL;
6074 gint64 dur_bytes = 0L;
6075 mmplayer_gst_element_t *mainbin = NULL;
6076 muxed_buffer_type_e type = MUXED_BUFFER_TYPE_MEM_QUEUE;
6079 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, NULL);
6081 mainbin = player->pipeline->mainbin;
6083 queue2 = gst_element_factory_make("queue2", "queue2");
6085 LOGE("failed to create buffering queue element");
6089 if (!gst_element_query_duration(mainbin[MMPLAYER_M_SRC].gst, GST_FORMAT_BYTES, &dur_bytes))
6090 LOGW("failed to get duration from source %s", GST_ELEMENT_NAME(mainbin[MMPLAYER_M_SRC].gst));
6092 LOGD("dur_bytes = %"G_GINT64_FORMAT, dur_bytes);
6094 /* NOTE : in case of ts streaming, player could not get the correct duration info *
6095 * skip the pull mode(file or ring buffering) setting. */
6096 if (dur_bytes > 0) {
6097 if (!g_strrstr(player->type, "video/mpegts")) {
6098 type = MUXED_BUFFER_TYPE_MEM_RING_BUFFER;
6099 player->streamer->ring_buffer_size = player->ini.http_ring_buffer_size;
6105 _mm_player_streaming_set_queue2(player->streamer,
6109 (guint64)dur_bytes); /* no meaning at the moment */
6115 _mmplayer_gst_create_decoder(mmplayer_t *player, GstPad *srcpad, const GstCaps *caps)
6117 mmplayer_gst_element_t *mainbin = NULL;
6118 GstElement *decodebin = NULL;
6119 GstElement *queue2 = NULL;
6120 GstPad *sinkpad = NULL;
6121 GstPad *qsrcpad = NULL;
6124 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin, FALSE);
6126 mainbin = player->pipeline->mainbin;
6128 if (MMPLAYER_IS_HTTP_STREAMING(player)) {
6130 if (mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst) {
6131 LOGW("need to check: muxed buffer is not null");
6134 queue2 = __mmplayer_gst_make_queue2(player);
6136 LOGE("failed to make queue2");
6140 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2)) {
6141 LOGE("failed to add buffering queue");
6145 sinkpad = gst_element_get_static_pad(queue2, "sink");
6146 qsrcpad = gst_element_get_static_pad(queue2, "src");
6148 if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
6149 LOGE("failed to link [%s:%s]-[%s:%s]",
6150 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6154 if (gst_element_sync_state_with_parent(queue2) == GST_STATE_CHANGE_FAILURE) {
6155 LOGE("failed to sync queue2 state with parent");
6159 mainbin[MMPLAYER_M_MUXED_S_BUFFER].id = MMPLAYER_M_MUXED_S_BUFFER;
6160 mainbin[MMPLAYER_M_MUXED_S_BUFFER].gst = queue2;
6164 gst_object_unref(GST_OBJECT(sinkpad));
6168 /* create decodebin */
6169 decodebin = _mmplayer_gst_make_decodebin(player);
6171 LOGE("failed to make decodebin");
6175 if (!gst_bin_add(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin)) {
6176 LOGE("failed to add decodebin");
6180 /* to force caps on the decodebin element and avoid reparsing stuff by
6181 * typefind. It also avoids a deadlock in the way typefind activates pads in
6182 * the state change */
6183 g_object_set(decodebin, "sink-caps", caps, NULL);
6185 sinkpad = gst_element_get_static_pad(decodebin, "sink");
6187 if (GST_PAD_LINK_OK != gst_pad_link(srcpad, sinkpad)) {
6188 LOGE("failed to link [%s:%s]-[%s:%s]",
6189 GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6193 gst_object_unref(GST_OBJECT(sinkpad));
6195 gst_object_unref(GST_OBJECT(qsrcpad));
6198 mainbin[MMPLAYER_M_AUTOPLUG].id = MMPLAYER_M_AUTOPLUG;
6199 mainbin[MMPLAYER_M_AUTOPLUG].gst = decodebin;
6201 /* set decodebin property about buffer in streaming playback. *
6202 * in case of HLS/DASH, it does not need to have big buffer *
6203 * because it is kind of adaptive streaming. */
6204 if (MMPLAYER_IS_HTTP_STREAMING(player) || MMPLAYER_IS_HTTP_LIVE_STREAMING(player) || MMPLAYER_IS_DASH_STREAMING(player)) {
6205 gint init_buffering_time = DEFAULT_PREBUFFERING_TIME;
6206 gint high_percent = 0;
6208 if (player->streamer->buffering_req.prebuffer_time > MIN_BUFFERING_TIME)
6209 init_buffering_time = player->streamer->buffering_req.prebuffer_time;
6211 high_percent = (gint)ceil((gdouble)(init_buffering_time * 100) / MAX_BUFFER_SIZE_TIME);
6213 LOGD("buffering time %d, per: 1~%d", init_buffering_time, high_percent);
6215 g_object_set(G_OBJECT(decodebin), "use-buffering", TRUE,
6216 "high-percent", high_percent,
6217 "max-size-bytes", MAX_BUFFER_SIZE_BYTES,
6218 "max-size-time", (guint64)(MAX_BUFFER_SIZE_TIME * GST_MSECOND),
6219 "max-size-buffers", 0, NULL); // disable or automatic
6222 if (gst_element_sync_state_with_parent(decodebin) == GST_STATE_CHANGE_FAILURE) {
6223 LOGE("failed to sync decodebin state with parent");
6234 gst_object_unref(GST_OBJECT(sinkpad));
6237 gst_object_unref(GST_OBJECT(qsrcpad));
6240 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6241 * You need to explicitly set elements to the NULL state before
6242 * dropping the final reference, to allow them to clean up.
6244 gst_element_set_state(queue2, GST_STATE_NULL);
6246 /* And, it still has a parent "player".
6247 * You need to let the parent manage the object instead of unreffing the object directly.
6249 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), queue2);
6250 gst_object_unref(queue2);
6255 /* NOTE : Trying to dispose element queue0, but it is in READY instead of the NULL state.
6256 * You need to explicitly set elements to the NULL state before
6257 * dropping the final reference, to allow them to clean up.
6259 gst_element_set_state(decodebin, GST_STATE_NULL);
6261 /* And, it still has a parent "player".
6262 * You need to let the parent manage the object instead of unreffing the object directly.
6265 gst_bin_remove(GST_BIN(mainbin[MMPLAYER_M_PIPE].gst), decodebin);
6266 gst_object_unref(decodebin);
6274 __mmplayer_check_not_supported_codec(mmplayer_t *player, const gchar *factory_class, const gchar *mime)
6278 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline, MM_ERROR_PLAYER_NOT_INITIALIZED);
6279 MMPLAYER_RETURN_VAL_IF_FAIL(mime, MM_ERROR_INVALID_ARGUMENT);
6281 LOGD("class : %s, mime : %s", factory_class, mime);
6283 /* add missing plugin */
6284 /* NOTE : msl should check missing plugin for image mime type.
6285 * Some motion jpeg clips can have playable audio track.
6286 * So, msl have to play audio after displaying popup written video format not supported.
6288 if (!(player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst)) {
6289 if (!(player->can_support_codec | player->videodec_linked | player->audiodec_linked)) {
6290 LOGD("not found demuxer");
6291 player->not_found_demuxer = TRUE;
6292 player->unlinked_demuxer_mime = g_strdup_printf("%s", mime);
6298 if (!g_strrstr(factory_class, "Demuxer")) {
6299 if ((g_str_has_prefix(mime, "video")) || (g_str_has_prefix(mime, "image"))) {
6300 LOGD("can support codec=0x%X, vdec_linked=%d, adec_linked=%d",
6301 player->can_support_codec, player->videodec_linked, player->audiodec_linked);
6303 /* check that clip have multi tracks or not */
6304 if ((player->can_support_codec & FOUND_PLUGIN_VIDEO) && (player->videodec_linked)) {
6305 LOGD("video plugin is already linked");
6307 LOGW("add VIDEO to missing plugin");
6308 player->not_supported_codec |= MISSING_PLUGIN_VIDEO;
6309 player->unlinked_video_mime = g_strdup_printf("%s", mime);
6311 } else if (g_str_has_prefix(mime, "audio")) {
6312 if ((player->can_support_codec & FOUND_PLUGIN_AUDIO) && (player->audiodec_linked)) {
6313 LOGD("audio plugin is already linked");
6315 LOGW("add AUDIO to missing plugin");
6316 player->not_supported_codec |= MISSING_PLUGIN_AUDIO;
6317 player->unlinked_audio_mime = g_strdup_printf("%s", mime);
6325 return MM_ERROR_NONE;
6329 _mmplayer_pipeline_complete(GstElement *decodebin, gpointer data)
6331 mmplayer_t *player = (mmplayer_t *)data;
6335 MMPLAYER_RETURN_IF_FAIL(player);
6337 /* remove fakesink. */
6338 if (!_mmplayer_gst_remove_fakesink(player,
6339 &player->pipeline->mainbin[MMPLAYER_M_SRC_FAKESINK])) {
6340 /* NOTE : _mmplayer_pipeline_complete() can be called several time. because
6341 * signaling mechanism(pad-added, no-more-pad, new-decoded-pad) from various
6342 * source element are not same. To overcome this situation, this function will called
6343 * several places and several times. Therefore, this is not an error case.
6348 LOGD("[handle: %p] pipeline has completely constructed", player);
6350 if ((player->msg_posted == FALSE) &&
6351 (player->cmd >= MMPLAYER_COMMAND_START))
6352 __mmplayer_handle_missed_plugin(player);
6354 MMPLAYER_GENERATE_DOT_IF_ENABLED(player, "pipeline-status-complete");
6358 __mmplayer_check_profile(void)
6361 static int profile_tv = -1;
6363 if (__builtin_expect(profile_tv != -1, 1))
6366 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
6367 switch (*profileName) {
6382 __mmplayer_get_next_uri(mmplayer_t *player)
6384 mmplayer_parse_profile_t profile;
6386 guint num_of_list = 0;
6389 num_of_list = g_list_length(player->uri_info.uri_list);
6390 uri_idx = player->uri_info.uri_idx;
6392 LOGD("num of uri list = %d, current uri idx %d", num_of_list, uri_idx);
6393 for (uri_idx++; uri_idx < num_of_list; uri_idx++) {
6394 uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6396 LOGW("next uri does not exist");
6400 if (_mmplayer_parse_profile((const char *)uri, NULL, &profile) != MM_ERROR_NONE) {
6401 LOGE("failed to parse profile");
6405 if ((profile.uri_type != MM_PLAYER_URI_TYPE_FILE) &&
6406 (profile.uri_type != MM_PLAYER_URI_TYPE_URL_HTTP)) {
6407 LOGW("uri type is not supported(%d)", profile.uri_type);
6411 LOGD("success to find next uri %d", uri_idx);
6415 if (!uri || uri_idx == num_of_list) {
6416 LOGE("failed to find next uri");
6420 player->uri_info.uri_idx = uri_idx;
6421 if (mm_player_set_attribute((MMHandleType)player, NULL,
6422 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6423 LOGE("failed to set attribute");
6427 SECURE_LOGD("next playback uri: %s", uri);
6432 __mmplayer_verify_gapless_play_path(mmplayer_t *player)
6434 #define REPEAT_COUNT_INFINITE -1
6435 #define REPEAT_COUNT_MIN 2
6436 #define ORIGINAL_URI_ONLY 1
6438 MMHandleType attrs = 0;
6442 guint num_of_uri = 0;
6443 int profile_tv = -1;
6447 LOGD("checking for gapless play option");
6449 if (player->build_audio_offload) {
6450 LOGE("offload path is not supportable.");
6454 if (player->pipeline->textbin) {
6455 LOGE("subtitle path is enabled. gapless play is not supported.");
6459 attrs = MMPLAYER_GET_ATTRS(player);
6461 LOGE("fail to get attributes.");
6465 mm_attrs_multiple_get(player->attrs, NULL,
6466 "content_video_found", &video,
6467 "profile_play_count", &count,
6468 MM_PLAYER_GAPLESS_MODE, &gapless, NULL);
6470 /* gapless playback is not supported in case of video at TV profile. */
6471 profile_tv = __mmplayer_check_profile();
6472 if (profile_tv && video) {
6473 LOGW("not support video gapless playback");
6477 /* check repeat count in case of audio */
6479 (video || (count != REPEAT_COUNT_INFINITE && count < REPEAT_COUNT_MIN))) {
6480 LOGW("gapless is disabled");
6484 num_of_uri = g_list_length(player->uri_info.uri_list);
6486 LOGD("repeat count = %d, num_of_list = %d", count, num_of_uri);
6488 if (num_of_uri == ORIGINAL_URI_ONLY) {
6489 /* audio looping path */
6490 if (count >= REPEAT_COUNT_MIN) {
6491 /* decrease play count */
6492 /* we succeeded to rewind. update play count and then wait for next EOS */
6494 mm_player_set_attribute((MMHandleType)player, NULL, "profile_play_count", count, NULL);
6495 } else if (count != REPEAT_COUNT_INFINITE) {
6496 LOGD("there is no next uri and no repeat");
6499 LOGD("looping cnt %d", count);
6501 /* gapless playback path */
6502 if (!__mmplayer_get_next_uri(player)) {
6503 LOGE("failed to get next uri");
6510 LOGE("unable to play gapless path. EOS will be posted soon");
6515 __mmplayer_remove_sinkpad (const GValue *item, gpointer user_data)
6517 GstPad *sinkpad = g_value_get_object (item);
6518 GstElement *element = GST_ELEMENT(user_data);
6519 if (!sinkpad || !element) {
6520 LOGE("invalid parameter");
6524 LOGD("(%s)element release request pad(%s)", GST_ELEMENT_NAME(element), GST_PAD_NAME(sinkpad));
6525 gst_element_release_request_pad(element, GST_PAD(sinkpad));
6529 __mmplayer_deactivate_combiner(mmplayer_t *player, mmplayer_track_type_e type)
6531 mmplayer_gst_element_t *sinkbin = NULL;
6532 main_element_id_e concatId = MMPLAYER_M_NUM;
6533 main_element_id_e sinkId = MMPLAYER_M_NUM;
6534 gboolean send_notice = FALSE;
6535 GstElement *element;
6539 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6541 LOGD("type %d", type);
6544 case MM_PLAYER_TRACK_TYPE_AUDIO:
6545 concatId = MMPLAYER_M_A_CONCAT;
6546 sinkId = MMPLAYER_A_BIN;
6547 sinkbin = player->pipeline->audiobin;
6549 case MM_PLAYER_TRACK_TYPE_VIDEO:
6550 concatId = MMPLAYER_M_V_CONCAT;
6551 sinkId = MMPLAYER_V_BIN;
6552 sinkbin = player->pipeline->videobin;
6555 case MM_PLAYER_TRACK_TYPE_TEXT:
6556 concatId = MMPLAYER_M_T_CONCAT;
6557 sinkId = MMPLAYER_T_BIN;
6558 sinkbin = player->pipeline->textbin;
6561 LOGE("requested type is not supportable");
6566 element = player->pipeline->mainbin[concatId].gst;
6570 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6571 GstPad *srcpad = gst_element_get_static_pad(element, "src");
6572 GstPad *sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6573 if (srcpad && sinkpad) {
6574 /* after getting drained signal there is no data flows, so no need to do pad_block */
6575 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6576 gst_pad_unlink(srcpad, sinkpad);
6578 /* send custom event to sink pad to handle it at video sink */
6580 LOGD("send custom event to sinkpad");
6581 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6582 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6583 gst_pad_send_event(sinkpad, event);
6586 gst_object_unref(srcpad);
6587 gst_object_unref(sinkpad);
6590 LOGD("release concat request pad");
6591 /* release and unref requests pad from the selector */
6592 iter = gst_element_iterate_sink_pads(element);
6593 while (gst_iterator_foreach(iter, __mmplayer_remove_sinkpad, element) == GST_ITERATOR_RESYNC)
6594 gst_iterator_resync(iter);
6595 gst_iterator_free(iter);
6601 __mmplayer_deactivate_selector(mmplayer_t *player, mmplayer_track_type_e type)
6603 mmplayer_track_t *selector = &player->track[type];
6604 mmplayer_gst_element_t *sinkbin = NULL;
6605 main_element_id_e selectorId = MMPLAYER_M_NUM;
6606 main_element_id_e sinkId = MMPLAYER_M_NUM;
6607 GstPad *srcpad = NULL;
6608 GstPad *sinkpad = NULL;
6609 gboolean send_notice = FALSE;
6612 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
6614 LOGD("type %d", type);
6617 case MM_PLAYER_TRACK_TYPE_AUDIO:
6618 selectorId = MMPLAYER_M_A_INPUT_SELECTOR;
6619 sinkId = MMPLAYER_A_BIN;
6620 sinkbin = player->pipeline->audiobin;
6622 case MM_PLAYER_TRACK_TYPE_VIDEO:
6623 selectorId = MMPLAYER_M_V_INPUT_SELECTOR;
6624 sinkId = MMPLAYER_V_BIN;
6625 sinkbin = player->pipeline->videobin;
6628 case MM_PLAYER_TRACK_TYPE_TEXT:
6629 selectorId = MMPLAYER_M_T_INPUT_SELECTOR;
6630 sinkId = MMPLAYER_T_BIN;
6631 sinkbin = player->pipeline->textbin;
6634 LOGE("requested type is not supportable");
6639 if (player->pipeline->mainbin[selectorId].gst) {
6642 srcpad = gst_element_get_static_pad(player->pipeline->mainbin[selectorId].gst, "src");
6644 if (selector->event_probe_id != 0)
6645 gst_pad_remove_probe(srcpad, selector->event_probe_id);
6646 selector->event_probe_id = 0;
6648 if ((sinkbin) && (sinkbin[sinkId].gst)) {
6649 sinkpad = gst_element_get_static_pad(sinkbin[sinkId].gst, "sink");
6651 if (srcpad && sinkpad) {
6652 /* after getting drained signal there is no data flows, so no need to do pad_block */
6653 LOGD("unlink %s:%s, %s:%s", GST_DEBUG_PAD_NAME(srcpad), GST_DEBUG_PAD_NAME(sinkpad));
6654 gst_pad_unlink(srcpad, sinkpad);
6656 /* send custom event to sink pad to handle it at video sink */
6658 LOGD("send custom event to sinkpad");
6659 GstStructure *s = gst_structure_new_empty("tizen/flush-buffer");
6660 GstEvent *event = gst_event_new_custom(GST_EVENT_CUSTOM_DOWNSTREAM, s);
6661 gst_pad_send_event(sinkpad, event);
6665 gst_object_unref(sinkpad);
6668 gst_object_unref(srcpad);
6671 LOGD("selector release");
6673 /* release and unref requests pad from the selector */
6674 for (n = 0; n < selector->streams->len; n++) {
6675 GstPad *sinkpad = g_ptr_array_index(selector->streams, n);
6676 gst_element_release_request_pad((player->pipeline->mainbin[selectorId].gst), sinkpad);
6679 g_ptr_array_set_size(selector->streams, 0);
6681 gst_element_set_state(player->pipeline->mainbin[selectorId].gst, GST_STATE_NULL);
6682 gst_bin_remove(GST_BIN_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst), player->pipeline->mainbin[selectorId].gst);
6684 player->pipeline->mainbin[selectorId].gst = NULL;
6692 __mmplayer_deactivate_old_path(mmplayer_t *player)
6695 MMPLAYER_RETURN_IF_FAIL(player);
6697 if (MMPLAYER_USE_DECODEBIN(player)) {
6698 if ((!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6699 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6700 (!__mmplayer_deactivate_selector(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6701 LOGE("deactivate selector error");
6705 if ((!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_AUDIO)) ||
6706 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_VIDEO)) ||
6707 (!__mmplayer_deactivate_combiner(player, MM_PLAYER_TRACK_TYPE_TEXT))) {
6708 LOGE("deactivate concat error");
6713 _mmplayer_track_destroy(player);
6714 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
6716 if (player->streamer) {
6717 _mm_player_streaming_initialize(player->streamer, FALSE);
6718 _mm_player_streaming_destroy(player->streamer);
6719 player->streamer = NULL;
6722 MMPLAYER_GAPLESS_PLAY_THREAD_SIGNAL(player);
6728 if (!player->msg_posted) {
6729 MMMessageParamType msg = {0,};
6732 msg.code = MM_ERROR_PLAYER_INTERNAL;
6733 LOGE("gapless_uri_play> deactivate error");
6735 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg);
6736 player->msg_posted = TRUE;
6742 _mmplayer_set_uri(MMHandleType hplayer, const char *uri)
6744 int result = MM_ERROR_NONE;
6745 mmplayer_t *player = (mmplayer_t *)hplayer;
6748 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6749 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6751 if (mm_player_set_attribute(hplayer, NULL,
6752 "profile_uri", uri, strlen(uri), NULL) != MM_ERROR_NONE) {
6753 LOGE("failed to set attribute");
6754 result = MM_ERROR_PLAYER_INTERNAL;
6756 if (_mmplayer_set_next_uri(hplayer, uri, TRUE) != MM_ERROR_NONE)
6757 LOGE("failed to add the original uri in the uri list.");
6765 _mmplayer_set_next_uri(MMHandleType hplayer, const char *uri, bool is_first_path)
6767 mmplayer_t *player = (mmplayer_t *)hplayer;
6768 guint num_of_list = 0;
6772 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6773 MMPLAYER_RETURN_VAL_IF_FAIL(uri, MM_ERROR_INVALID_ARGUMENT);
6775 if (player->pipeline && player->pipeline->textbin) {
6776 LOGE("subtitle path is enabled.");
6777 return MM_ERROR_PLAYER_INVALID_STATE;
6780 num_of_list = g_list_length(player->uri_info.uri_list);
6782 if (is_first_path) {
6783 if (num_of_list == 0) {
6784 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6785 SECURE_LOGD("add original path : %s", uri);
6787 g_free(g_list_nth_data(player->uri_info.uri_list, 0));
6788 player->uri_info.uri_list = g_list_prepend(
6789 g_list_delete_link(player->uri_info.uri_list, player->uri_info.uri_list), g_strdup(uri));
6790 SECURE_LOGD("change original path : %s", uri);
6793 MMHandleType attrs = 0;
6794 attrs = MMPLAYER_GET_ATTRS(player);
6796 if (num_of_list == 0) {
6797 char *original_uri = NULL;
6800 mm_attrs_get_string_by_name(attrs, "profile_uri", &original_uri);
6802 if (!original_uri) {
6803 LOGE("there is no original uri.");
6804 return MM_ERROR_PLAYER_INVALID_STATE;
6807 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(original_uri));
6808 player->uri_info.uri_idx = 0;
6810 SECURE_LOGD("add original path at first : %s", original_uri);
6814 player->uri_info.uri_list = g_list_append(player->uri_info.uri_list, g_strdup(uri));
6815 SECURE_LOGD("add new path : %s(total num of list = %d)", uri, g_list_length(player->uri_info.uri_list));
6819 return MM_ERROR_NONE;
6823 _mmplayer_get_next_uri(MMHandleType hplayer, char **uri)
6825 mmplayer_t *player = (mmplayer_t *)hplayer;
6826 char *next_uri = NULL;
6827 guint num_of_list = 0;
6830 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
6832 num_of_list = g_list_length(player->uri_info.uri_list);
6834 if (num_of_list > 0) {
6835 gint uri_idx = player->uri_info.uri_idx;
6837 if (uri_idx < num_of_list - 1)
6842 next_uri = g_list_nth_data(player->uri_info.uri_list, uri_idx);
6843 LOGE("next uri idx : %d, uri = %s", uri_idx, next_uri);
6845 *uri = g_strdup(next_uri);
6849 return MM_ERROR_NONE;
6853 _mmplayer_gst_decode_unknown_type(GstElement *elem, GstPad *pad,
6854 GstCaps *caps, gpointer data)
6856 mmplayer_t *player = (mmplayer_t *)data;
6857 const gchar *klass = NULL;
6858 const gchar *mime = NULL;
6859 gchar *caps_str = NULL;
6861 klass = gst_element_factory_get_metadata(gst_element_get_factory(elem), GST_ELEMENT_METADATA_KLASS);
6862 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6863 caps_str = gst_caps_to_string(caps);
6865 LOGW("unknown type of caps : %s from %s",
6866 caps_str, GST_ELEMENT_NAME(elem));
6868 MMPLAYER_FREEIF(caps_str);
6870 /* There is no available codec. */
6871 __mmplayer_check_not_supported_codec(player, klass, mime);
6875 _mmplayer_gst_decode_autoplug_continue(GstElement *bin, GstPad *pad,
6876 GstCaps *caps, gpointer data)
6878 mmplayer_t *player = (mmplayer_t *)data;
6879 const char *mime = NULL;
6880 gboolean ret = TRUE;
6882 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
6883 mime = gst_structure_get_name(gst_caps_get_structure(caps, 0));
6885 if (g_str_has_prefix(mime, "audio")) {
6886 GstStructure *caps_structure = NULL;
6887 gint samplerate = 0;
6889 gchar *caps_str = NULL;
6891 caps_structure = gst_caps_get_structure(caps, 0);
6892 gst_structure_get_int(caps_structure, "rate", &samplerate);
6893 gst_structure_get_int(caps_structure, "channels", &channels);
6895 if ((channels > 0 && samplerate == 0)) {
6896 LOGD("exclude audio...");
6900 caps_str = gst_caps_to_string(caps);
6901 /* set it directly because not sent by TAG */
6902 if (g_strrstr(caps_str, "mobile-xmf"))
6903 mm_player_set_attribute((MMHandleType)player, NULL,
6904 "content_audio_codec", "mobile-xmf", strlen("mobile-xmf"), NULL);
6906 MMPLAYER_FREEIF(caps_str);
6907 } else if (g_str_has_prefix(mime, "video") && player->videodec_linked) {
6908 LOGD("already video linked");
6911 LOGD("found new stream");
6918 __mmplayer_is_audio_offload_device_type(mmplayer_t *player)
6920 gboolean ret = FALSE;
6921 GDBusConnection *conn = NULL;
6923 GVariant *result = NULL;
6924 const gchar *dbus_device_type = NULL;
6925 const gchar *dbus_ret = NULL;
6928 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
6930 LOGE("failed g_bus_get_sync() (%s)", (err ? err->message : "null"));
6935 result = g_dbus_connection_call_sync(conn,
6936 "org.pulseaudio.Server",
6937 "/org/pulseaudio/StreamManager",
6938 "org.pulseaudio.StreamManager",
6939 "GetCurrentMediaRoutingPath",
6940 g_variant_new("(s)", "out"),
6941 G_VARIANT_TYPE("(ss)"),
6942 G_DBUS_CALL_FLAGS_NONE,
6946 if (!result || err) {
6947 LOGE("failed g_dbus_connection_call_sync() (%s)", (err ? err->message : "null"));
6952 /* device type is listed in stream-map.json at mmfw-sysconf */
6953 g_variant_get(result, "(&s&s)", &dbus_device_type, &dbus_ret);
6955 LOGI("g_dbus_connection_call_sync() success (%s, %s)", dbus_device_type, dbus_ret);
6956 if (strncmp("STREAM_MANAGER_RETURN_OK", dbus_ret, strlen(dbus_ret)))
6959 /* the device type is listed in ini file among audio-jack, bt-a2dp, usb-audio, builtin-speaker */
6960 for (idx = 0; player->ini.audio_offload_device_type[idx][0] != '\0'; idx++) {
6961 if (strstr(dbus_device_type, player->ini.audio_offload_device_type[idx])) {
6962 LOGD("audio offload is supportable");
6968 LOGD("audio offload is not supportable");
6971 g_variant_unref(result);
6973 g_object_unref(conn);
6978 static void __mmplayer_rebuild_audio_pipeline(mmplayer_t *player)
6980 mmplayer_state_e current_state = MM_PLAYER_STATE_NONE;
6981 gint64 position = 0;
6983 MMPLAYER_RETURN_IF_FAIL(player && player->attrs &&
6984 player->pipeline && player->pipeline->mainbin);
6986 MMPLAYER_CMD_LOCK(player);
6987 current_state = MMPLAYER_CURRENT_STATE(player);
6989 if (!gst_element_query_position(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &position))
6990 LOGW("getting current position failed in paused");
6992 _mmplayer_unrealize((MMHandleType)player);
6993 _mmplayer_realize((MMHandleType)player);
6995 _mmplayer_set_position((MMHandleType)player, position);
6997 /* async not to be blocked in streaming case */
6998 mm_player_set_attribute((MMHandleType)player, NULL, "profile_prepare_async", TRUE, NULL);
7000 _mmplayer_pause((MMHandleType)player);
7002 if (current_state == MM_PLAYER_STATE_PLAYING)
7003 _mmplayer_start((MMHandleType)player);
7004 MMPLAYER_CMD_UNLOCK(player);
7006 LOGD("rebuilding audio pipeline is completed.");
7009 void __mmplayer_audio_device_connected_cb(MMSoundDevice_t device_h, bool is_connected, void *user_data)
7011 mmplayer_t *player = (mmplayer_t *)user_data;
7012 mm_sound_device_type_e dev_type = MM_SOUND_DEVICE_TYPE_BUILTIN_SPEAKER;
7013 gboolean is_supportable = FALSE;
7015 if (mm_sound_get_device_type(device_h, &dev_type) != MM_ERROR_NONE)
7016 LOGW("failed to get device type");
7018 LOGD("dev type (%d), connected (%d)", dev_type, is_connected);
7020 if ((dev_type != MM_SOUND_DEVICE_TYPE_BLUETOOTH_A2DP) &&
7021 (dev_type != MM_SOUND_DEVICE_TYPE_AUDIOJACK) &&
7022 (dev_type != MM_SOUND_DEVICE_TYPE_USB_AUDIO)) {
7023 LOGD("ignore this dev connected info");
7027 is_supportable = __mmplayer_is_audio_offload_device_type(player);
7028 if (player->build_audio_offload == is_supportable) {
7029 LOGD("keep current pipeline without re-building");
7033 /* rebuild pipeline */
7034 LOGD("re-build pipeline - offload: %d", is_supportable);
7035 player->build_audio_offload = FALSE;
7036 __mmplayer_rebuild_audio_pipeline(player);
7042 __mmplayer_add_audio_device_connected_cb(mmplayer_t *player)
7044 unsigned int id = 0;
7046 if (player->audio_device_cb_id != 0) {
7047 LOGW("audio device connected cb was already added (%u)", player->audio_device_cb_id);
7051 if (mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_IO_DIRECTION_OUT_FLAG,
7052 __mmplayer_audio_device_connected_cb, player, &id) == MM_ERROR_NONE) {
7053 LOGD("added device connected cb (%u)", id);
7054 player->audio_device_cb_id = id;
7056 LOGW("failed to add device connected cb");
7063 int _mmplayer_audio_offload_is_activated(MMHandleType hplayer, bool *activated)
7065 mmplayer_t *player = (mmplayer_t *)hplayer;
7068 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
7069 MMPLAYER_RETURN_VAL_IF_FAIL(activated, MM_ERROR_INVALID_ARGUMENT);
7071 *activated = player->build_audio_offload;
7073 LOGD("offload activated : %d", (int)*activated);
7076 return MM_ERROR_NONE;
7080 __mmplayer_is_offload_supported_type(mmplayer_t *player)
7083 this function need to be updated according to the supported media format
7084 @see player->ini.audio_offload_media_format */
7086 if (__mmplayer_is_only_mp3_type(player->type)) {
7087 LOGD("offload supportable media format type");
7095 __mmplayer_can_build_audio_offload_path(mmplayer_t *player)
7097 gboolean ret = FALSE;
7098 GstElementFactory *factory = NULL;
7101 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->attrs, FALSE);
7103 LOGD("current stream : %s, sink: %s", player->type, player->ini.audio_offload_sink_element);
7104 if (!__mmplayer_is_offload_supported_type(player))
7107 if (!strcmp(player->ini.audio_offload_sink_element, "")) {
7108 LOGD("there is no audio offload sink");
7112 if (player->ini.audio_offload_device_type[0][0] == '\0') {
7113 LOGW("there is no audio device type to support offload");
7117 factory = gst_element_factory_find(player->ini.audio_offload_sink_element);
7119 LOGW("there is no installed audio offload sink element");
7122 gst_object_unref(factory);
7124 if (_mmplayer_acquire_hw_resource(player,
7125 MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD) != MM_ERROR_NONE) {
7126 LOGE("failed to acquire audio offload decoder resource");
7130 if (!__mmplayer_add_audio_device_connected_cb(player))
7133 if (!__mmplayer_is_audio_offload_device_type(player))
7136 LOGD("audio offload can be built");
7141 __mmplayer_release_hw_resource(player, MMPLAYER_RESOURCE_TYPE_AUDIO_OFFLOAD);
7147 static GstAutoplugSelectResult
7148 __mmplayer_check_codec_info(mmplayer_t *player, const char *klass, GstCaps *caps, char *factory_name)
7150 GstAutoplugSelectResult ret = GST_AUTOPLUG_SELECT_TRY;
7151 int audio_offload = 0;
7153 if ((g_strrstr(klass, "Codec/Decoder/Audio"))) {
7154 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_OFFLOAD, &audio_offload); /* user requirement */
7156 if (audio_offload && __mmplayer_can_build_audio_offload_path(player)) {
7157 LOGD("expose audio path to build offload output path");
7158 player->build_audio_offload = TRUE;
7159 /* update codec info */
7160 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7161 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7162 player->audiodec_linked = 1;
7164 ret = GST_AUTOPLUG_SELECT_EXPOSE;
7168 /* FIXME: If HW audio decoder is selected, related resource have to be acquired here.
7169 And need to consider the multi-track audio content.
7170 There is no HW audio decoder in public. */
7172 /* set stream information */
7173 if (!player->audiodec_linked)
7174 _mmplayer_set_audio_attrs(player, caps);
7176 /* update codec info */
7177 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7178 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7179 player->audiodec_linked = 1;
7181 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7183 if ((strlen(player->ini.videocodec_element_hw) > 0) &&
7184 (g_strrstr(factory_name, player->ini.videocodec_element_hw))) {
7186 /* mark video decoder for acquire */
7187 if (player->hw_resource[MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER] != NULL) {
7188 LOGW("video decoder resource is already acquired, skip it.");
7189 ret = GST_AUTOPLUG_SELECT_SKIP;
7193 if (_mmplayer_acquire_hw_resource(player, MMPLAYER_RESOURCE_TYPE_VIDEO_DECODER) != MM_ERROR_NONE) {
7194 LOGE("failed to acquire video decoder resource");
7195 ret = GST_AUTOPLUG_SELECT_SKIP;
7198 player->interrupted_by_resource = FALSE;
7201 /* update codec info */
7202 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7203 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7204 player->videodec_linked = 1;
7212 _mmplayer_gst_decode_autoplug_sort(GstElement *bin,
7213 GstPad *pad, GstCaps *caps, GValueArray *factories, gpointer data)
7215 #define DEFAULT_IDX 0xFFFF
7216 #define MIN_FACTORY_NUM 2
7217 mmplayer_t *player = (mmplayer_t *)data;
7218 GValueArray *new_factories = NULL;
7219 GValue val = { 0, };
7220 GstElementFactory *factory = NULL;
7221 const gchar *klass = NULL;
7222 gchar *factory_name = NULL;
7223 guint hw_dec_idx = DEFAULT_IDX;
7224 guint first_sw_dec_idx = DEFAULT_IDX;
7225 guint last_sw_dec_idx = DEFAULT_IDX;
7226 guint new_pos = DEFAULT_IDX;
7227 guint rm_pos = DEFAULT_IDX;
7228 int audio_codec_type;
7229 int video_codec_type;
7230 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
7232 if (factories->n_values < MIN_FACTORY_NUM)
7235 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_VIDEO_CODEC_TYPE, &video_codec_type);
7236 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, &audio_codec_type);
7239 LOGD("num of factory : %d, codec type %d, %d", factories->n_values, video_codec_type, audio_codec_type);
7241 for (int i = 0 ; i < factories->n_values ; i++) {
7242 gchar *hw_dec_info = NULL;
7243 gchar (*sw_dec_info)[PLAYER_INI_MAX_STRLEN] = {NULL, };
7245 factory = g_value_get_object(g_value_array_get_nth(factories, i));
7247 LOGW("failed to get factory object");
7250 klass = gst_element_factory_get_klass(factory);
7251 factory_name = GST_OBJECT_NAME(factory);
7254 LOGD("Klass [%s] Factory [%s]", klass, factory_name);
7256 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7257 if (!player->need_audio_dec_sorting) {
7258 LOGD("sorting is not required");
7261 codec_type = audio_codec_type;
7262 hw_dec_info = player->ini.audiocodec_element_hw;
7263 sw_dec_info = player->ini.audiocodec_element_sw;
7264 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7265 if (!player->need_video_dec_sorting) {
7266 LOGD("sorting is not required");
7269 codec_type = video_codec_type;
7270 hw_dec_info = player->ini.videocodec_element_hw;
7271 sw_dec_info = player->ini.videocodec_element_sw;
7276 if (g_strrstr(factory_name, hw_dec_info)) {
7279 for (int j = 0; sw_dec_info[j][0] != '\0'; j++) {
7280 if (strstr(factory_name, sw_dec_info[j])) {
7281 last_sw_dec_idx = i;
7282 if (first_sw_dec_idx == DEFAULT_IDX) {
7283 first_sw_dec_idx = i;
7288 if (first_sw_dec_idx == DEFAULT_IDX)
7289 LOGW("unknown codec %s", factory_name);
7293 if (hw_dec_idx == DEFAULT_IDX || first_sw_dec_idx == DEFAULT_IDX)
7296 if (codec_type == MM_PLAYER_CODEC_TYPE_HW) {
7297 if (hw_dec_idx < first_sw_dec_idx)
7299 new_pos = first_sw_dec_idx;
7300 rm_pos = hw_dec_idx + 1;
7301 } else if (codec_type == MM_PLAYER_CODEC_TYPE_SW) {
7302 if (last_sw_dec_idx < hw_dec_idx)
7304 new_pos = last_sw_dec_idx + 1;
7305 rm_pos = hw_dec_idx;
7310 /* change position - insert H/W decoder according to the new position */
7311 factory = g_value_get_object(g_value_array_get_nth(factories, hw_dec_idx));
7313 LOGW("failed to get factory object");
7316 new_factories = g_value_array_copy(factories);
7317 g_value_init (&val, G_TYPE_OBJECT);
7318 g_value_set_object (&val, factory);
7319 g_value_array_insert(new_factories, new_pos, &val);
7320 g_value_unset (&val);
7321 g_value_array_remove(new_factories, rm_pos); /* remove previous H/W element */
7323 for (int i = 0 ; i < new_factories->n_values ; i++) {
7324 factory = g_value_get_object(g_value_array_get_nth(new_factories, i));
7326 LOGD("[Re-arranged] Klass [%s] Factory [%s]",
7327 gst_element_factory_get_klass(factory), GST_OBJECT_NAME (factory));
7329 LOGE("[Re-arranged] failed to get factory object");
7332 return new_factories;
7336 _mmplayer_gst_decode_autoplug_select(GstElement *bin, GstPad *pad,
7337 GstCaps *caps, GstElementFactory *factory, gpointer data)
7339 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
7340 mmplayer_t *player = (mmplayer_t *)data;
7342 gchar *factory_name = NULL;
7343 gchar *caps_str = NULL;
7344 const gchar *klass = NULL;
7347 factory_name = GST_OBJECT_NAME(factory);
7348 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
7349 caps_str = gst_caps_to_string(caps);
7351 LOGD("[handle: %p] found new element [%s] to link", player, factory_name);
7353 /* store type string */
7354 if (player->type == NULL) {
7355 player->type = gst_caps_to_string(caps);
7356 __mmplayer_update_content_type_info(player);
7359 /* filtering exclude keyword */
7360 for (idx = 0; player->ini.exclude_element_keyword[idx][0] != '\0'; idx++) {
7361 if (strstr(factory_name, player->ini.exclude_element_keyword[idx])) {
7362 LOGW("skipping [%s] by exclude keyword [%s]",
7363 factory_name, player->ini.exclude_element_keyword[idx]);
7365 result = GST_AUTOPLUG_SELECT_SKIP;
7370 for (idx = 0; player->ini.unsupported_codec_keyword[idx][0] != '\0'; idx++) {
7371 if (caps_str && strstr(caps_str, player->ini.unsupported_codec_keyword[idx])) {
7372 LOGW("skipping [%s] by unsupported codec keyword [%s]",
7373 factory_name, player->ini.unsupported_codec_keyword[idx]);
7374 result = GST_AUTOPLUG_SELECT_SKIP;
7379 /* exclude webm format */
7380 /* NOTE : MSL have to post MM_ERROR_PLAYER_NOT_SUPPORTED_FORMAT
7381 * because webm format is not supportable.
7382 * If webm is disabled in "autoplug-continue", there is no state change
7383 * failure or error because the decodebin will expose the pad directly.
7384 * It make MSL invoke _prepare_async_callback.
7385 * So, we need to disable webm format in "autoplug-select" */
7386 if (caps_str && strstr(caps_str, "webm")) {
7387 LOGW("webm is not supported");
7388 result = GST_AUTOPLUG_SELECT_SKIP;
7392 /* check factory class for filtering */
7393 /* NOTE : msl don't need to use image plugins.
7394 * So, those plugins should be skipped for error handling.
7396 if (g_strrstr(klass, "Codec/Decoder/Image")) {
7397 LOGD("skipping [%s] by not required", factory_name);
7398 result = GST_AUTOPLUG_SELECT_SKIP;
7402 if ((MMPLAYER_IS_MS_BUFF_SRC(player)) &&
7403 (g_strrstr(klass, "Codec/Demuxer") || (g_strrstr(klass, "Codec/Parser")))) {
7404 // TO CHECK : subtitle if needed, add subparse exception.
7405 LOGD("skipping parser/demuxer [%s] in es player by not required", factory_name);
7406 result = GST_AUTOPLUG_SELECT_SKIP;
7410 if (g_strrstr(factory_name, "mpegpsdemux")) {
7411 LOGD("skipping PS container - not support");
7412 result = GST_AUTOPLUG_SELECT_SKIP;
7416 if (g_strrstr(factory_name, "mssdemux"))
7417 player->smooth_streaming = TRUE;
7419 if ((g_strrstr(klass, "Codec/Parser/Converter/Video")) ||
7420 (g_strrstr(klass, "Codec/Decoder/Video"))) {
7423 GstStructure *str = NULL;
7424 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &stype);
7426 /* don't make video because of not required */
7427 if ((stype == MM_DISPLAY_SURFACE_NULL) &&
7428 (!player->set_mode.video_export)) {
7429 LOGD("no need video decoding, expose pad");
7430 result = GST_AUTOPLUG_SELECT_EXPOSE;
7434 /* get w/h for omx state-tune */
7435 /* FIXME: deprecated? */
7436 str = gst_caps_get_structure(caps, 0);
7437 gst_structure_get_int(str, "width", &width);
7440 if (player->v_stream_caps) {
7441 gst_caps_unref(player->v_stream_caps);
7442 player->v_stream_caps = NULL;
7445 player->v_stream_caps = gst_caps_copy(caps);
7446 LOGD("take caps for video state tune");
7447 MMPLAYER_LOG_GST_CAPS_TYPE(player->v_stream_caps);
7451 if (g_strrstr(klass, "Codec/Decoder")) {
7452 result = __mmplayer_check_codec_info(player, klass, caps, factory_name);
7453 if (result != GST_AUTOPLUG_SELECT_TRY) {
7454 LOGW("skip add decoder");
7460 MMPLAYER_FREEIF(caps_str);
7466 _mmplayer_gst_decode_pad_removed(GstElement *elem, GstPad *new_pad,
7469 //mmplayer_t *player = (mmplayer_t *)data;
7470 GstCaps *caps = NULL;
7472 LOGD("[Decodebin2] pad-removed signal");
7474 caps = gst_pad_query_caps(new_pad, NULL);
7476 LOGW("query caps is NULL");
7480 gchar *caps_str = NULL;
7481 caps_str = gst_caps_to_string(caps);
7483 LOGD("pad removed caps : %s from %s", caps_str, GST_ELEMENT_NAME(elem));
7485 MMPLAYER_FREEIF(caps_str);
7486 gst_caps_unref(caps);
7490 _mmplayer_gst_about_to_finish(GstElement *bin, gpointer data)
7492 mmplayer_t *player = (mmplayer_t *)data;
7495 MMPLAYER_RETURN_IF_FAIL(player);
7497 LOGD("got about to finish signal");
7499 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7500 LOGW("Fail to get cmd lock");
7504 if (!__mmplayer_verify_gapless_play_path(player)) {
7505 LOGD("decoding is finished.");
7506 MMPLAYER_CMD_UNLOCK(player);
7510 _mmplayer_set_reconfigure_state(player, TRUE);
7511 MMPLAYER_CMD_UNLOCK(player);
7513 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL);
7514 __mmplayer_deactivate_old_path(player);
7520 _mmplayer_gst_decode_drained(GstElement *bin, gpointer data)
7522 mmplayer_t *player = (mmplayer_t *)data;
7523 GstIterator *iter = NULL;
7524 GValue item = { 0, };
7526 gboolean done = FALSE;
7527 gboolean is_all_drained = TRUE;
7530 MMPLAYER_RETURN_IF_FAIL(player);
7532 LOGD("got drained signal");
7534 if (!MMPLAYER_CMD_TRYLOCK(player)) {
7535 LOGW("Fail to get cmd lock");
7539 if (!__mmplayer_verify_gapless_play_path(player)) {
7540 LOGD("decoding is finished.");
7541 MMPLAYER_CMD_UNLOCK(player);
7545 _mmplayer_set_reconfigure_state(player, TRUE);
7546 MMPLAYER_CMD_UNLOCK(player);
7548 /* check decodebin src pads whether they received EOS or not */
7549 iter = gst_element_iterate_src_pads(player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7552 switch (gst_iterator_next(iter, &item)) {
7553 case GST_ITERATOR_OK:
7554 pad = g_value_get_object(&item);
7555 if (pad && !GST_PAD_IS_EOS(pad)) {
7556 LOGW("[%s:%s] not received EOS yet.", GST_DEBUG_PAD_NAME(pad));
7557 is_all_drained = FALSE;
7560 g_value_reset(&item);
7562 case GST_ITERATOR_RESYNC:
7563 gst_iterator_resync(iter);
7565 case GST_ITERATOR_ERROR:
7566 case GST_ITERATOR_DONE:
7571 g_value_unset(&item);
7572 gst_iterator_free(iter);
7574 if (!is_all_drained) {
7575 LOGD("Wait util the all pads get EOS.");
7580 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_AUDIO] = FALSE;
7581 player->gapless.update_segment[MM_PLAYER_TRACK_TYPE_VIDEO] = FALSE;
7583 /* deactivate pipeline except sinkbins to set up the new pipeline of next uri*/
7584 MMPLAYER_POST_MSG(player, MM_MESSAGE_GAPLESS_CONSTRUCTION, NULL); /* post message for gapless */
7585 __mmplayer_deactivate_old_path(player);
7591 _mmplayer_gst_element_added(GstElement *bin, GstElement *element, gpointer data)
7593 mmplayer_t *player = (mmplayer_t *)data;
7594 const gchar *klass = NULL;
7595 gchar *factory_name = NULL;
7597 klass = gst_element_factory_get_metadata(gst_element_get_factory(element), GST_ELEMENT_METADATA_KLASS);
7598 factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
7600 LOGD("new elem klass: %s, factory_name: %s, new elem name : %s", klass, factory_name, GST_ELEMENT_NAME(element));
7602 if (__mmplayer_add_dump_buffer_probe(player, element))
7603 LOGD("add buffer probe");
7605 if (g_strrstr(klass, "Codec/Decoder/Audio")) {
7606 gchar *selected = NULL;
7607 selected = g_strdup(GST_ELEMENT_NAME(element));
7608 player->audio_decoders = g_list_append(player->audio_decoders, selected);
7610 /* update codec info */
7611 player->not_supported_codec &= MISSING_PLUGIN_VIDEO;
7612 player->can_support_codec |= FOUND_PLUGIN_AUDIO;
7613 player->audiodec_linked = 1;
7614 } else if (g_strrstr(klass, "Codec/Decoder/Video")) {
7615 /* update codec info */
7616 player->not_supported_codec &= MISSING_PLUGIN_AUDIO;
7617 player->can_support_codec |= FOUND_PLUGIN_VIDEO;
7618 player->videodec_linked = 1;
7621 if (g_strrstr(klass, "Demuxer/Adaptive")) {
7622 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].id = MMPLAYER_M_ADAPTIVE_DEMUX;
7623 player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst = element;
7625 LOGD("set max variant limit: %d, %d %d", player->adaptive_info.limit.bandwidth,
7626 player->adaptive_info.limit.width, player->adaptive_info.limit.height);
7628 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
7629 "max-bandwidth", player->adaptive_info.limit.bandwidth,
7630 "max-video-width", player->adaptive_info.limit.width,
7631 "max-video-height", player->adaptive_info.limit.height, NULL);
7633 } else if (g_strrstr(klass, "Demuxer")) {
7635 LOGD("plugged element is demuxer. take it");
7637 player->pipeline->mainbin[MMPLAYER_M_DEMUX].id = MMPLAYER_M_DEMUX;
7638 player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst = element;
7641 if (g_strrstr(factory_name, "asfdemux") || g_strrstr(factory_name, "qtdemux") || g_strrstr(factory_name, "avidemux")) {
7642 int surface_type = 0;
7644 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &surface_type);
7647 // to support trust-zone only
7648 if (g_strrstr(factory_name, "asfdemux")) {
7649 LOGD("set file-location %s", player->profile.uri);
7650 g_object_set(G_OBJECT(element), "file-location", player->profile.uri, NULL);
7651 } else if (g_strrstr(factory_name, "legacyh264parse")) {
7652 LOGD("[%s] output-format to legacyh264parse", "mssdemux");
7653 g_object_set(G_OBJECT(element), "output-format", 1, NULL); /* NALU/Byte Stream format */
7654 } else if (g_strrstr(factory_name, "mpegaudioparse")) {
7655 if ((MMPLAYER_IS_HTTP_STREAMING(player)) &&
7656 (__mmplayer_is_only_mp3_type(player->type))) {
7657 LOGD("[mpegaudioparse] set streaming pull mode.");
7658 g_object_set(G_OBJECT(element), "http-pull-mp3dec", TRUE, NULL);
7660 } else if (g_strrstr(factory_name, player->ini.videocodec_element_hw)) {
7661 player->pipeline->mainbin[MMPLAYER_M_DEC1].gst = element;
7664 if ((player->pipeline->mainbin[MMPLAYER_M_DEMUX].gst) &&
7665 (g_strrstr(GST_ELEMENT_NAME(element), "multiqueue"))) {
7666 LOGD("plugged element is multiqueue. take it %s", GST_ELEMENT_NAME(element));
7668 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].id = MMPLAYER_M_DEMUXED_S_BUFFER;
7669 player->pipeline->mainbin[MMPLAYER_M_DEMUXED_S_BUFFER].gst = element;
7671 if ((MMPLAYER_IS_HTTP_STREAMING(player)) ||
7672 (MMPLAYER_IS_HTTP_LIVE_STREAMING(player)) ||
7673 (MMPLAYER_IS_DASH_STREAMING(player))) {
7674 /* in case of multiqueue, max bytes size is defined with fixed value in mm_player_streaming.h*/
7675 _mm_player_streaming_set_multiqueue(player->streamer, element);
7676 _mm_player_streaming_sync_property(player->streamer, player->pipeline->mainbin[MMPLAYER_M_AUTOPLUG].gst);
7685 __mmplayer_release_misc(mmplayer_t *player)
7688 bool cur_mode = player->set_mode.rich_audio;
7691 MMPLAYER_RETURN_IF_FAIL(player);
7693 player->sent_bos = FALSE;
7694 player->playback_rate = DEFAULT_PLAYBACK_RATE;
7696 player->seek_state = MMPLAYER_SEEK_NONE;
7698 player->total_bitrate = 0;
7699 player->total_maximum_bitrate = 0;
7701 player->not_found_demuxer = 0;
7703 player->last_position = 0;
7704 player->duration = 0;
7705 player->http_content_size = 0;
7706 player->not_supported_codec = MISSING_PLUGIN_NONE;
7707 player->can_support_codec = FOUND_PLUGIN_NONE;
7708 player->pending_seek.is_pending = false;
7709 player->pending_seek.pos = 0;
7710 player->msg_posted = FALSE;
7711 player->has_many_types = FALSE;
7712 player->is_subtitle_force_drop = FALSE;
7713 player->play_subtitle = FALSE;
7714 player->adjust_subtitle_pos = 0;
7715 player->has_closed_caption = FALSE;
7716 player->set_mode.video_export = false;
7717 player->profile.uri_type = MM_PLAYER_URI_TYPE_NONE;
7718 memset(&player->set_mode, 0, sizeof(mmplayer_setting_mode_t));
7720 player->set_mode.rich_audio = cur_mode;
7722 if (player->audio_device_cb_id > 0 &&
7723 mm_sound_remove_device_connected_callback(player->audio_device_cb_id) != MM_ERROR_NONE)
7724 LOGW("failed to remove audio device_connected_callback");
7725 player->audio_device_cb_id = 0;
7727 for (i = 0; i < MM_PLAYER_STREAM_COUNT_MAX; i++) {
7728 player->bitrate[i] = 0;
7729 player->maximum_bitrate[i] = 0;
7732 /* free memory related to audio effect */
7733 MMPLAYER_FREEIF(player->audio_effect_info.custom_ext_level_for_plugin);
7735 if (player->adaptive_info.var_list) {
7736 g_list_free_full(player->adaptive_info.var_list, g_free);
7737 player->adaptive_info.var_list = NULL;
7740 player->adaptive_info.limit.bandwidth = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7741 player->adaptive_info.limit.width = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7742 player->adaptive_info.limit.height = ADAPTIVE_VARIANT_DEFAULT_VALUE;
7744 /* Reset video360 settings to their defaults in case if the pipeline is to be
7747 player->video360_metadata.is_spherical = -1;
7748 player->is_openal_plugin_used = FALSE;
7750 player->is_content_spherical = FALSE;
7751 player->is_video360_enabled = TRUE;
7752 player->video360_metadata.projection_type = VIDEO360_PROJECTION_TYPE_EQUIRECTANGULAR;
7753 player->video360_metadata.stereo_mode = VIDEO360_MODE_MONOSCOPIC;
7754 player->video360_yaw_radians = PLAYER_SPHERICAL_DEFAULT_YAW;
7755 player->video360_pitch_radians = PLAYER_SPHERICAL_DEFAULT_PITCH;
7756 player->video360_zoom = 1.0f;
7757 player->video360_horizontal_fov = PLAYER_SPHERICAL_DEFAULT_H_FOV;
7758 player->video360_vertical_fov = PLAYER_SPHERICAL_DEFAULT_V_FOV;
7760 player->sound.rg_enable = false;
7762 __mmplayer_initialize_video_roi(player);
7767 __mmplayer_release_misc_post(mmplayer_t *player)
7769 gchar *original_uri = NULL;
7772 /* player->pipeline is already released before. */
7773 MMPLAYER_RETURN_IF_FAIL(player);
7775 player->video_decoded_cb = NULL;
7776 player->video_decoded_cb_user_param = NULL;
7777 player->video_stream_prerolled = false;
7779 player->audio_decoded_cb = NULL;
7780 player->audio_decoded_cb_user_param = NULL;
7781 player->audio_extract_opt = MM_PLAYER_AUDIO_EXTRACT_DEFAULT;
7783 player->audio_stream_changed_cb = NULL;
7784 player->audio_stream_changed_cb_user_param = NULL;
7786 mm_player_set_attribute((MMHandleType)player, NULL, "content_video_found", 0, NULL);
7788 /* clean found audio decoders */
7789 if (player->audio_decoders) {
7790 g_list_free_full(player->audio_decoders, (GDestroyNotify)g_free);
7791 player->audio_decoders = NULL;
7794 /* clean the uri list except original uri */
7795 if (player->uri_info.uri_list && g_list_length(player->uri_info.uri_list) > 1) {
7797 original_uri = g_list_nth_data(player->uri_info.uri_list, 0);
7798 tmp = g_list_remove_link(player->uri_info.uri_list, player->uri_info.uri_list);
7799 g_list_free_full(tmp, (GDestroyNotify)g_free);
7802 LOGW("failed to get original uri info");
7804 mm_player_set_attribute((MMHandleType)player, NULL, "profile_uri",
7805 original_uri, (original_uri) ? strlen(original_uri) : (0), NULL);
7806 MMPLAYER_FREEIF(original_uri);
7809 /* clear the audio stream buffer list */
7810 _mmplayer_audio_stream_clear_buffer(player, FALSE);
7812 /* clear the video stream bo list */
7813 __mmplayer_video_stream_destroy_bo_list(player);
7814 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_MAX);
7816 if (player->profile.input_mem.buf) {
7817 free(player->profile.input_mem.buf);
7818 player->profile.input_mem.buf = NULL;
7820 player->profile.input_mem.len = 0;
7821 player->profile.input_mem.offset = 0;
7823 player->uri_info.uri_idx = 0;
7828 __mmplayer_check_subtitle(mmplayer_t *player)
7830 MMHandleType attrs = 0;
7831 char *subtitle_uri = NULL;
7835 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
7837 /* get subtitle attribute */
7838 attrs = MMPLAYER_GET_ATTRS(player);
7842 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
7843 if (!subtitle_uri || !strlen(subtitle_uri))
7846 SECURE_LOGD("subtitle uri is %s[%zu]", subtitle_uri, strlen(subtitle_uri));
7847 player->is_external_subtitle_present = TRUE;
7855 _mmplayer_cancel_eos_timer(mmplayer_t *player)
7857 MMPLAYER_RETURN_IF_FAIL(player);
7859 if (player->eos_timer) {
7860 LOGD("cancel eos timer");
7861 __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
7862 player->eos_timer = 0;
7869 __mmplayer_add_sink(mmplayer_t *player, GstElement *sink, gboolean first)
7873 MMPLAYER_RETURN_IF_FAIL(player);
7874 MMPLAYER_RETURN_IF_FAIL(sink);
7877 player->sink_elements = g_list_prepend(player->sink_elements, sink);
7879 player->sink_elements = g_list_append(player->sink_elements, sink);
7885 __mmplayer_del_sink(mmplayer_t *player, GstElement *sink)
7889 MMPLAYER_RETURN_IF_FAIL(player);
7890 MMPLAYER_RETURN_IF_FAIL(sink);
7892 player->sink_elements = g_list_remove(player->sink_elements, sink);
7898 _mmplayer_add_signal_connection(mmplayer_t *player, GObject *object,
7899 mmplayer_signal_type_e type, const gchar *signal, GCallback cb_funct, gpointer u_data)
7901 mmplayer_signal_item_t *item = NULL;
7904 MMPLAYER_RETURN_IF_FAIL(player);
7906 if (type >= MM_PLAYER_SIGNAL_TYPE_MAX) {
7907 LOGE("invalid signal type [%d]", type);
7911 item = (mmplayer_signal_item_t *)g_try_malloc(sizeof(mmplayer_signal_item_t));
7913 LOGE("cannot connect signal [%s]", signal);
7918 item->sig = g_signal_connect(object, signal, cb_funct, u_data);
7919 player->signals[type] = g_list_append(player->signals[type], item);
7925 /* NOTE : be careful with calling this api. please refer to below glib comment
7926 * glib comment : Note that there is a bug in GObject that makes this function much
7927 * less useful than it might seem otherwise. Once gobject is disposed, the callback
7928 * will no longer be called, but, the signal handler is not currently disconnected.
7929 * If the instance is itself being freed at the same time than this doesn't matter,
7930 * since the signal will automatically be removed, but if instance persists,
7931 * then the signal handler will leak. You should not remove the signal yourself
7932 * because in a future versions of GObject, the handler will automatically be
7935 * It's possible to work around this problem in a way that will continue to work
7936 * with future versions of GObject by checking that the signal handler is still
7937 * connected before disconnected it:
7939 * if (g_signal_handler_is_connected(instance, id))
7940 * g_signal_handler_disconnect(instance, id);
7943 __mmplayer_release_signal_connection(mmplayer_t *player, mmplayer_signal_type_e type)
7945 GList *sig_list = NULL;
7946 mmplayer_signal_item_t *item = NULL;
7950 MMPLAYER_RETURN_IF_FAIL(player);
7952 LOGD("release signals type : %d", type);
7954 if (type >= MM_PLAYER_SIGNAL_TYPE_ALL) {
7955 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUTOPLUG);
7956 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_VIDEOBIN);
7957 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_AUDIOBIN);
7958 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
7959 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_OTHERS);
7963 sig_list = player->signals[type];
7965 for (; sig_list; sig_list = sig_list->next) {
7966 item = sig_list->data;
7968 if (item && item->obj && GST_IS_ELEMENT(item->obj)) {
7969 if (g_signal_handler_is_connected(item->obj, item->sig))
7970 g_signal_handler_disconnect(item->obj, item->sig);
7973 MMPLAYER_FREEIF(item);
7976 g_list_free(player->signals[type]);
7977 player->signals[type] = NULL;
7985 _mmplayer_change_videosink(MMHandleType handle, MMDisplaySurfaceType surface_type, int wl_surface_id)
7987 mmplayer_t *player = 0;
7988 int prev_display_surface_type = 0;
7992 MMPLAYER_RETURN_VAL_IF_FAIL(handle, MM_ERROR_COMMON_INVALID_ARGUMENT);
7994 player = MM_PLAYER_CAST(handle);
7996 /* check video sinkbin is created */
7997 if (_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM)) {
7998 LOGW("Videosink is already created");
7999 return MM_ERROR_NONE;
8002 LOGD("videosink element is not yet ready");
8004 if (surface_type >= MM_DISPLAY_SURFACE_NUM) {
8005 LOGE("Not support this surface type(%d) for changing vidoesink", surface_type);
8007 return MM_ERROR_INVALID_ARGUMENT;
8010 /* load previous attributes */
8011 if (player->attrs) {
8012 mm_attrs_get_int_by_name(player->attrs, "display_surface_type", &prev_display_surface_type);
8013 LOGD("[0: Video surface, 4: EVAS surface] previous surface type(%d), new surface type(%d)", prev_display_surface_type, surface_type);
8014 if (prev_display_surface_type == surface_type) {
8015 LOGD("incoming display surface type is same as previous one, do nothing..");
8017 return MM_ERROR_NONE;
8020 LOGE("failed to load attributes");
8022 return MM_ERROR_PLAYER_INTERNAL;
8025 /* videobin is not created yet, so we just set attributes related to display surface */
8026 LOGD("store display attribute for given surface type(%d)", surface_type);
8027 mm_player_set_attribute(handle, NULL, "display_surface_type", surface_type,
8028 "display_overlay", wl_surface_id, NULL);
8031 return MM_ERROR_NONE;
8034 /* Note : if silent is true, then subtitle would not be displayed. :*/
8036 _mmplayer_set_subtitle_silent(MMHandleType hplayer, int silent)
8038 mmplayer_t *player = (mmplayer_t *)hplayer;
8042 /* check player handle */
8043 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8045 player->set_mode.subtitle_off = silent;
8047 LOGD("subtitle is %s.", player->set_mode.subtitle_off ? "ON" : "OFF");
8051 return MM_ERROR_NONE;
8055 _mmplayer_sync_subtitle_pipeline(mmplayer_t *player)
8057 mmplayer_gst_element_t *mainbin = NULL;
8058 mmplayer_gst_element_t *textbin = NULL;
8059 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8060 GstState current_state = GST_STATE_VOID_PENDING;
8061 GstState element_state = GST_STATE_VOID_PENDING;
8062 GstState element_pending_state = GST_STATE_VOID_PENDING;
8064 GstEvent *event = NULL;
8065 int result = MM_ERROR_NONE;
8067 GstClock *curr_clock = NULL;
8068 GstClockTime base_time, start_time, curr_time;
8073 /* check player handle */
8074 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8076 player->pipeline->mainbin &&
8077 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8079 mainbin = player->pipeline->mainbin;
8080 textbin = player->pipeline->textbin;
8082 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8084 // sync clock with current pipeline
8085 curr_clock = GST_ELEMENT_CLOCK(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst);
8086 curr_time = gst_clock_get_time(curr_clock);
8088 base_time = gst_element_get_base_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8089 start_time = gst_element_get_start_time(GST_ELEMENT_CAST(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
8091 LOGD("state: %d, base_time=%" GST_TIME_FORMAT " start_time=%" GST_TIME_FORMAT " curr_time=%" GST_TIME_FORMAT,
8092 current_state, GST_TIME_ARGS(base_time), GST_TIME_ARGS(start_time), GST_TIME_ARGS(curr_time));
8094 if (current_state > GST_STATE_READY) {
8095 // sync state with current pipeline
8096 gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_PAUSED);
8097 gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_PAUSED);
8098 gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_PAUSED);
8100 ret = gst_element_get_state(mainbin[MMPLAYER_M_SUBSRC].gst, &element_state, &element_pending_state, 5 * GST_SECOND);
8101 if (GST_STATE_CHANGE_FAILURE == ret) {
8102 LOGE("fail to state change.");
8103 result = MM_ERROR_PLAYER_INTERNAL;
8107 gst_element_set_base_time(textbin[MMPLAYER_T_BIN].gst, base_time);
8108 gst_element_set_start_time(textbin[MMPLAYER_T_BIN].gst, start_time);
8111 gst_element_set_clock(textbin[MMPLAYER_T_BIN].gst, curr_clock);
8112 gst_object_unref(curr_clock);
8115 // seek to current position
8116 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8117 result = MM_ERROR_PLAYER_INVALID_STATE;
8118 LOGE("gst_element_query_position failed, invalid state");
8122 LOGD("seek time = %"G_GINT64_FORMAT", rate = %f", time, player->playback_rate);
8123 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);
8125 _mmplayer_gst_send_event_to_sink(player, event);
8127 result = MM_ERROR_PLAYER_INTERNAL;
8128 LOGE("gst_event_new_seek failed"); /* pipeline will got error and can not be recovered */
8132 /* sync state with current pipeline */
8133 gst_element_sync_state_with_parent(textbin[MMPLAYER_T_BIN].gst);
8134 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBPARSE].gst);
8135 gst_element_sync_state_with_parent(mainbin[MMPLAYER_M_SUBSRC].gst);
8137 return MM_ERROR_NONE;
8140 /* release text pipeline resource */
8141 player->textsink_linked = 0;
8143 /* release signal */
8144 __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_TEXTBIN);
8146 /* release textbin with it's children */
8147 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->textbin, MMPLAYER_T_BIN);
8148 MMPLAYER_FREEIF(player->pipeline->textbin);
8149 player->pipeline->textbin = NULL;
8151 /* release subtitle elem */
8152 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBSRC);
8153 MMPLAYER_RELEASE_ELEMENT(player, player->pipeline->mainbin, MMPLAYER_M_SUBPARSE);
8159 __mmplayer_change_external_subtitle_language(mmplayer_t *player, const char *filepath)
8161 GstStateChangeReturn ret = GST_STATE_CHANGE_FAILURE;
8162 GstState current_state = GST_STATE_VOID_PENDING;
8164 MMHandleType attrs = 0;
8165 mmplayer_gst_element_t *mainbin = NULL;
8166 mmplayer_gst_element_t *textbin = NULL;
8168 gchar *subtitle_uri = NULL;
8169 int result = MM_ERROR_NONE;
8170 const gchar *charset = NULL;
8174 /* check player handle */
8175 MMPLAYER_RETURN_VAL_IF_FAIL(player &&
8177 player->pipeline->mainbin &&
8178 player->pipeline->textbin, MM_ERROR_PLAYER_NOT_INITIALIZED);
8179 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8181 mainbin = player->pipeline->mainbin;
8182 textbin = player->pipeline->textbin;
8184 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8185 if (current_state < GST_STATE_READY) {
8186 result = MM_ERROR_PLAYER_INVALID_STATE;
8187 LOGE("Pipeline is not in proper state");
8191 attrs = MMPLAYER_GET_ATTRS(player);
8193 LOGE("cannot get content attribute");
8194 result = MM_ERROR_PLAYER_INTERNAL;
8198 mm_attrs_get_string_by_name(attrs, "subtitle_uri", &subtitle_uri);
8199 if (!subtitle_uri || strlen(subtitle_uri) < 1) {
8200 LOGE("subtitle uri is not proper filepath");
8201 result = MM_ERROR_PLAYER_INVALID_URI;
8205 if (!_mmplayer_get_storage_info(filepath, &player->storage_info[MMPLAYER_PATH_TEXT])) {
8206 LOGE("failed to get storage info of subtitle path");
8207 result = MM_ERROR_PLAYER_INVALID_URI;
8211 SECURE_LOGD("old subtitle file path is [%s]", subtitle_uri);
8212 SECURE_LOGD("new subtitle file path is [%s]", filepath);
8214 if (!strcmp(filepath, subtitle_uri)) {
8215 LOGD("subtitle path is not changed");
8218 if (mm_player_set_attribute((MMHandleType)player, NULL,
8219 "subtitle_uri", filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8220 LOGE("failed to set attribute");
8225 //gst_pad_set_blocked_async(src-srcpad, TRUE)
8226 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8227 player->subtitle_language_list = NULL;
8228 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8230 ret = gst_element_set_state(textbin[MMPLAYER_T_BIN].gst, GST_STATE_READY);
8231 if (ret != GST_STATE_CHANGE_SUCCESS) {
8232 LOGE("failed to change state of textbin to READY");
8233 result = MM_ERROR_PLAYER_INTERNAL;
8237 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBPARSE].gst, GST_STATE_READY);
8238 if (ret != GST_STATE_CHANGE_SUCCESS) {
8239 LOGE("failed to change state of subparse to READY");
8240 result = MM_ERROR_PLAYER_INTERNAL;
8244 ret = gst_element_set_state(mainbin[MMPLAYER_M_SUBSRC].gst, GST_STATE_READY);
8245 if (ret != GST_STATE_CHANGE_SUCCESS) {
8246 LOGE("failed to change state of filesrc to READY");
8247 result = MM_ERROR_PLAYER_INTERNAL;
8251 __mmplayer_initialize_storage_info(player, MMPLAYER_PATH_TEXT);
8253 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBSRC].gst), "location", filepath, NULL);
8255 charset = _mmplayer_get_charset(filepath);
8257 LOGD("detected charset is %s", charset);
8258 g_object_set(G_OBJECT(mainbin[MMPLAYER_M_SUBPARSE].gst), "subtitle-encoding", charset, NULL);
8261 result = _mmplayer_sync_subtitle_pipeline(player);
8268 /* API to switch between external subtitles */
8270 _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char *filepath)
8272 int result = MM_ERROR_NONE;
8273 mmplayer_t *player = (mmplayer_t *)hplayer;
8278 /* check player handle */
8279 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8281 /* filepath can be null in idle state */
8283 /* check file path */
8284 if ((path = strstr(filepath, "file://")))
8285 result = _mmplayer_exist_file_path(path + 7);
8287 result = _mmplayer_exist_file_path(filepath);
8289 if (result != MM_ERROR_NONE) {
8290 LOGE("invalid subtitle path 0x%X", result);
8291 return result; /* file not found or permission denied */
8295 if (!player->pipeline) {
8297 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri", filepath,
8298 (filepath)?(strlen(filepath)):(0), NULL) != MM_ERROR_NONE) {
8299 LOGE("failed to set attribute");
8300 return MM_ERROR_PLAYER_INTERNAL;
8303 /* cur state <> IDLE(READY, PAUSE, PLAYING..) */
8304 /* check filepath */
8305 MMPLAYER_RETURN_VAL_IF_FAIL(filepath, MM_ERROR_COMMON_INVALID_ARGUMENT);
8307 if (!__mmplayer_check_subtitle(player)) {
8308 if (mm_player_set_attribute(hplayer, NULL, "subtitle_uri",
8309 filepath, strlen(filepath), NULL) != MM_ERROR_NONE) {
8310 LOGE("failed to set attribute");
8311 return MM_ERROR_PLAYER_INTERNAL;
8314 if (__mmplayer_gst_create_text_pipeline(player) != MM_ERROR_NONE) {
8315 LOGE("fail to create text pipeline");
8316 return MM_ERROR_PLAYER_INTERNAL;
8319 result = _mmplayer_sync_subtitle_pipeline(player);
8321 result = __mmplayer_change_external_subtitle_language(player, filepath);
8324 MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
8325 player->is_external_subtitle_added_now = TRUE;
8327 MMPLAYER_SUBTITLE_INFO_LOCK(player);
8328 if (!player->subtitle_language_list) {
8329 gint64 timeout = g_get_monotonic_time() + G_TIME_SPAN_SECOND; /* wait 1 sec */
8330 if (!MMPLAYER_SUBTITLE_INFO_WAIT_UNTIL(player, timeout))
8331 LOGW("subtitle language list is not updated yet");
8333 MMPLAYER_SUBTITLE_INFO_UNLOCK(player);
8341 __mmplayer_switch_stream(mmplayer_t *player, mmplayer_track_type_e type, int index)
8343 guint active_idx = 0;
8344 GstStream *stream = NULL;
8345 GList *streams = NULL;
8346 GstEvent *ev = NULL;
8347 GstCaps *caps = NULL;
8349 LOGD("Switching Streams... type: %d, index: %d", type, index);
8351 player->track[type].active_track_index = index;
8353 for (int i = 0; i < MM_PLAYER_TRACK_TYPE_MAX; i++) {
8354 /* FIXME: need to consider the non display type or audio only in case of MM_PLAYER_TRACK_TYPE_VIDEO */
8355 if (player->track[i].total_track_num > 0) {
8356 active_idx = player->track[i].active_track_index;
8357 stream = g_ptr_array_index(player->track[i].streams, active_idx);
8358 streams = g_list_append (streams, (gchar *)gst_stream_get_stream_id(stream));
8359 LOGD("Selecting %d type stream : %s\n", i, gst_stream_get_stream_id(stream));
8361 if (i == MM_PLAYER_TRACK_TYPE_AUDIO) {
8362 caps = gst_stream_get_caps(stream);
8364 _mmplayer_set_audio_attrs(player, caps);
8365 gst_caps_unref(caps);
8371 ev = gst_event_new_select_streams(streams);
8372 gst_element_send_event(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, ev);
8373 g_list_free(streams);
8375 return MM_ERROR_NONE;
8379 __mmplayer_change_selector_pad(mmplayer_t *player, mmplayer_track_type_e type, int index)
8381 int result = MM_ERROR_NONE;
8382 gchar *change_pad_name = NULL;
8383 GstPad *sinkpad = NULL;
8384 mmplayer_gst_element_t *mainbin = NULL;
8385 main_element_id_e elem_idx = MMPLAYER_M_NUM;
8386 GstCaps *caps = NULL;
8387 gint total_track_num = 0;
8391 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->pipeline && player->pipeline->mainbin,
8392 MM_ERROR_PLAYER_NOT_INITIALIZED);
8394 LOGD("Change Track(%d) to %d", type, index);
8396 mainbin = player->pipeline->mainbin;
8398 if (type == MM_PLAYER_TRACK_TYPE_AUDIO) {
8399 elem_idx = MMPLAYER_M_A_INPUT_SELECTOR;
8400 } else if (type == MM_PLAYER_TRACK_TYPE_TEXT) {
8401 elem_idx = MMPLAYER_M_T_INPUT_SELECTOR;
8403 /* Changing Video Track is not supported. */
8404 LOGE("Track Type Error");
8408 if (mainbin[elem_idx].gst == NULL) {
8409 result = MM_ERROR_PLAYER_NO_OP;
8410 LOGD("Req track doesn't exist");
8414 total_track_num = player->track[type].total_track_num;
8415 if (total_track_num <= 0) {
8416 result = MM_ERROR_PLAYER_NO_OP;
8417 LOGD("Language list is not available");
8421 if ((index < 0) || (index >= total_track_num)) {
8422 result = MM_ERROR_INVALID_ARGUMENT;
8423 LOGD("Not a proper index : %d", index);
8427 /*To get the new pad from the selector*/
8428 change_pad_name = g_strdup_printf("sink_%u", index);
8429 if (change_pad_name == NULL) {
8430 result = MM_ERROR_PLAYER_INTERNAL;
8431 LOGD("Pad does not exists");
8435 LOGD("new active pad name: %s", change_pad_name);
8437 sinkpad = gst_element_get_static_pad(mainbin[elem_idx].gst, change_pad_name);
8438 if (sinkpad == NULL) {
8439 LOGD("sinkpad is NULL");
8440 result = MM_ERROR_PLAYER_INTERNAL;
8444 LOGD("Set Active Pad - %s:%s", GST_DEBUG_PAD_NAME(sinkpad));
8445 g_object_set(mainbin[elem_idx].gst, "active-pad", sinkpad, NULL);
8447 caps = gst_pad_get_current_caps(sinkpad);
8448 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
8451 gst_object_unref(sinkpad);
8453 if (type == MM_PLAYER_TRACK_TYPE_AUDIO)
8454 _mmplayer_set_audio_attrs(player, caps);
8457 gst_caps_unref(caps);
8460 MMPLAYER_FREEIF(change_pad_name);
8465 _mmplayer_change_track_language(MMHandleType hplayer, mmplayer_track_type_e type, int index)
8467 int result = MM_ERROR_NONE;
8468 mmplayer_t *player = NULL;
8469 mmplayer_gst_element_t *mainbin = NULL;
8471 gint current_active_index = 0;
8473 GstState current_state = GST_STATE_VOID_PENDING;
8478 player = (mmplayer_t *)hplayer;
8479 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8481 if (!player->pipeline) {
8482 LOGE("Track %d pre setting -> %d", type, index);
8484 player->track[type].active_track_index = index;
8488 mainbin = player->pipeline->mainbin;
8490 current_active_index = player->track[type].active_track_index;
8492 /*If index is same as running index no need to change the pad*/
8493 if (current_active_index == index)
8496 if (!gst_element_query_position(mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &time)) {
8497 result = MM_ERROR_PLAYER_INVALID_STATE;
8501 current_state = GST_STATE(mainbin[MMPLAYER_M_PIPE].gst);
8502 if (current_state < GST_STATE_PAUSED) {
8503 result = MM_ERROR_PLAYER_INVALID_STATE;
8504 LOGW("Pipeline not in proper state");
8508 if (MMPLAYER_USE_DECODEBIN(player))
8509 result = __mmplayer_change_selector_pad(player, type, index);
8511 result = __mmplayer_switch_stream(player, type, index);
8513 if (result != MM_ERROR_NONE) {
8514 LOGE("failed to change track");
8518 player->track[type].active_track_index = index;
8520 if (MMPLAYER_USE_DECODEBIN(player)) {
8521 GstEvent *event = NULL;
8522 if (current_state == GST_STATE_PLAYING) {
8523 event = gst_event_new_seek(player->playback_rate, GST_FORMAT_TIME,
8524 (GstSeekFlags)(GST_SEEK_FLAG_SEGMENT | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP),
8525 GST_SEEK_TYPE_SET, time, GST_SEEK_TYPE_NONE, -1);
8527 _mmplayer_gst_send_event_to_sink(player, event);
8529 result = MM_ERROR_PLAYER_INTERNAL;
8540 _mmplayer_get_subtitle_silent(MMHandleType hplayer, int *silent)
8542 mmplayer_t *player = (mmplayer_t *)hplayer;
8546 /* check player handle */
8547 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8549 *silent = player->set_mode.subtitle_off;
8551 LOGD("subtitle is %s.", silent ? "ON" : "OFF");
8555 return MM_ERROR_NONE;
8559 __mmplayer_add_dump_buffer_probe(mmplayer_t *player, GstElement *element)
8561 MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
8562 MMPLAYER_RETURN_VAL_IF_FAIL(element, FALSE);
8564 gchar *factory_name = GST_OBJECT_NAME(gst_element_get_factory(element));
8565 gchar dump_file_name[PLAYER_INI_MAX_STRLEN*2];
8569 for (idx = 0; player->ini.dump_element_keyword[idx][0] != '\0'; idx++) {
8570 if (g_strrstr(factory_name, player->ini.dump_element_keyword[idx])) {
8571 LOGD("dump [%s] sink pad", player->ini.dump_element_keyword[idx]);
8572 mmplayer_dump_t *dump_s;
8573 dump_s = g_try_malloc(sizeof(mmplayer_dump_t));
8574 if (dump_s == NULL) {
8575 LOGE("malloc fail");
8579 dump_s->dump_element_file = NULL;
8580 dump_s->dump_pad = NULL;
8581 dump_s->dump_pad = gst_element_get_static_pad(element, "sink");
8583 if (dump_s->dump_pad) {
8584 memset(dump_file_name, 0x00, PLAYER_INI_MAX_STRLEN * 2);
8585 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]);
8586 dump_s->dump_element_file = fopen(dump_file_name, "w+");
8587 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);
8588 /* add list for removed buffer probe and close FILE */
8589 player->dump_list = g_list_append(player->dump_list, dump_s);
8590 LOGD("%s sink pad added buffer probe for dump", factory_name);
8593 MMPLAYER_FREEIF(dump_s);
8594 LOGE("failed to get %s sink pad added", factory_name);
8601 static GstPadProbeReturn
8602 __mmplayer_dump_buffer_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
8604 FILE *dump_data = (FILE *)u_data;
8606 GstBuffer *buffer = gst_pad_probe_info_get_buffer(info);
8607 GstMapInfo probe_info = GST_MAP_INFO_INIT;
8609 MMPLAYER_RETURN_VAL_IF_FAIL(dump_data, GST_PAD_PROBE_PASS);
8611 gst_buffer_map(buffer, &probe_info, GST_MAP_READ);
8613 LOGD("buffer timestamp = %" GST_TIME_FORMAT, GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));
8615 fwrite(probe_info.data, 1, probe_info.size , dump_data);
8617 gst_buffer_unmap(buffer, &probe_info);
8619 return GST_PAD_PROBE_OK;
8623 __mmplayer_release_dump_list(GList *dump_list)
8625 GList *d_list = dump_list;
8630 for (; d_list; d_list = g_list_next(d_list)) {
8631 mmplayer_dump_t *dump_s = d_list->data;
8632 if (dump_s->dump_pad) {
8633 if (dump_s->probe_handle_id)
8634 gst_pad_remove_probe(dump_s->dump_pad, dump_s->probe_handle_id);
8635 gst_object_unref(GST_OBJECT(dump_s->dump_pad));
8637 if (dump_s->dump_element_file) {
8638 fclose(dump_s->dump_element_file);
8639 dump_s->dump_element_file = NULL;
8641 MMPLAYER_FREEIF(dump_s);
8643 g_list_free(dump_list);
8648 _mmplayer_has_closed_caption(MMHandleType hplayer, bool *exist)
8650 mmplayer_t *player = (mmplayer_t *)hplayer;
8654 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8655 MMPLAYER_RETURN_VAL_IF_FAIL(exist, MM_ERROR_INVALID_ARGUMENT);
8657 *exist = (bool)player->has_closed_caption;
8661 return MM_ERROR_NONE;
8665 _mm_player_video_stream_internal_buffer_unref(void *buffer)
8670 LOGD("unref internal gst buffer %p", buffer);
8672 gst_buffer_unref((GstBuffer *)buffer);
8679 _mmplayer_get_timeout(MMHandleType hplayer, int *timeout)
8681 mmplayer_t *player = (mmplayer_t *)hplayer;
8685 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8686 MMPLAYER_RETURN_VAL_IF_FAIL(timeout, MM_ERROR_COMMON_INVALID_ARGUMENT);
8688 if (MMPLAYER_IS_STREAMING(player))
8689 *timeout = (int)player->ini.live_state_change_timeout;
8691 *timeout = (int)player->ini.localplayback_state_change_timeout;
8693 LOGD("timeout = %d", *timeout);
8696 return MM_ERROR_NONE;
8700 __mmplayer_initialize_storage_info(mmplayer_t *player, mmplayer_path_type_e path_type)
8704 MMPLAYER_RETURN_IF_FAIL(player);
8706 for (i = 0; i < MMPLAYER_PATH_MAX; i++) {
8708 if (path_type == MMPLAYER_PATH_MAX || path_type == i) {
8709 player->storage_info[i].type = STORAGE_TYPE_INTERNAL;
8710 player->storage_info[i].state = STORAGE_STATE_UNMOUNTABLE;
8711 player->storage_info[i].id = -1;
8712 memset(player->storage_info[i].path, 0x00, MM_MAX_URL_LEN);
8714 if (path_type != MMPLAYER_PATH_MAX)
8723 _mmplayer_manage_external_storage_state(MMHandleType hplayer, int id, int state)
8725 int ret = MM_ERROR_NONE;
8726 mmplayer_t *player = (mmplayer_t *)hplayer;
8727 MMMessageParamType msg_param = {0, };
8730 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8732 LOGW("state changed storage %d:%d", id, state);
8734 if (state != STORAGE_STATE_UNMOUNTABLE && state != STORAGE_STATE_REMOVED)
8735 return MM_ERROR_NONE;
8737 /* FIXME: text path should be handled separately. */
8738 if (((player->storage_info[MMPLAYER_PATH_VOD].type == STORAGE_TYPE_EXTERNAL)
8739 && (player->storage_info[MMPLAYER_PATH_VOD].id == id)) ||
8740 ((player->storage_info[MMPLAYER_PATH_TEXT].type == STORAGE_TYPE_EXTERNAL)
8741 && (player->storage_info[MMPLAYER_PATH_TEXT].id == id))) {
8742 LOGW("external storage is removed");
8744 if (player->msg_posted == FALSE) {
8745 memset(&msg_param, 0, sizeof(MMMessageParamType));
8746 msg_param.code = MM_ERROR_PLAYER_INVALID_URI;
8747 MMPLAYER_POST_MSG(player, MM_MESSAGE_ERROR, &msg_param);
8748 player->msg_posted = TRUE;
8751 /* unrealize the player */
8752 ret = _mmplayer_unrealize(hplayer);
8753 if (ret != MM_ERROR_NONE)
8754 LOGE("failed to unrealize");
8762 _mmplayer_get_adaptive_variant_info(MMHandleType hplayer, int *num, char **var_info)
8764 int ret = MM_ERROR_NONE;
8765 mmplayer_t *player = (mmplayer_t *)hplayer;
8766 int idx = 0, total = 0;
8767 gchar *result = NULL, *tmp = NULL;
8770 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8771 MMPLAYER_RETURN_VAL_IF_FAIL(num && var_info, MM_ERROR_COMMON_INVALID_ARGUMENT);
8773 total = *num = g_list_length(player->adaptive_info.var_list);
8775 LOGW("There is no stream variant info.");
8779 result = g_strdup("");
8780 for (idx = 0 ; idx < total ; idx++) {
8781 stream_variant_t *v_data = NULL;
8782 v_data = g_list_nth_data(player->adaptive_info.var_list, idx);
8785 gchar data[64] = {0};
8786 snprintf(data, sizeof(data), "%d,%d,%d,", v_data->bandwidth, v_data->width, v_data->height);
8788 tmp = g_strconcat(result, data, NULL);
8792 LOGW("There is no variant data in %d", idx);
8797 *var_info = (char *)result;
8799 LOGD("variant info %d:%s", *num, *var_info);
8805 _mmplayer_set_max_adaptive_variant_limit(MMHandleType hplayer, int bandwidth, int width, int height)
8807 int ret = MM_ERROR_NONE;
8808 mmplayer_t *player = (mmplayer_t *)hplayer;
8811 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8813 LOGD("set limit to [b]%d, [w]%d, [h]%d", bandwidth, width, height);
8815 player->adaptive_info.limit.bandwidth = (bandwidth >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (bandwidth) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8816 player->adaptive_info.limit.width = (width >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (width) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8817 player->adaptive_info.limit.height = (height >= ADAPTIVE_VARIANT_DEFAULT_VALUE) ? (height) : (ADAPTIVE_VARIANT_DEFAULT_VALUE);
8819 if (player->pipeline && player->pipeline->mainbin && player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst) {
8820 LOGD("update max limit of %s", GST_ELEMENT_NAME(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst));
8821 g_object_set(player->pipeline->mainbin[MMPLAYER_M_ADAPTIVE_DEMUX].gst,
8822 "max-bandwidth", bandwidth, "max-video-width", width, "max-video-height", height, NULL);
8824 /* FIXME: seek to current position for applying new variant limitation */
8833 _mmplayer_get_max_adaptive_variant_limit(MMHandleType hplayer, int *bandwidth, int *width, int *height)
8835 int ret = MM_ERROR_NONE;
8836 mmplayer_t *player = (mmplayer_t *)hplayer;
8839 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8840 MMPLAYER_RETURN_VAL_IF_FAIL(bandwidth && width && height, MM_ERROR_COMMON_INVALID_ARGUMENT);
8842 *bandwidth = player->adaptive_info.limit.bandwidth;
8843 *width = player->adaptive_info.limit.width;
8844 *height = player->adaptive_info.limit.height;
8846 LOGD("get limit to [b]%d, [w]%d, [h]%d", *bandwidth, *width, *height);
8853 _mmplayer_get_streaming_buffering_time(MMHandleType hplayer, int *prebuffer_ms, int *rebuffer_ms)
8855 int ret = MM_ERROR_NONE;
8856 mmplayer_t *player = (mmplayer_t *)hplayer;
8859 MMPLAYER_RETURN_VAL_IF_FAIL(player && player->streamer, MM_ERROR_PLAYER_NOT_INITIALIZED);
8860 MMPLAYER_RETURN_VAL_IF_FAIL(prebuffer_ms && rebuffer_ms, MM_ERROR_COMMON_INVALID_ARGUMENT);
8861 MMPLAYER_RETURN_VAL_IF_FAIL(MMPLAYER_IS_STREAMING(player), MM_ERROR_PLAYER_NO_OP);
8863 *prebuffer_ms = player->streamer->buffering_req.prebuffer_time;
8865 if (player->streamer->buffering_req.rebuffer_time > MIN_BUFFERING_TIME)
8866 *rebuffer_ms = player->streamer->buffering_req.rebuffer_time;
8867 else /* live case */
8868 *rebuffer_ms = DEFAULT_LIVE_REBUFFER_TIME;
8870 LOGD("buffering time %d ms / %d ms", *prebuffer_ms, *rebuffer_ms);
8877 _mmplayer_set_codec_type(MMHandleType hplayer, mmplayer_stream_type_e stream_type, mmplayer_codec_type_e codec_type)
8879 #define IDX_FIRST_SW_CODEC 0
8880 mmplayer_t *player = (mmplayer_t *)hplayer;
8881 int default_codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
8882 const char *attr_name = NULL;
8883 const char *default_type = NULL;
8884 const char *element_hw = NULL;
8885 const char *element_sw = NULL;
8888 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8890 LOGD("stream type: %d, codec_type: %d", stream_type, codec_type);
8892 /* FIXME: player need to know whether the decoder exist or not about required codec type since 6.0*/
8893 switch (stream_type) {
8894 case MM_PLAYER_STREAM_TYPE_AUDIO:
8895 attr_name = MM_PLAYER_AUDIO_CODEC_TYPE;
8896 default_type = player->ini.audiocodec_default_type;
8897 element_hw = player->ini.audiocodec_element_hw;
8898 element_sw = player->ini.audiocodec_element_sw[IDX_FIRST_SW_CODEC];
8900 case MM_PLAYER_STREAM_TYPE_VIDEO:
8901 attr_name = MM_PLAYER_VIDEO_CODEC_TYPE;
8902 default_type = player->ini.videocodec_default_type;
8903 element_hw = player->ini.videocodec_element_hw;
8904 element_sw = player->ini.videocodec_element_sw[IDX_FIRST_SW_CODEC];
8907 LOGE("Invalid stream type %s", MMPLAYER_STREAM_TYPE_GET_NAME(stream_type));
8908 return MM_ERROR_COMMON_INVALID_ARGUMENT;
8912 LOGD("default setting: [%s][%s][h:%s][s:%s]", attr_name, default_type, element_hw, element_sw);
8914 if (!strcmp(default_type, "sw"))
8915 default_codec_type = MM_PLAYER_CODEC_TYPE_SW;
8917 default_codec_type = MM_PLAYER_CODEC_TYPE_HW;
8919 if (codec_type == MM_PLAYER_CODEC_TYPE_DEFAULT)
8920 codec_type = default_codec_type;
8922 /* to support codec selection, codec info have to be added in ini file.
8923 in case of hw codec is selected, filter elements should be applied
8924 depending on the hw capabilities. */
8925 if (codec_type != default_codec_type) {
8926 if (((codec_type == MM_PLAYER_CODEC_TYPE_HW) && (!strcmp(element_hw, ""))) ||
8927 ((codec_type == MM_PLAYER_CODEC_TYPE_SW) && (!strcmp(element_sw, "")))) {
8928 LOGE("There is no codec for type %d", codec_type);
8929 return MM_ERROR_PLAYER_NO_OP;
8932 LOGD("sorting is required");
8933 if (stream_type == MM_PLAYER_STREAM_TYPE_AUDIO)
8934 player->need_audio_dec_sorting = TRUE;
8936 player->need_video_dec_sorting = TRUE;
8939 LOGD("update %s codec_type to %d", attr_name, codec_type);
8940 mm_player_set_attribute(hplayer, NULL, attr_name, codec_type, NULL);
8943 return MM_ERROR_NONE;
8947 _mmplayer_set_replaygain_enabled(MMHandleType hplayer, bool enabled)
8949 mmplayer_t *player = (mmplayer_t *)hplayer;
8950 GstElement *rg_vol_element = NULL;
8954 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8956 player->sound.rg_enable = enabled;
8958 /* just hold rgvolume enable value if pipeline is not ready */
8959 if (!player->pipeline || !player->pipeline->audiobin) {
8960 LOGD("pipeline is not ready. holding rgvolume enable value");
8961 return MM_ERROR_NONE;
8964 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
8966 if (!rg_vol_element) {
8967 LOGD("rgvolume element is not created");
8968 return MM_ERROR_PLAYER_INTERNAL;
8972 g_object_set(rg_vol_element, "enable-rgvolume", TRUE, NULL);
8974 g_object_set(rg_vol_element, "enable-rgvolume", FALSE, NULL);
8978 return MM_ERROR_NONE;
8982 _mmplayer_is_replaygain_enabled(MMHandleType hplayer, bool *enabled)
8984 mmplayer_t *player = (mmplayer_t *)hplayer;
8985 GstElement *rg_vol_element = NULL;
8986 gboolean enable = FALSE;
8990 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
8991 MMPLAYER_RETURN_VAL_IF_FAIL(enabled, MM_ERROR_INVALID_ARGUMENT);
8993 /* just hold enable_rg value if pipeline is not ready */
8994 if (!player->pipeline || !player->pipeline->audiobin) {
8995 LOGD("pipeline is not ready. holding rgvolume value (%d)", player->sound.rg_enable);
8996 *enabled = player->sound.rg_enable;
8997 return MM_ERROR_NONE;
9000 rg_vol_element = player->pipeline->audiobin[MMPLAYER_A_RGVOL].gst;
9002 if (!rg_vol_element) {
9003 LOGD("rgvolume element is not created");
9004 return MM_ERROR_PLAYER_INTERNAL;
9007 g_object_get(rg_vol_element, "enable-rgvolume", &enable, NULL);
9008 *enabled = (bool)enable;
9012 return MM_ERROR_NONE;
9016 _mmplayer_set_video_roi_area(MMHandleType hplayer, double scale_x, double scale_y, double scale_width, double scale_height)
9018 mmplayer_t *player = (mmplayer_t *)hplayer;
9019 MMHandleType attrs = 0;
9021 int ret = MM_ERROR_NONE;
9025 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9027 attrs = MMPLAYER_GET_ATTRS(player);
9028 MMPLAYER_RETURN_VAL_IF_FAIL(attrs, MM_ERROR_PLAYER_INTERNAL);
9030 mm_attrs_get_int_by_name(attrs, "display_overlay", &handle);
9032 LOGE("Display handle is NULL, after setting window handle, set video roi area");
9033 return MM_ERROR_PLAYER_INTERNAL;
9036 player->video_roi.scale_x = scale_x;
9037 player->video_roi.scale_y = scale_y;
9038 player->video_roi.scale_width = scale_width;
9039 player->video_roi.scale_height = scale_height;
9041 /* check video sinkbin is created */
9042 if (!_mmplayer_is_videosink_ready(player, MM_DISPLAY_SURFACE_NUM))
9043 return MM_ERROR_NONE;
9045 if (!gst_video_overlay_set_video_roi_area(
9046 GST_VIDEO_OVERLAY(player->pipeline->videobin[MMPLAYER_V_SINK].gst),
9047 scale_x, scale_y, scale_width, scale_height))
9048 ret = MM_ERROR_PLAYER_INTERNAL;
9050 LOGD("set video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9051 scale_x, scale_y, scale_width, scale_height);
9059 _mmplayer_get_video_roi_area(MMHandleType hplayer, double *scale_x, double *scale_y, double *scale_width, double *scale_height)
9061 mmplayer_t *player = (mmplayer_t *)hplayer;
9062 int ret = MM_ERROR_NONE;
9066 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9067 MMPLAYER_RETURN_VAL_IF_FAIL(scale_x && scale_y && scale_width && scale_height, MM_ERROR_INVALID_ARGUMENT);
9069 *scale_x = player->video_roi.scale_x;
9070 *scale_y = player->video_roi.scale_y;
9071 *scale_width = player->video_roi.scale_width;
9072 *scale_height = player->video_roi.scale_height;
9074 LOGD("get video param : video roi area scale value: x(%f) y(%f) width(%f) height(%f)",
9075 *scale_x, *scale_y, *scale_width, *scale_height);
9081 _mmplayer_set_client_pid(MMHandleType hplayer, int pid)
9083 mmplayer_t *player = (mmplayer_t *)hplayer;
9087 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9089 player->client_pid = pid;
9091 LOGD("client pid[%d] %p", pid, player);
9095 return MM_ERROR_NONE;
9099 _mmplayer_is_audio_control_available(MMHandleType hplayer, mmplayer_audio_control_opt_e opt, bool *available)
9101 mmplayer_t *player = (mmplayer_t *)hplayer;
9102 mmplayer_codec_type_e codec_type = MM_PLAYER_CODEC_TYPE_DEFAULT;
9103 enum audio_element_id elem_id = MMPLAYER_A_NUM;
9107 MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
9108 MMPLAYER_RETURN_VAL_IF_FAIL(available, MM_ERROR_INVALID_ARGUMENT);
9111 mm_attrs_get_int_by_name(player->attrs, MM_PLAYER_AUDIO_CODEC_TYPE, (int *)&codec_type);
9113 LOGD("current state %d, codec_type %d", MMPLAYER_CURRENT_STATE(player), codec_type);
9115 if (codec_type == MM_PLAYER_CODEC_TYPE_SW)
9116 return MM_ERROR_NONE;
9118 /* in case of audio codec default type is HW */
9120 case MM_PLAYER_AUDIO_CONTROL_OPT_EFFECT:
9121 if (player->ini.support_audio_effect)
9122 return MM_ERROR_NONE;
9123 elem_id = MMPLAYER_A_FILTER;
9125 case MM_PLAYER_AUDIO_CONTROL_OPT_REPLAYGAIN:
9126 if (player->ini.support_replaygain_control)
9127 return MM_ERROR_NONE;
9128 elem_id = MMPLAYER_A_RGVOL;
9130 case MM_PLAYER_AUDIO_CONTROL_OPT_PITCH:
9131 if (player->ini.support_pitch_control)
9132 return MM_ERROR_NONE;
9133 elem_id = MMPLAYER_A_PITCH;
9135 case MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING:
9136 if (player->ini.support_audio_effect)
9137 return MM_ERROR_NONE;
9139 /* default case handling is not required */
9142 if (MMPLAYER_CURRENT_STATE(player) < MM_PLAYER_STATE_READY) {
9143 LOGW("audio control option [%d] is not available", opt);
9146 /* setting pcm exporting option is allowed before READY state */
9147 if (opt == MM_PLAYER_AUDIO_CONTROL_OPT_PCM_EXPORTING)
9148 return MM_ERROR_PLAYER_INVALID_STATE;
9150 /* check whether the audio filter exist or not after READY state,
9151 because the sw codec could be added during auto-plugging in some cases */
9152 if (!player->pipeline ||
9153 !player->pipeline->audiobin ||
9154 !player->pipeline->audiobin[elem_id].gst) {
9155 LOGW("there is no audio elem [%d]", elem_id);
9160 LOGD("audio control opt %d, available %d", opt, *available);
9164 return MM_ERROR_NONE;
9168 __mmplayer_update_duration_value(mmplayer_t *player)
9170 gboolean ret = FALSE;
9171 gint64 dur_nsec = 0;
9172 LOGD("try to update duration");
9174 if (gst_element_query_duration(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst, GST_FORMAT_TIME, &dur_nsec) && (dur_nsec > 0)) {
9175 player->duration = dur_nsec;
9176 LOGW("duration : %"G_GINT64_FORMAT" msec", GST_TIME_AS_MSECONDS(dur_nsec));
9180 if (player->duration < 0) {
9181 LOGW("duration is Non-Initialized !!!");
9182 player->duration = 0;
9185 /* update streaming service type */
9186 player->streaming_type = _mmplayer_get_stream_service_type(player);
9188 /* check duration is OK */
9189 if (dur_nsec == 0 && !MMPLAYER_IS_LIVE_STREAMING(player))
9190 /* FIXIT : find another way to get duration here. */
9191 LOGW("finally it's failed to get duration from pipeline. progressbar will not work correctely!");
9197 __mmplayer_update_audio_attrs(mmplayer_t *player, MMHandleType attrs)
9199 /* update audio params
9200 NOTE : We need original audio params and it can be only obtained from src pad of audio
9201 decoder. Below code only valid when we are not using 'resampler' just before
9202 'audioconverter'. */
9203 GstCaps *caps_a = NULL;
9205 gint samplerate = 0, channels = 0;
9206 GstStructure *p = NULL;
9207 GstElement *aconv = NULL;
9209 LOGD("try to update audio attrs");
9211 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->audiobin, FALSE);
9213 if (player->pipeline->audiobin[MMPLAYER_A_CONV].gst) {
9214 aconv = player->pipeline->audiobin[MMPLAYER_A_CONV].gst;
9215 } else if (player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst) {
9216 aconv = player->pipeline->audiobin[MMPLAYER_A_EXTRACT_CONV].gst;
9218 LOGE("there is no audio converter");
9222 pad = gst_element_get_static_pad(aconv, "sink");
9225 LOGW("failed to get pad from audio converter");
9229 caps_a = gst_pad_get_current_caps(pad);
9231 LOGW("not ready to get audio caps");
9232 gst_object_unref(pad);
9236 p = gst_caps_get_structure(caps_a, 0);
9238 mm_attrs_get_int_by_name(attrs, "content_audio_samplerate", &samplerate);
9240 gst_structure_get_int(p, "rate", &samplerate);
9241 gst_structure_get_int(p, "channels", &channels);
9243 mm_player_set_attribute((MMHandleType)player, NULL,
9244 "content_audio_samplerate", samplerate,
9245 "content_audio_channels", channels, NULL);
9247 SECURE_LOGD("samplerate : %d channels : %d", samplerate, channels);
9249 gst_caps_unref(caps_a);
9250 gst_object_unref(pad);
9256 __mmplayer_update_video_attrs(mmplayer_t *player, MMHandleType attrs)
9258 LOGD("try to update video attrs");
9260 GstCaps *caps_v = NULL;
9264 GstStructure *p = NULL;
9266 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin, FALSE);
9267 MMPLAYER_RETURN_VAL_IF_FAIL(player->pipeline->videobin[MMPLAYER_V_SINK].gst, FALSE);
9269 pad = gst_element_get_static_pad(player->pipeline->videobin[MMPLAYER_V_SINK].gst, "sink");
9271 LOGD("no videosink sink pad");
9275 caps_v = gst_pad_get_current_caps(pad);
9276 /* Use v_stream_caps, if fail to get video_sink sink pad*/
9277 if (!caps_v && player->v_stream_caps) {
9278 caps_v = player->v_stream_caps;
9279 gst_caps_ref(caps_v);
9283 LOGD("no negotiated caps from videosink");
9284 gst_object_unref(pad);
9288 p = gst_caps_get_structure(caps_v, 0);
9289 gst_structure_get_int(p, "width", &width);
9290 gst_structure_get_int(p, "height", &height);
9292 mm_player_set_attribute((MMHandleType)player, NULL,
9293 MM_PLAYER_VIDEO_WIDTH, width, MM_PLAYER_VIDEO_HEIGHT, height, NULL);
9295 gst_structure_get_fraction(p, "framerate", &tmpNu, &tmpDe);
9297 SECURE_LOGD("width : %d height : %d", width, height);
9299 gst_caps_unref(caps_v);
9300 gst_object_unref(pad);
9303 mm_player_set_attribute((MMHandleType)player, NULL,
9304 MM_PLAYER_VIDEO_FPS, (tmpNu/tmpDe), NULL);
9305 SECURE_LOGD("fps : %d", tmpNu / tmpDe);
9312 __mmplayer_update_bitrate_attrs(mmplayer_t *player, MMHandleType attrs)
9314 gboolean ret = FALSE;
9315 guint64 data_size = 0;
9319 /* FIXIT : please make it clear the dependency with duration/codec/uritype */
9320 if (!player->duration)
9323 if (!MMPLAYER_IS_STREAMING(player) && (player->can_support_codec & FOUND_PLUGIN_VIDEO)) {
9324 mm_attrs_get_string_by_name(attrs, "profile_uri", &path);
9325 if (stat(path, &sb) == 0)
9326 data_size = (guint64)sb.st_size;
9328 } else if (MMPLAYER_IS_HTTP_STREAMING(player)) {
9329 data_size = player->http_content_size;
9332 LOGD("try to update bitrate : data_size = %"G_GUINT64_FORMAT, data_size);
9335 guint64 bitrate = 0;
9336 guint64 msec_dur = 0;
9338 msec_dur = GST_TIME_AS_MSECONDS(player->duration);
9340 bitrate = data_size * 8 * 1000 / msec_dur;
9341 SECURE_LOGD("file size : %"G_GUINT64_FORMAT
9342 ", video bitrate = %"G_GUINT64_FORMAT, data_size, bitrate);
9343 mm_player_set_attribute((MMHandleType)player, NULL,
9344 MM_PLAYER_VIDEO_BITRATE, (int)bitrate, NULL);
9347 LOGD("player duration is less than 0");
9351 if (MMPLAYER_IS_RTSP_STREAMING(player)) {
9352 if (player->total_bitrate) {
9353 mm_player_set_attribute((MMHandleType)player, NULL,
9354 MM_PLAYER_VIDEO_BITRATE, player->total_bitrate, NULL);
9363 __mmplayer_copy_uri_and_set_type(mmplayer_parse_profile_t *data, const char *uri, int uri_type)
9365 strncpy(data->uri, uri, MM_MAX_URL_LEN - 1);
9366 data->uri_type = uri_type;
9370 __mmplayer_set_mem_uri(mmplayer_parse_profile_t *data, char *path, void *param)
9372 int ret = MM_ERROR_PLAYER_INVALID_URI;
9374 char *buffer = NULL;
9375 char *seperator = strchr(path, ',');
9376 char ext[100] = {0,}, size[100] = {0,};
9379 if ((buffer = strstr(path, "ext="))) {
9380 buffer += strlen("ext=");
9382 if (strlen(buffer)) {
9383 strncpy(ext, buffer, 99);
9385 if ((seperator = strchr(ext, ','))
9386 || (seperator = strchr(ext, ' '))
9387 || (seperator = strchr(ext, '\0'))) {
9388 seperator[0] = '\0';
9393 if ((buffer = strstr(path, "size="))) {
9394 buffer += strlen("size=");
9396 if (strlen(buffer) > 0) {
9397 strncpy(size, buffer, 99);
9399 if ((seperator = strchr(size, ','))
9400 || (seperator = strchr(size, ' '))
9401 || (seperator = strchr(size, '\0'))) {
9402 seperator[0] = '\0';
9405 mem_size = atoi(size);
9410 LOGD("ext: %s, mem_size: %d, mmap(param): %p", ext, mem_size, param);
9412 if (mem_size && param) {
9413 if (data->input_mem.buf)
9414 free(data->input_mem.buf);
9415 data->input_mem.buf = malloc(mem_size);
9417 if (data->input_mem.buf) {
9418 memcpy(data->input_mem.buf, param, mem_size);
9419 data->input_mem.len = mem_size;
9420 ret = MM_ERROR_NONE;
9422 LOGE("failed to alloc mem %d", mem_size);
9423 ret = MM_ERROR_PLAYER_INTERNAL;
9426 data->input_mem.offset = 0;
9427 data->uri_type = MM_PLAYER_URI_TYPE_MEM;
9434 __mmplayer_set_file_uri(mmplayer_parse_profile_t *data, const char *uri)
9436 gchar *location = NULL;
9439 int ret = MM_ERROR_NONE;
9441 if ((path = strstr(uri, "file://"))) {
9442 location = g_filename_from_uri(uri, NULL, &err);
9443 if (!location || (err != NULL)) {
9444 LOGE("Invalid URI '%s' for filesrc: %s", path,
9445 (err != NULL) ? err->message : "unknown error");
9449 MMPLAYER_FREEIF(location);
9451 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9452 return MM_ERROR_PLAYER_INVALID_URI;
9454 LOGD("path from uri: %s", location);
9457 path = (location != NULL) ? (location) : ((char *)uri);
9460 ret = _mmplayer_exist_file_path(path);
9462 /* if no protocol prefix exist. check file existence and then give file:// as it's prefix */
9463 if (ret == MM_ERROR_NONE) {
9464 if (_mmplayer_is_sdp_file(path)) {
9465 LOGD("uri is actually a file but it's sdp file. giving it to rtspsrc");
9466 g_snprintf(data->uri, MM_MAX_URL_LEN, "rtsp-sdp://%s", path);
9467 data->uri_type = MM_PLAYER_URI_TYPE_URL_RTSP;
9469 g_snprintf(data->uri, MM_MAX_URL_LEN, "file://%s", path);
9470 data->uri_type = MM_PLAYER_URI_TYPE_FILE;
9472 } else if (ret == MM_ERROR_PLAYER_PERMISSION_DENIED) {
9473 data->uri_type = MM_PLAYER_URI_TYPE_NO_PERMISSION;
9475 LOGE("invalid uri, could not play..");
9476 data->uri_type = MM_PLAYER_URI_TYPE_NONE;
9479 MMPLAYER_FREEIF(location);
9484 static mmplayer_video_decoded_data_info_t *
9485 __mmplayer_create_stream_from_pad(GstPad *pad)
9487 GstCaps *caps = NULL;
9488 GstStructure *structure = NULL;
9489 unsigned int fourcc = 0;
9490 const gchar *string_format = NULL;
9491 mmplayer_video_decoded_data_info_t *stream = NULL;
9493 MMPixelFormatType format;
9496 caps = gst_pad_get_current_caps(pad);
9498 LOGE("Caps is NULL.");
9503 MMPLAYER_LOG_GST_CAPS_TYPE(caps);
9505 structure = gst_caps_get_structure(caps, 0);
9506 gst_structure_get_int(structure, "width", &width);
9507 gst_structure_get_int(structure, "height", &height);
9508 string_format = gst_structure_get_string(structure, "format");
9511 fourcc = _mmplayer_convert_fourcc_string_to_value(string_format);
9512 format = _mmplayer_get_pixtype(fourcc);
9513 gst_video_info_from_caps(&info, caps);
9514 gst_caps_unref(caps);
9517 if (width == 0 || height == 0 || format == MM_PIXEL_FORMAT_INVALID) {
9518 LOGE("Wrong condition!!");
9522 stream = (mmplayer_video_decoded_data_info_t *)g_try_malloc0(sizeof(mmplayer_video_decoded_data_info_t));
9524 LOGE("failed to alloc mem for video data");
9528 stream->width = width;
9529 stream->height = height;
9530 stream->format = format;
9531 stream->plane_num = GST_VIDEO_INFO_N_PLANES(&info);
9537 __mmplayer_zerocopy_set_stride_elevation_bo(mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9539 unsigned int pitch = 0;
9540 unsigned int size = 0;
9542 tbm_surface_h surface = gst_tizen_memory_get_surface(mem);
9545 for (index = 0; index < gst_tizen_memory_get_num_bos(mem); index++) {
9546 bo = gst_tizen_memory_get_bos(mem, index);
9548 stream->bo[index] = tbm_bo_ref(bo);
9550 LOGE("failed to get bo for index %d", index);
9553 for (index = 0; index < stream->plane_num; index++) {
9554 tbm_surface_internal_get_plane_data(surface, index, &size, NULL, &pitch);
9555 stream->stride[index] = pitch;
9557 stream->elevation[index] = size / pitch;
9559 stream->elevation[index] = stream->height;
9564 __mmplayer_swcodec_set_stride_elevation(mmplayer_video_decoded_data_info_t *stream)
9566 if (stream->format == MM_PIXEL_FORMAT_I420) {
9567 int ret = TBM_SURFACE_ERROR_NONE;
9568 tbm_surface_h surface;
9569 tbm_surface_info_s info;
9571 surface = tbm_surface_create(stream->width, stream->height, TBM_FORMAT_YUV420);
9573 ret = tbm_surface_get_info(surface, &info);
9574 if (ret != TBM_SURFACE_ERROR_NONE) {
9575 tbm_surface_destroy(surface);
9579 tbm_surface_destroy(surface);
9580 stream->stride[0] = info.planes[0].stride;
9581 stream->elevation[0] = info.planes[0].size / info.planes[0].stride;
9582 stream->stride[1] = info.planes[1].stride;
9583 stream->elevation[1] = info.planes[1].size / info.planes[1].stride;
9584 stream->stride[2] = info.planes[2].stride;
9585 stream->elevation[2] = info.planes[2].size / info.planes[2].stride;
9586 stream->bo_size = info.planes[0].size + info.planes[1].size + info.planes[2].size;
9587 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9588 stream->stride[0] = stream->width * 4;
9589 stream->elevation[0] = stream->height;
9590 stream->bo_size = stream->stride[0] * stream->height;
9592 LOGE("Not support format %d", stream->format);
9600 __mmplayer_swcodec_set_bo(mmplayer_t *player, mmplayer_video_decoded_data_info_t *stream, GstMemory *mem)
9602 tbm_bo_handle thandle;
9604 int src_stride[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9605 int src_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9606 int dest_offset[MM_PLAYER_IMGB_MPLANE_MAX] = { 0, };
9610 unsigned char *src = NULL;
9611 unsigned char *dest = NULL;
9612 GstMapInfo mapinfo = GST_MAP_INFO_INIT;
9614 is_mapped = gst_memory_map(mem, &mapinfo, GST_MAP_READWRITE);
9616 LOGE("fail to gst_memory_map");
9620 if (!mapinfo.data) {
9621 LOGE("data pointer is wrong");
9625 stream->bo[0] = __mmplayer_video_stream_get_bo(player, stream->bo_size);
9626 if (!stream->bo[0]) {
9627 LOGE("Fail to tbm_bo_alloc!!");
9631 thandle = tbm_bo_map(stream->bo[0], TBM_DEVICE_CPU, TBM_OPTION_WRITE);
9633 LOGE("thandle pointer is wrong");
9637 if (stream->format == MM_PIXEL_FORMAT_I420) {
9638 src_stride[0] = GST_ROUND_UP_4(stream->width);
9639 src_stride[1] = src_stride[2] = GST_ROUND_UP_4(stream->width >> 1);
9640 src_offset[1] = src_stride[0] * GST_ROUND_UP_2(stream->height);
9641 src_offset[2] = src_offset[1] + (src_stride[1] * (GST_ROUND_UP_2(stream->height) >> 1));
9644 dest_offset[1] = stream->stride[0] * stream->elevation[0];
9645 dest_offset[2] = dest_offset[1] + stream->stride[1] * stream->elevation[1];
9647 for (i = 0; i < 3; i++) {
9648 src = mapinfo.data + src_offset[i];
9649 dest = thandle.ptr + dest_offset[i];
9654 for (j = 0; j < stream->height >> k; j++) {
9655 memcpy(dest, src, stream->width>>k);
9656 src += src_stride[i];
9657 dest += stream->stride[i];
9660 } else if (stream->format == MM_PIXEL_FORMAT_RGBA) {
9661 memcpy(thandle.ptr, mapinfo.data, stream->bo_size);
9663 LOGE("Not support format %d", stream->format);
9667 tbm_bo_unmap(stream->bo[0]);
9668 gst_memory_unmap(mem, &mapinfo);
9674 tbm_bo_unmap(stream->bo[0]);
9677 gst_memory_unmap(mem, &mapinfo);
9683 __mmplayer_set_pause_state(mmplayer_t *player)
9685 if (player->sent_bos)
9688 /* rtsp case, get content attrs by GstMessage */
9689 if (MMPLAYER_IS_RTSP_STREAMING(player))
9692 /* it's first time to update all content attrs. */
9693 _mmplayer_update_content_attrs(player, ATTR_ALL);
9697 __mmplayer_set_playing_state(mmplayer_t *player)
9699 gchar *audio_codec = NULL;
9701 if (player->resumed_by_rewind && player->playback_rate < 0.0) {
9702 /* initialize because auto resume is done well. */
9703 player->resumed_by_rewind = FALSE;
9704 player->playback_rate = 1.0;
9707 if (player->sent_bos)
9710 /* try to get content metadata */
9712 /* NOTE : giving ATTR_MISSING_ONLY may have dependency with
9713 * c-api since c-api doesn't use _start() anymore. It may not work properly with
9714 * legacy mmfw-player api
9716 _mmplayer_update_content_attrs(player, ATTR_MISSING_ONLY);
9718 if ((player->cmd == MMPLAYER_COMMAND_START)
9719 || (player->cmd == MMPLAYER_COMMAND_RESUME)) {
9720 __mmplayer_handle_missed_plugin(player);
9723 /* check audio codec field is set or not
9724 * we can get it from typefinder or codec's caps.
9726 mm_attrs_get_string_by_name(player->attrs, "content_audio_codec", &audio_codec);
9728 /* The codec format can't be sent for audio only case like amr, mid etc.
9729 * Because, parser don't make related TAG.
9730 * So, if it's not set yet, fill it with found data.
9733 if (g_strrstr(player->type, "audio/midi"))
9734 audio_codec = "MIDI";
9735 else if (g_strrstr(player->type, "audio/x-amr"))
9736 audio_codec = "AMR";
9737 else if (g_strrstr(player->type, "audio/mpeg")
9738 && !g_strrstr(player->type, "mpegversion=(int)1"))
9739 audio_codec = "AAC";
9741 audio_codec = "unknown";
9743 if (mm_player_set_attribute((MMHandleType)player, NULL,
9744 "content_audio_codec", audio_codec, strlen(audio_codec), NULL) != MM_ERROR_NONE)
9745 LOGE("failed to set attribute");
9747 LOGD("set audio codec type with caps");